KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > test > Creator


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 JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
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 JavaDoc _constructors = new HashMap JavaDoc();
63
64     private ClassFactory _classFactory = new ClassFactoryImpl();
65
66     private ClassResolver _classResolver = new DefaultClassResolver();
67
68     private List JavaDoc _workers = new ArrayList JavaDoc();
69
70     {
71         // Overrride AbstractComponent's implementations of
72
// these two properties (making them read/write).
73

74         _workers.add(new CreatePropertyWorker("messages"));
75         _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         _workers.add(new AbstractPropertyWorker());
82     }
83
84     private ComponentConstructor createComponentConstructor(Class JavaDoc inputClass)
85     {
86         if (inputClass.isInterface() || inputClass.isPrimitive() || inputClass.isArray())
87             throw new IllegalArgumentException JavaDoc(ScriptMessages.wrongTypeForEnhancement(inputClass));
88
89         EnhancementOperationImpl op = new EnhancementOperationImpl(_classResolver,
90                 new ComponentSpecification(), inputClass, _classFactory);
91
92         Iterator JavaDoc i = _workers.iterator();
93         while (i.hasNext())
94         {
95             EnhancementWorker worker = (EnhancementWorker) i.next();
96
97             worker.performEnhancement(op, null);
98         }
99
100         return op.getConstructor();
101     }
102
103     private ComponentConstructor getComponentConstructor(Class JavaDoc inputClass)
104     {
105         ComponentConstructor result = (ComponentConstructor) _constructors.get(inputClass);
106
107         if (result == null)
108         {
109             result = createComponentConstructor(inputClass);
110
111             _constructors.put(inputClass, result);
112         }
113
114         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     public Object JavaDoc newInstance(Class JavaDoc abstractClass)
122     {
123         ComponentConstructor constructor = getComponentConstructor(abstractClass);
124
125         try
126         {
127             return constructor.newInstance();
128         }
129         catch (Exception JavaDoc ex)
130         {
131             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     public Object JavaDoc newInstance(Class JavaDoc abstractClass, Map JavaDoc properties)
142     {
143         Object JavaDoc result = newInstance(abstractClass);
144
145         if (properties != null)
146         {
147             Iterator JavaDoc i = properties.entrySet().iterator();
148
149             while (i.hasNext())
150             {
151                 Map.Entry JavaDoc e = (Map.Entry JavaDoc) i.next();
152
153                 String JavaDoc propertyName = (String JavaDoc) e.getKey();
154
155                 PropertyUtils.write(result, propertyName, e.getValue());
156             }
157         }
158
159         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     public Object JavaDoc newInstance(Class JavaDoc abstractClass, Object JavaDoc[] properties)
168     {
169         Map JavaDoc propertyMap = Tapestry.convertArrayToMap(properties);
170
171         return newInstance(abstractClass, propertyMap);
172     }
173 }
Popular Tags