Clover coverage report - Code Coverage for tapestry release 4.0-alpha-3
Coverage timestamp: Mon May 16 2005 09:05:49 EDT
file stats: LOC: 173   Methods: 5
NCLOC: 90   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover 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  62
         _workers.add(new CreatePropertyWorker("messages"));
 75  62
         _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  62
         _workers.add(new AbstractPropertyWorker());
 82   
     }
 83   
 
 84  63
     private ComponentConstructor createComponentConstructor(Class inputClass)
 85   
     {
 86  63
         if (inputClass.isInterface() || inputClass.isPrimitive() || inputClass.isArray())
 87  1
             throw new IllegalArgumentException(ScriptMessages.wrongTypeForEnhancement(inputClass));
 88   
 
 89  62
         EnhancementOperationImpl op = new EnhancementOperationImpl(_classResolver,
 90   
                 new ComponentSpecification(), inputClass, _classFactory);
 91   
 
 92  62
         Iterator i = _workers.iterator();
 93  62
         while (i.hasNext())
 94   
         {
 95  186
             EnhancementWorker worker = (EnhancementWorker) i.next();
 96   
 
 97  186
             worker.performEnhancement(op, null);
 98   
         }
 99   
 
 100  62
         return op.getConstructor();
 101   
     }
 102   
 
 103  65
     private ComponentConstructor getComponentConstructor(Class inputClass)
 104   
     {
 105  65
         ComponentConstructor result = (ComponentConstructor) _constructors.get(inputClass);
 106   
 
 107  65
         if (result == null)
 108   
         {
 109  63
             result = createComponentConstructor(inputClass);
 110   
 
 111  62
             _constructors.put(inputClass, result);
 112   
         }
 113   
 
 114  64
         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  65
     public Object newInstance(Class abstractClass)
 122   
     {
 123  65
         ComponentConstructor constructor = getComponentConstructor(abstractClass);
 124   
 
 125  64
         try
 126   
         {
 127  64
             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  39
     public Object newInstance(Class abstractClass, Map properties)
 142   
     {
 143  39
         Object result = newInstance(abstractClass);
 144   
 
 145  39
         if (properties != null)
 146   
         {
 147  35
             Iterator i = properties.entrySet().iterator();
 148   
 
 149  35
             while (i.hasNext())
 150   
             {
 151  64
                 Map.Entry e = (Map.Entry) i.next();
 152   
 
 153  64
                 String propertyName = (String) e.getKey();
 154   
 
 155  64
                 PropertyUtils.write(result, propertyName, e.getValue());
 156   
             }
 157   
         }
 158   
 
 159  39
         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  39
     public Object newInstance(Class abstractClass, Object[] properties)
 168   
     {
 169  39
         Map propertyMap = Tapestry.convertArrayToMap(properties);
 170   
 
 171  39
         return newInstance(abstractClass, propertyMap);
 172   
     }
 173   
 }