View Javadoc

1   package net.sourceforge.jparam.conversion.creators;
2   
3   import java.lang.reflect.Constructor;
4   import java.lang.reflect.Method;
5   import java.lang.reflect.Modifier;
6   import java.util.HashSet;
7   import java.util.Iterator;
8   import java.util.Set;
9   
10  import net.sourceforge.jparam.conversion.ConverterRegistry;
11  import net.sourceforge.jparam.conversion.converters.CreatorConverter;
12  import net.sourceforge.jparam.conversion.converters.ParentConverter;
13  import net.sourceforge.jparam.util.MultiMap;
14  import net.sourceforge.jparam.util.Utils;
15  
16  /***
17   * This registry holds all the available creators for all registered Java
18   * classes
19   * 
20   * Once a <code>Class</code> is registered, all of its constructors are
21   * defined as creator
22   * <p>
23   * Constructors with a single argument are also defined as converters from the
24   * arguments type to the class type
25   * 
26   * @author ron_sidi
27   * 
28   */
29  public class CreatorRegistry {
30  	private static CreatorRegistry registry = null;
31  
32  	private MultiMap creators = new MultiMap();
33  
34  	private Set registeredClasses = new HashSet();
35  
36  	private CreatorRegistry() {
37  	}
38  
39  	public static CreatorRegistry getInstance() {
40  		if (registry == null) {
41  			registry = new CreatorRegistry();
42  		}
43  		return registry;
44  	}
45  
46  	Set getCreators(Class c) {
47  		return creators.get(c);
48  	}
49  
50  	/***
51  	 * Register all the creation method defined in the given helper class, a
52  	 * method is considered a creation method if:
53  	 * <p>
54  	 * <li>The method name begins with create (this is needed because Java
55  	 * doesn't distinguish between methods according to their return type)
56  	 * <li>The method is <code>public</code></li>
57  	 * <li>The method is <code>static</code></li>
58  	 * <li>The method has exactly one argument</li>
59  	 * <li>The method has a typed return value that is not primitive or void</li>
60  	 * 
61  	 * 
62  	 * @param c
63  	 */
64  	public void registerHelperClass(Class c) {
65  		Method[] creatorClassMethods = c.getMethods();
66  		for (int i = 0; i < creatorClassMethods.length; i++) {
67  			Method m = creatorClassMethods[i];
68  
69  			if (MethodCreator.isMethodValid(m)) {
70  				MethodCreator mc = new MethodCreator(m);
71  
72  				registerCreator(mc);
73  			}
74  		}
75  	}
76  
77  	public void registerClass(Class c) {
78  		Utils.assert(!registeredClasses.contains(c), "Class " + c.getName()
79  				+ " already registered");
80  		registeredClasses.add(c);
81  		Constructor[] classConstructors = c.getConstructors();
82  		for (int i = 0; i < classConstructors.length; i++) {
83  			if (Modifier.isPublic(classConstructors[i].getModifiers())) {
84  				ConstructorCreator creator = new ConstructorCreator(
85  						classConstructors[i]);
86  				registerCreator(creator);
87  			}
88  		}
89  
90  		// @TODO: If a hierarchy of classes is registered, all conversions are
91  		// added, need to verify this doesn't happne
92  		// if a exdends b and b extends c, we will have a->b and a->c and b->
93  		// when a->c is not needed and maybe even not correct
94  
95  		// register parent converters, these converters will do nothing but
96  		// change the weight of conversion paths,
97  		// making sure that if we have converters both for a class and its
98  		// ancestor, the correct converter will be taken
99  		for (Iterator iter = registeredClasses.iterator(); iter.hasNext();) {
100 			Class existingClass = (Class) iter.next();
101 			if (existingClass.equals(c.getSuperclass())) {
102 				ConverterRegistry.getInstance().registerConverter(
103 						new ParentConverter(existingClass, c));
104 			}
105 
106 			if (c.equals(existingClass.getSuperclass())) {
107 				ConverterRegistry.getInstance().registerConverter(
108 						new ParentConverter(c, existingClass));
109 			}
110 		}
111 	}
112 
113 	private void registerCreator(ICreator c) {
114 		Utils.assert(registeredClasses.contains(c.getReturnClass()),
115 				"Registering creator for non-registered class..." + c);
116 		creators.put(c.getReturnClass(), c);
117 		if (c.getParameterTypes().length == 1) {
118 			ConverterRegistry.getInstance().registerConverter(
119 					new CreatorConverter(c));
120 		}
121 	}
122 
123 	public static void clearSingleton() {
124 		registry = null;
125 	}
126 }