KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > swixml > DefaultFactory


1 /*--
2  $Id: DefaultFactory.java,v 1.1 2004/03/01 07:56:05 wolfpaulus Exp $
3
4  Copyright (C) 2003-2004 Wolf Paulus.
5  All rights reserved.
6
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions
9  are met:
10
11  1. Redistributions of source code must retain the above copyright
12  notice, this list of conditions, and the following disclaimer.
13
14  2. Redistributions in binary form must reproduce the above copyright
15  notice, this list of conditions, and the disclaimer that follows
16  these conditions in the documentation and/or other materials provided
17  with the distribution.
18
19  3. The end-user documentation included with the redistribution,
20  if any, must include the following acknowledgment:
21         "This product includes software developed by the
22          SWIXML Project (http://www.swixml.org/)."
23  Alternately, this acknowledgment may appear in the software itself,
24  if and wherever such third-party acknowledgments normally appear.
25
26  4. The name "Swixml" must not be used to endorse or promote products
27  derived from this software without prior written permission. For
28  written permission, please contact <info_AT_swixml_DOT_org>
29
30  5. Products derived from this software may not be called "Swixml",
31  nor may "Swixml" appear in their name, without prior written
32  permission from the Swixml Project Management.
33
34  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  DISCLAIMED. IN NO EVENT SHALL THE SWIXML PROJECT OR ITS
38  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
41  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
42  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
43  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
44  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  SUCH DAMAGE.
46  ====================================================================
47
48  This software consists of voluntary contributions made by many
49  individuals on behalf of the Swixml Project and was originally
50  created by Wolf Paulus <wolf_AT_swixml_DOT_org>. For more information
51  on the Swixml Project, please see <http://www.swixml.org/>.
52 */

53
54 package org.swixml;
55
56 import java.lang.reflect.Constructor JavaDoc;
57 import java.lang.reflect.InvocationTargetException JavaDoc;
58 import java.lang.reflect.Method JavaDoc;
59 import java.util.*;
60
61 /**
62  * The <code>DefaultFactory</code> is a default implementation of the <code>Factory</code> Interface.
63  * <p>The DefaultFactory registers all setter methods that take a
64  * single producable paramter with a class template </p>
65  *
66  * @author <a HREF="mailto:wolf@paulus.com">Wolf Paulus</a>
67  * @version $Revision: 1.1 $
68  */

69 public final class DefaultFactory implements Factory {
70
71   /** Collection for all setter methods */
72   private final Collection setters = new ArrayList();
73
74   /** The factory creates instances of this Class */
75   private final Class JavaDoc template;
76
77   /** Priority to resolve method name clashes */
78   protected Class JavaDoc[] parameterPriority = {String JavaDoc.class, float.class, double.class, boolean.class, char.class, long.class, byte.class, int.class};
79
80   /**
81    * Creates a new Factory for the given <code>Class</code> template.
82    * @param template <code>Class</code>
83    *
84    * <p><b>Note:</b><br>
85    * Only <i>set</i>Methods that take a single parameter are considered.
86    * Moreover, to be regsitered, a Converter needs to be available in the ConverterLibrary that can create
87    * instances of the paramter type.</p>
88    */

89   public DefaultFactory( Class JavaDoc template ) {
90     this.template = template;
91     //
92
// Collects all set<Methods> that require a single parameter, which can be created by an Converter.
93
//
94
this.registerSetters();
95   }
96
97   /**
98    * Returns a priority ID of the given type based on a priority arrray
99    * @param type <code>Class</code>
100    * @return <code>int</code> parameter type priority
101    */

102   protected int priority( Class JavaDoc type ) {
103     for (int i = 0; i < parameterPriority.length; i++) {
104       if (type.isAssignableFrom( parameterPriority[i] ))
105         return i;
106     }
107     return -1;
108   }
109
110   /**
111    * Registers all available setter methods meeting these rules:
112    * <ul>
113    * <li>Method name needs to start with <i>set</i></li>
114    * <li>Method signature specifies exactly one parameter</li>
115    * <li>if methods have the same name then super class methods are ignored</li>
116    * <li>if methods have the same name and are implemented in the same class,
117    * then only the method which parameter type has the highest priority is registered</li>
118    * </ul>
119    */

120   protected void registerSetters() {
121     //
122
// Collects all set<Methods> that require a single parameter, which can be created by an Converter.
123
//
124
Method JavaDoc[] methods = template.getMethods();
125     for (int i = 0; i < methods.length; i++) {
126       String JavaDoc methodeName = methods[i].getName();
127       if (methodeName.startsWith( Factory.SETTER_ID )) {
128         if (methods[i].getParameterTypes().length == 1) {
129           Class JavaDoc paraType = methods[i].getParameterTypes()[0];
130           if (ConverterLibrary.getInstance().hasConverter( paraType )) {
131             //
132
// Check for registered method with the same name:
133
// Here it is perfectly fine to use getSetter and not guessSetter, since we are dealing with Methods already
134
Method JavaDoc m = this.getSetter( methodeName );
135             if (m != null) {
136               //
137
// Here: m and method[i] have the same name. m is already regsitered and method[i] wants to.
138
// The most specializied method should win. If both methods are implemented within the same class,
139
// then the method's paramter will be checked for the highest priority.
140
//
141
Class JavaDoc cm = m.getDeclaringClass();
142               Class JavaDoc cmi = methods[i].getDeclaringClass();
143
144               if (cm.equals( cmi )) {
145                 Class JavaDoc pType = m.getParameterTypes()[0];
146                 if (priority( pType ) < priority( paraType )) {
147                   setters.remove( m );
148                   setters.add( methods[i] );
149                 }
150               } else if (cm.isAssignableFrom( cmi )) {
151                 setters.remove( m );
152                 setters.add( methods[i] );
153               }
154             } else {
155               setters.add( methods[i] );
156             }
157           }
158         }
159       }
160     }
161     //Collections.sort((List)setters);
162
}
163
164   /**
165    * Create a new component instance
166    *
167    * @return instance <code>Object</code> a new instance of a template class
168    * @throws Exception
169    */

170   public Object JavaDoc newInstance() throws Exception JavaDoc {
171     return template.newInstance();
172   }
173
174
175   /**
176    * Creates a new Object which class is {@link #getTemplate()}.
177    * A default costructior is only used if no constructor is available,
178    * accepting the provided parameter
179    * @param parameter <code>Object</code>, parameter used during construction or initialization.
180    * @return instance <code>Object</code> a new instance of a template class
181    * @throws Exception
182    */

183   public Object JavaDoc newInstance( Object JavaDoc parameter ) throws Exception JavaDoc {
184     Class JavaDoc pType = parameter.getClass(); // get runtime class of the parameter
185
Constructor JavaDoc[] ctors = template.getConstructors();
186     for (int i = 0; i < ctors.length; i++) {
187       Class JavaDoc[] paraTypes = ctors[i].getParameterTypes();
188       if (0 < paraTypes.length && paraTypes[0].isAssignableFrom( pType )) {
189         return ctors[i].newInstance( new Object JavaDoc[]{parameter} );
190       }
191     }
192     return template.newInstance();
193   }
194
195
196   /**
197    * Creates a new Object which class is {@link #getTemplate()} and the constructor
198    * parameter are <code>parameter</code>.
199    *
200    * @param parameter <code>Object[]</code> the parameter array to be passed into the constructor
201    * @return <code>Object</object> - the created object, an instance of the template class
202    * @throws InstantiationException if the creation of the object failed
203    * @throws IllegalAccessException if the constructor is either private or protected.
204    * @throws InvocationTargetException if the constructor invoked throws an exception
205    *
206    * idea suggested by Frank Meissner <f.meissner@web.de>
207    *
208    */

209   public Object JavaDoc newInstance( Object JavaDoc[] parameter ) throws InstantiationException JavaDoc, IllegalAccessException JavaDoc, InvocationTargetException JavaDoc {
210     if (parameter != null) {
211       Class JavaDoc pTypes[] = new Class JavaDoc[parameter.length]; // parameter types
212
Constructor JavaDoc constructors[] = template.getConstructors();
213       Constructor JavaDoc ctor = null;
214
215       //
216
// init. parameter type array
217
//
218
for (int i = 0; i < pTypes.length; i++) {
219         pTypes[i] = parameter[i].getClass();
220       }
221
222       //
223
// find matching Ctor
224
//
225
for (int i = 0; ctor == null && i < constructors.length; i++) {
226         Class JavaDoc cParams[] = constructors[i].getParameterTypes(); // ctor's paramter types
227

228         if (cParams.length == pTypes.length) {
229           ctor = constructors[i]; // potential match found ...
230
for (int j = 0; ctor != null && j < cParams.length; j++) {
231             if (cParams[j].equals( Object JavaDoc.class )) {
232               if (!cParams[j].equals( pTypes[j] )) {
233                 ctor = null; //dismissed
234
}
235             } else {
236               if (!cParams[j].isAssignableFrom( pTypes[j] )) {
237                 ctor = null; //dismissed
238
}
239             }
240           } // end for j - loop Ctor's parameter
241
}
242       } // end for i - loop all Ctors
243

244       //
245
// instantiate using ctor with mathcing parameter array or throw IllegalArgumentException
246
//
247
if (ctor != null) {
248         return ctor.newInstance( parameter );
249       } else { // no matching constructor was found
250
throw new IllegalArgumentException JavaDoc( "unable to find constructor, accepting:" + pTypes );
251       }
252     } else {
253       return template.newInstance();
254     }
255   }
256
257
258   /**
259    * @return class - <code>Class</code> the backing class template
260    */

261   public Class JavaDoc getTemplate() {
262     return template;
263   }
264
265   /**
266    * @return <code>Collection</code> containing all available setter methods
267    */

268   public Collection getSetters() {
269     return setters;
270   }
271
272   /**
273    * Returns a Setter Method that accepts the given class as a parameter
274    * @param template <code>Class</code>
275    * @return <code>Method</code> - setter that accepts the given class as a parameter
276    * @see org.swixml.Factory#getSetter(java.lang.Class)
277    */

278   public Method JavaDoc getSetter( Class JavaDoc template ) {
279     Method JavaDoc method = null;
280     Iterator it = setters.iterator();
281     while (it != null && it.hasNext()) {
282       Method JavaDoc m = (Method JavaDoc) it.next();
283       Class JavaDoc[] paraTypes = m.getParameterTypes();
284       if (paraTypes != null && 0 < paraTypes.length && template.equals( paraTypes[0] )) {
285         method = m;
286         break;
287       }
288     } // end_for
289
return method;
290   }
291
292   /**
293    * Returns a setter method by name<br>
294    * @param name <code>String</code> name of the setter method
295    * @return <code>Method</code> - setter method which can be invoked on an object of the template class
296    * @see #guessSetter
297    * @see org.swixml.Factory
298    * <pre><b>Typical Use:</b>
299    * <p>Method method = factory.getSetter(&quot;set&quot; + Parser.capitalize(attr.getName()));</p>
300    * </pre>
301    */

302   public Method JavaDoc getSetter( String JavaDoc name ) {
303     Method JavaDoc method = null;
304     Iterator it = setters.iterator();
305     while (it != null && it.hasNext()) {
306       Method JavaDoc m = (Method JavaDoc) it.next();
307       if (m.getName().equals( name )) {
308         method = m;
309         break;
310       }
311     }
312     return method;
313   }
314
315   /**
316    * Returns a setter method by a Attribute name. Differently to the <code>getSetter</code> method, here the attibute
317    * name can be used directly and case doesn't matter.<br>
318    *
319    * @param name <code>String</code> name of the setter method
320    *
321    * @return <code>Method</code> - setter method which can invoked on an object of the template class
322    *
323    * @see #getSetter
324    * <pre><b>Typical Use:</b>
325    * <p>Method method = factory.getSetter( attr.getName() );</p>
326    * </pre>
327    */

328   public Method JavaDoc guessSetter( String JavaDoc name ) {
329
330     Method JavaDoc method = null;
331     Iterator it = setters.iterator();
332     name = (Factory.SETTER_ID + name).toLowerCase();
333     while (it != null && it.hasNext()) {
334       Method JavaDoc m = (Method JavaDoc) it.next();
335       if (m.getName().toLowerCase().equals( name )) {
336         method = m;
337         break;
338       }
339     }
340     return method;
341   }
342
343   /**
344    * Remove the given method form the collection of supported setters.
345    * @param method <code>Method</code>
346    */

347   public void removeSetter( Method JavaDoc method ) {
348     setters.remove( method );
349   }
350 }
Popular Tags