Clover coverage report - Code Coverage for tapestry release 4.0.1
Coverage timestamp: Fri Mar 31 2006 09:12:14 EST
file stats: LOC: 214   Methods: 8
NCLOC: 129   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SpecifiedPropertyWorker.java 100% 100% 100% 100%
coverage
 1    // Copyright 2004, 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.tapestry.enhance;
 16   
 17    import java.lang.reflect.Modifier;
 18    import java.util.Iterator;
 19   
 20    import org.apache.hivemind.ErrorLog;
 21    import org.apache.hivemind.Location;
 22    import org.apache.hivemind.service.BodyBuilder;
 23    import org.apache.hivemind.service.MethodSignature;
 24    import org.apache.hivemind.util.Defense;
 25    import org.apache.tapestry.IBinding;
 26    import org.apache.tapestry.IComponent;
 27    import org.apache.tapestry.binding.BindingSource;
 28    import org.apache.tapestry.event.PageDetachListener;
 29    import org.apache.tapestry.spec.IComponentSpecification;
 30    import org.apache.tapestry.spec.IPropertySpecification;
 31   
 32    /**
 33    * Responsible for adding properties to a class corresponding to specified properties in the
 34    * component's specification.
 35    *
 36    * @author Howard M. Lewis Ship
 37    * @since 4.0
 38    * @see org.apache.tapestry.annotations.PersistAnnotationWorker
 39    * @see org.apache.tapestry.annotations.InitialValueAnnotationWorker
 40    */
 41    public class SpecifiedPropertyWorker implements EnhancementWorker
 42    {
 43    private ErrorLog _errorLog;
 44   
 45    private BindingSource _bindingSource;
 46   
 47    /**
 48    * Iterates over the specified properties, creating an enhanced property for each (a field, an
 49    * accessor, a mutator). Persistent properties will invoke
 50    * {@link org.apache.tapestry.Tapestry#fireObservedChange(IComponent, String, Object)}in thier
 51    * mutator.
 52    */
 53   
 54  786 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
 55    {
 56  786 Iterator i = spec.getPropertySpecificationNames().iterator();
 57   
 58  786 while (i.hasNext())
 59    {
 60  226 String name = (String) i.next();
 61  226 IPropertySpecification ps = spec.getPropertySpecification(name);
 62   
 63  226 try
 64    {
 65  226 performEnhancement(op, ps);
 66    }
 67    catch (RuntimeException ex)
 68    {
 69  2 _errorLog.error(
 70    EnhanceMessages.errorAddingProperty(name, op.getBaseClass(), ex),
 71    ps.getLocation(),
 72    ex);
 73    }
 74    }
 75    }
 76   
 77  226 private void performEnhancement(EnhancementOperation op, IPropertySpecification ps)
 78    {
 79  226 Defense.notNull(ps, "ps");
 80   
 81  226 String propertyName = ps.getName();
 82  226 String specifiedType = ps.getType();
 83  226 boolean persistent = ps.isPersistent();
 84  226 String initialValue = ps.getInitialValue();
 85  226 Location location = ps.getLocation();
 86   
 87  226 addProperty(op, propertyName, specifiedType, persistent, initialValue, location);
 88    }
 89   
 90  226 public void addProperty(EnhancementOperation op, String propertyName, String specifiedType,
 91    boolean persistent, String initialValue, Location location)
 92    {
 93  226 Class propertyType = EnhanceUtils.extractPropertyType(op, propertyName, specifiedType);
 94   
 95  224 op.claimProperty(propertyName);
 96   
 97  224 String field = "_$" + propertyName;
 98   
 99  224 op.addField(field, propertyType);
 100   
 101    // Release 3.0 would squack a bit about overriding non-abstract methods
 102    // if they exist. 4.0 is less picky ... it blindly adds new methods, possibly
 103    // overwriting methods in the base component class.
 104   
 105  224 EnhanceUtils.createSimpleAccessor(op, field, propertyName, propertyType, location);
 106   
 107  224 addMutator(op, propertyName, propertyType, field, persistent, location);
 108   
 109  224 if (initialValue == null)
 110  212 addReinitializer(op, propertyType, field);
 111    else
 112  12 addInitialValue(op, propertyName, propertyType, field, initialValue, location);
 113    }
 114   
 115  212 private void addReinitializer(EnhancementOperation op, Class propertyType, String fieldName)
 116    {
 117  212 String defaultFieldName = fieldName + "$default";
 118   
 119  212 op.addField(defaultFieldName, propertyType);
 120   
 121    // On finishLoad(), store the current value into the default field.
 122   
 123  212 op.extendMethodImplementation(
 124    IComponent.class,
 125    EnhanceUtils.FINISH_LOAD_SIGNATURE,
 126    defaultFieldName + " = " + fieldName + ";");
 127   
 128    // On pageDetach(), restore the attribute to its default value.
 129   
 130  212 op.extendMethodImplementation(
 131    PageDetachListener.class,
 132    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
 133    fieldName + " = " + defaultFieldName + ";");
 134    }
 135   
 136  12 private void addInitialValue(EnhancementOperation op, String propertyName, Class propertyType,
 137    String fieldName, String initialValue, Location location)
 138    {
 139  12 String description = EnhanceMessages.initialValueForProperty(propertyName);
 140   
 141  12 InitialValueBindingCreator creator = new InitialValueBindingCreator(_bindingSource,
 142    description, initialValue, location);
 143   
 144  12 String creatorField = op.addInjectedField(
 145    fieldName + "$initialValueBindingCreator",
 146    InitialValueBindingCreator.class,
 147    creator);
 148   
 149  12 String bindingField = fieldName + "$initialValueBinding";
 150  12 op.addField(bindingField, IBinding.class);
 151   
 152  12 BodyBuilder builder = new BodyBuilder();
 153   
 154  12 builder.addln("{0} = {1}.createBinding(this);", bindingField, creatorField);
 155   
 156  12 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, builder
 157    .toString());
 158   
 159  12 builder.clear();
 160   
 161  12 builder.addln("{0} = {1};", fieldName, EnhanceUtils.createUnwrapExpression(
 162    op,
 163    bindingField,
 164    propertyType));
 165   
 166  12 String code = builder.toString();
 167   
 168    // In finishLoad() and pageDetach(), de-reference the binding to get the value
 169    // for the property.
 170   
 171  12 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, code);
 172  12 op.extendMethodImplementation(
 173    PageDetachListener.class,
 174    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
 175    code);
 176   
 177    }
 178   
 179  224 private void addMutator(EnhancementOperation op, String propertyName, Class propertyType,
 180    String fieldName, boolean persistent, Location location)
 181    {
 182  224 String methodName = EnhanceUtils.createMutatorMethodName(propertyName);
 183   
 184  224 BodyBuilder body = new BodyBuilder();
 185   
 186  224 body.begin();
 187   
 188  224 if (persistent)
 189    {
 190  40 body.add("org.apache.tapestry.Tapestry#fireObservedChange(this, ");
 191  40 body.addQuoted(propertyName);
 192  40 body.addln(", ($w) $1);");
 193    }
 194   
 195  224 body.addln(fieldName + " = $1;");
 196   
 197  224 body.end();
 198   
 199  224 MethodSignature sig = new MethodSignature(void.class, methodName, new Class[]
 200    { propertyType }, null);
 201   
 202  224 op.addMethod(Modifier.PUBLIC, sig, body.toString(), location);
 203    }
 204   
 205  80 public void setErrorLog(ErrorLog errorLog)
 206    {
 207  80 _errorLog = errorLog;
 208    }
 209   
 210  80 public void setBindingSource(BindingSource bindingSource)
 211    {
 212  80 _bindingSource = bindingSource;
 213    }
 214    }