Clover coverage report - Code Coverage for tapestry release 4.0-beta-6
Coverage timestamp: Wed Sep 7 2005 18:41:34 EDT
file stats: LOC: 212   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    */
 39    public class SpecifiedPropertyWorker implements EnhancementWorker
 40    {
 41    private ErrorLog _errorLog;
 42   
 43    private BindingSource _bindingSource;
 44   
 45    /**
 46    * Iterates over the specified properties, creating an enhanced property for each (a field, an
 47    * accessor, a mutator). Persistent properties will invoke
 48    * {@link org.apache.tapestry.Tapestry#fireObservedChange(IComponent, String, Object)}in thier
 49    * mutator.
 50    */
 51   
 52  422 public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
 53    {
 54  422 Iterator i = spec.getPropertySpecificationNames().iterator();
 55   
 56  422 while (i.hasNext())
 57    {
 58  122 String name = (String) i.next();
 59  122 IPropertySpecification ps = spec.getPropertySpecification(name);
 60   
 61  122 try
 62    {
 63  122 performEnhancement(op, ps);
 64    }
 65    catch (RuntimeException ex)
 66    {
 67  1 _errorLog.error(
 68    EnhanceMessages.errorAddingProperty(name, op.getBaseClass(), ex),
 69    ps.getLocation(),
 70    ex);
 71    }
 72    }
 73    }
 74   
 75  122 private void performEnhancement(EnhancementOperation op, IPropertySpecification ps)
 76    {
 77  122 Defense.notNull(ps, "ps");
 78   
 79  122 String propertyName = ps.getName();
 80  122 String specifiedType = ps.getType();
 81  122 boolean persistent = ps.isPersistent();
 82  122 String initialValue = ps.getInitialValue();
 83  122 Location location = ps.getLocation();
 84   
 85  122 addProperty(op, propertyName, specifiedType, persistent, initialValue, location);
 86    }
 87   
 88  122 public void addProperty(EnhancementOperation op, String propertyName, String specifiedType,
 89    boolean persistent, String initialValue, Location location)
 90    {
 91  122 Class propertyType = EnhanceUtils.extractPropertyType(op, propertyName, specifiedType);
 92   
 93  121 op.claimProperty(propertyName);
 94   
 95  121 String field = "_$" + propertyName;
 96   
 97  121 op.addField(field, propertyType);
 98   
 99    // Release 3.0 would squack a bit about overriding non-abstract methods
 100    // if they exist. 4.0 is less picky ... it blindly adds new methods, possibly
 101    // overwriting methods in the base component class.
 102   
 103  121 EnhanceUtils.createSimpleAccessor(op, field, propertyName, propertyType, location);
 104   
 105  121 addMutator(op, propertyName, propertyType, field, persistent, location);
 106   
 107  121 if (initialValue == null)
 108  114 addReinitializer(op, propertyType, field);
 109    else
 110  7 addInitialValue(op, propertyName, propertyType, field, initialValue, location);
 111    }
 112   
 113  114 private void addReinitializer(EnhancementOperation op, Class propertyType, String fieldName)
 114    {
 115  114 String defaultFieldName = fieldName + "$default";
 116   
 117  114 op.addField(defaultFieldName, propertyType);
 118   
 119    // On finishLoad(), store the current value into the default field.
 120   
 121  114 op.extendMethodImplementation(
 122    IComponent.class,
 123    EnhanceUtils.FINISH_LOAD_SIGNATURE,
 124    defaultFieldName + " = " + fieldName + ";");
 125   
 126    // On pageDetach(), restore the attribute to its default value.
 127   
 128  114 op.extendMethodImplementation(
 129    PageDetachListener.class,
 130    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
 131    fieldName + " = " + defaultFieldName + ";");
 132    }
 133   
 134  7 private void addInitialValue(EnhancementOperation op, String propertyName, Class propertyType,
 135    String fieldName, String initialValue, Location location)
 136    {
 137  7 String description = EnhanceMessages.initialValueForProperty(propertyName);
 138   
 139  7 InitialValueBindingCreator creator = new InitialValueBindingCreator(_bindingSource,
 140    description, initialValue, location);
 141   
 142  7 String creatorField = op.addInjectedField(
 143    fieldName + "$initialValueBindingCreator",
 144    InitialValueBindingCreator.class,
 145    creator);
 146   
 147  7 String bindingField = fieldName + "$initialValueBinding";
 148  7 op.addField(bindingField, IBinding.class);
 149   
 150  7 BodyBuilder builder = new BodyBuilder();
 151   
 152  7 builder.addln("{0} = {1}.createBinding(this);", bindingField, creatorField);
 153   
 154  7 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, builder
 155    .toString());
 156   
 157  7 builder.clear();
 158   
 159  7 builder.addln("{0} = {1};", fieldName, EnhanceUtils.createUnwrapExpression(
 160    op,
 161    bindingField,
 162    propertyType));
 163   
 164  7 String code = builder.toString();
 165   
 166    // In finishLoad() and pageDetach(), de-reference the binding to get the value
 167    // for the property.
 168   
 169  7 op.extendMethodImplementation(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE, code);
 170  7 op.extendMethodImplementation(
 171    PageDetachListener.class,
 172    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
 173    code);
 174   
 175    }
 176   
 177  121 private void addMutator(EnhancementOperation op, String propertyName, Class propertyType,
 178    String fieldName, boolean persistent, Location location)
 179    {
 180  121 String methodName = EnhanceUtils.createMutatorMethodName(propertyName);
 181   
 182  121 BodyBuilder body = new BodyBuilder();
 183   
 184  121 body.begin();
 185   
 186  121 if (persistent)
 187    {
 188  20 body.add("org.apache.tapestry.Tapestry#fireObservedChange(this, ");
 189  20 body.addQuoted(propertyName);
 190  20 body.addln(", ($w) $1);");
 191    }
 192   
 193  121 body.addln(fieldName + " = $1;");
 194   
 195  121 body.end();
 196   
 197  121 MethodSignature sig = new MethodSignature(void.class, methodName, new Class[]
 198    { propertyType }, null);
 199   
 200  121 op.addMethod(Modifier.PUBLIC, sig, body.toString(), location);
 201    }
 202   
 203  42 public void setErrorLog(ErrorLog errorLog)
 204    {
 205  42 _errorLog = errorLog;
 206    }
 207   
 208  42 public void setBindingSource(BindingSource bindingSource)
 209    {
 210  42 _bindingSource = bindingSource;
 211    }
 212    }