Clover coverage report - Code Coverage for tapestry release 4.0-beta-12
Coverage timestamp: Sun Oct 30 2005 16:22:01 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  393 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
 55    {
 56  393 Iterator i = spec.getPropertySpecificationNames().iterator();
 57   
 58  393 while (i.hasNext())
 59    {
 60  113 String name = (String) i.next();
 61  113 IPropertySpecification ps = spec.getPropertySpecification(name);
 62   
 63  113 try
 64    {
 65  113 performEnhancement(op, ps);
 66    }
 67    catch (RuntimeException ex)
 68    {
 69  1 _errorLog.error(
 70    EnhanceMessages.errorAddingProperty(name, op.getBaseClass(), ex),
 71    ps.getLocation(),
 72    ex);
 73    }
 74    }
 75    }
 76   
 77  113 private void performEnhancement(EnhancementOperation op, IPropertySpecification ps)
 78    {
 79  113 Defense.notNull(ps, "ps");
 80   
 81  113 String propertyName = ps.getName();
 82  113 String specifiedType = ps.getType();
 83  113 boolean persistent = ps.isPersistent();
 84  113 String initialValue = ps.getInitialValue();
 85  113 Location location = ps.getLocation();
 86   
 87  113 addProperty(op, propertyName, specifiedType, persistent, initialValue, location);
 88    }
 89   
 90  113 public void addProperty(EnhancementOperation op, String propertyName, String specifiedType,
 91    boolean persistent, String initialValue, Location location)
 92    {
 93  113 Class propertyType = EnhanceUtils.extractPropertyType(op, propertyName, specifiedType);
 94   
 95  112 op.claimProperty(propertyName);
 96   
 97  112 String field = "_$" + propertyName;
 98   
 99  112 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  112 EnhanceUtils.createSimpleAccessor(op, field, propertyName, propertyType, location);
 106   
 107  112 addMutator(op, propertyName, propertyType, field, persistent, location);
 108   
 109  112 if (initialValue == null)
 110  106 addReinitializer(op, propertyType, field);
 111    else
 112  6 addInitialValue(op, propertyName, propertyType, field, initialValue, location);
 113    }
 114   
 115  106 private void addReinitializer(EnhancementOperation op, Class propertyType, String fieldName)
 116    {
 117  106 String defaultFieldName = fieldName + "$default";
 118   
 119  106 op.addField(defaultFieldName, propertyType);
 120   
 121    // On finishLoad(), store the current value into the default field.
 122   
 123  106 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  106 op.extendMethodImplementation(
 131    PageDetachListener.class,
 132    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
 133    fieldName + " = " + defaultFieldName + ";");
 134    }
 135   
 136  6 private void addInitialValue(EnhancementOperation op, String propertyName, Class propertyType,
 137    String fieldName, String initialValue, Location location)
 138    {
 139  6 String description = EnhanceMessages.initialValueForProperty(propertyName);
 140   
 141  6 InitialValueBindingCreator creator = new InitialValueBindingCreator(_bindingSource,
 142    description, initialValue, location);
 143   
 144  6 String creatorField = op.addInjectedField(
 145    fieldName + "$initialValueBindingCreator",
 146    InitialValueBindingCreator.class,
 147    creator);
 148   
 149  6 String bindingField = fieldName + "$initialValueBinding";
 150  6 op.addField(bindingField, IBinding.class);
 151   
 152  6 BodyBuilder builder = new BodyBuilder();
 153   
 154  6 builder.addln("{0} = {1}.createBinding(this);", bindingField, creatorField);
 155   
 156  6 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, builder
 157    .toString());
 158   
 159  6 builder.clear();
 160   
 161  6 builder.addln("{0} = {1};", fieldName, EnhanceUtils.createUnwrapExpression(
 162    op,
 163    bindingField,
 164    propertyType));
 165   
 166  6 String code = builder.toString();
 167   
 168    // In finishLoad() and pageDetach(), de-reference the binding to get the value
 169    // for the property.
 170   
 171  6 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, code);
 172  6 op.extendMethodImplementation(
 173    PageDetachListener.class,
 174    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
 175    code);
 176   
 177    }
 178   
 179  112 private void addMutator(EnhancementOperation op, String propertyName, Class propertyType,
 180    String fieldName, boolean persistent, Location location)
 181    {
 182  112 String methodName = EnhanceUtils.createMutatorMethodName(propertyName);
 183   
 184  112 BodyBuilder body = new BodyBuilder();
 185   
 186  112 body.begin();
 187   
 188  112 if (persistent)
 189    {
 190  20 body.add("org.apache.tapestry.Tapestry#fireObservedChange(this, ");
 191  20 body.addQuoted(propertyName);
 192  20 body.addln(", ($w) $1);");
 193    }
 194   
 195  112 body.addln(fieldName + " = $1;");
 196   
 197  112 body.end();
 198   
 199  112 MethodSignature sig = new MethodSignature(void.class, methodName, new Class[]
 200    { propertyType }, null);
 201   
 202  112 op.addMethod(Modifier.PUBLIC, sig, body.toString(), location);
 203    }
 204   
 205  40 public void setErrorLog(ErrorLog errorLog)
 206    {
 207  40 _errorLog = errorLog;
 208    }
 209   
 210  40 public void setBindingSource(BindingSource bindingSource)
 211    {
 212  40 _bindingSource = bindingSource;
 213    }
 214    }