Clover coverage report - Code Coverage for tapestry release 4.0-beta-2
Coverage timestamp: Sat Jul 9 2005 22:02:17 EDT
file stats: LOC: 173   Methods: 5
NCLOC: 90   Classes: 1
30 day Evaluation License registered to hlship@comcast.net Your 30 day evaluation period has expired. Please visit http://www.cenqua.com to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Creator.java 100% 96.7% 100% 97.8%
coverage 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.test;
 16   
 17    import java.util.ArrayList;
 18    import java.util.HashMap;
 19    import java.util.Iterator;
 20    import java.util.List;
 21    import java.util.Map;
 22   
 23    import org.apache.commons.logging.Log;
 24    import org.apache.commons.logging.LogFactory;
 25    import org.apache.hivemind.ApplicationRuntimeException;
 26    import org.apache.hivemind.ClassResolver;
 27    import org.apache.hivemind.impl.DefaultClassResolver;
 28    import org.apache.hivemind.service.ClassFactory;
 29    import org.apache.hivemind.service.impl.ClassFactoryImpl;
 30    import org.apache.hivemind.util.PropertyUtils;
 31    import org.apache.tapestry.Tapestry;
 32    import org.apache.tapestry.enhance.AbstractPropertyWorker;
 33    import org.apache.tapestry.enhance.EnhancementOperationImpl;
 34    import org.apache.tapestry.enhance.EnhancementWorker;
 35    import org.apache.tapestry.services.ComponentConstructor;
 36    import org.apache.tapestry.spec.ComponentSpecification;
 37   
 38    /**
 39    * A utility class that is used to instantiate abstract Tapestry pages and components. It creates,
 40    * at runtime, a subclass where all abstract properties are filled in (each property complete with
 41    * an instance variable, an accessor method and a mutator method). This isn't quite the same as how
 42    * the class is enhanced at runtime (though it does use a subset of the same
 43    * {@link org.apache.tapestry.enhance.EnhancementWorker code}), but is sufficient to unit test the
 44    * class, especially listener methods.
 45    * <p>
 46    * One part of the enhancement is that the
 47    * {@link org.apache.tapestry.IComponent#getSpecification() specification}&nbsp;and
 48    * {@link org.apache.tapestry.IComponent#getMessages() messages}&nbsp;properties of the page or
 49    * component class are converted into read/write properties that can be set via reflection
 50    * (including {@link #newInstance(Class, Map)}.
 51    *
 52    * @author Howard Lewis Ship
 53    * @since 4.0
 54    */
 55    public class Creator
 56    {
 57    private static final Log LOG = LogFactory.getLog(Creator.class);
 58   
 59    /**
 60    * Keyed on Class, value is an {@link ComponentConstructor}.
 61    */
 62    private Map _constructors = new HashMap();
 63   
 64    private ClassFactory _classFactory = new ClassFactoryImpl();
 65   
 66    private ClassResolver _classResolver = new DefaultClassResolver();
 67   
 68    private List _workers = new ArrayList();
 69   
 70    {
 71    // Overrride AbstractComponent's implementations of
 72    // these two properties (making them read/write).
 73   
 74  123 _workers.add(new CreatePropertyWorker("messages"));
 75  123 _workers.add(new CreatePropertyWorker("specification"));
 76   
 77    // Implement any abstract properties.
 78    // Note that we don't bother setting the errorLog property
 79    // so failures may turn into NPEs.
 80   
 81  123 _workers.add(new AbstractPropertyWorker());
 82    }
 83   
 84  132 private ComponentConstructor createComponentConstructor(Class inputClass)
 85    {
 86  132 if (inputClass.isInterface() || inputClass.isPrimitive() || inputClass.isArray())
 87  1 throw new IllegalArgumentException(ScriptMessages.wrongTypeForEnhancement(inputClass));
 88   
 89  131 EnhancementOperationImpl op = new EnhancementOperationImpl(_classResolver,
 90    new ComponentSpecification(), inputClass, _classFactory);
 91   
 92  131 Iterator i = _workers.iterator();
 93  131 while (i.hasNext())
 94    {
 95  393 EnhancementWorker worker = (EnhancementWorker) i.next();
 96   
 97  393 worker.performEnhancement(op, null);
 98    }
 99   
 100  131 return op.getConstructor();
 101    }
 102   
 103  133 private ComponentConstructor getComponentConstructor(Class inputClass)
 104    {
 105  133 ComponentConstructor result = (ComponentConstructor) _constructors.get(inputClass);
 106   
 107  133 if (result == null)
 108    {
 109  132 result = createComponentConstructor(inputClass);
 110   
 111  131 _constructors.put(inputClass, result);
 112    }
 113   
 114  132 return result;
 115    }
 116   
 117    /**
 118    * Given a particular abstract class; will create an instance of that class. A subclass is
 119    * created with all abstract properties filled in with ordinary implementations.
 120    */
 121  133 public Object newInstance(Class abstractClass)
 122    {
 123  133 ComponentConstructor constructor = getComponentConstructor(abstractClass);
 124   
 125  132 try
 126    {
 127  132 return constructor.newInstance();
 128    }
 129    catch (Exception ex)
 130    {
 131  0 throw new ApplicationRuntimeException(ScriptMessages.unableToInstantiate(
 132    abstractClass,
 133    ex));
 134    }
 135    }
 136   
 137    /**
 138    * Creates a new instance of a given class, and then initializes properties of the instance. The
 139    * map contains string keys that are property names, and object values.
 140    */
 141  107 public Object newInstance(Class abstractClass, Map properties)
 142    {
 143  107 Object result = newInstance(abstractClass);
 144   
 145  107 if (properties != null)
 146    {
 147  82 Iterator i = properties.entrySet().iterator();
 148   
 149  82 while (i.hasNext())
 150    {
 151  181 Map.Entry e = (Map.Entry) i.next();
 152   
 153  181 String propertyName = (String) e.getKey();
 154   
 155  181 PropertyUtils.write(result, propertyName, e.getValue());
 156    }
 157    }
 158   
 159  107 return result;
 160    }
 161   
 162    /**
 163    * A convienience (useful in test code) for invoking {@link #newInstance(Class, Map)}. The Map
 164    * is constructed from the properties array, which consists of alternating keys and values.
 165    */
 166   
 167  107 public Object newInstance(Class abstractClass, Object[] properties)
 168    {
 169  107 Map propertyMap = Tapestry.convertArrayToMap(properties);
 170   
 171  107 return newInstance(abstractClass, propertyMap);
 172    }
 173    }