KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > julia > factory > CheckGenericFactoryMixin


1 package org.objectweb.fractal.julia.factory;
2
3 import org.objectweb.fractal.api.Component;
4 import org.objectweb.fractal.api.Type;
5 import org.objectweb.fractal.api.factory.GenericFactory;
6 import org.objectweb.fractal.api.factory.InstantiationException;
7 import org.objectweb.fractal.api.type.ComponentType;
8 import org.objectweb.fractal.api.type.InterfaceType;
9 import org.objectweb.fractal.julia.loader.Initializable;
10 import org.objectweb.fractal.julia.loader.Tree;
11
12 import java.lang.reflect.Method JavaDoc;
13 import java.lang.reflect.Modifier JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Map JavaDoc;
16
17 /**
18  * Provides reflective checks to a {@link GenericFactory}.
19  * <br>
20  * <br>
21  * <b>Requirements</b>
22  * <ul>
23  * <li>the types of the components created with this generic factory must be
24  * instances of the {@link ComponentType} interface.</li>
25  * <li>the Java platform must provide the Java Reflection API, the
26  * ClassLoader class, and Thread.getContextClassLoader method.</li>
27  * </ul>
28  */

29
30 public abstract class CheckGenericFactoryMixin
31   implements GenericFactory, Initializable
32 {
33
34   // -------------------------------------------------------------------------
35
// Private constructor
36
// -------------------------------------------------------------------------
37

38   private CheckGenericFactoryMixin () {
39   }
40
41   // -------------------------------------------------------------------------
42
// Fields and methods added and overriden by the mixin class
43
// -------------------------------------------------------------------------
44

45   private boolean useContextClassLoader;
46   
47   /**
48    * Initializes this object with the given arguments.
49    *
50    * @param args the arguments to be used to initialize this object. The format
51    * of these arguments depends on the class of this object.
52    * @throws Exception if a problem occurs during the object initialization.
53    */

54
55   public void initialize (final Tree args) throws Exception JavaDoc {
56     Tree t = args.getValue("use-context-class-loader");
57     if (t != null && t.equals("true")) {
58       useContextClassLoader = true;
59     }
60   }
61
62   /**
63    * Checks that <tt>type</tt> and <tt>contentDesc</tt> are compatible, and
64    * then calls the overriden method.
65    *
66    * @param type an arbitrary component type.
67    * @param controllerDesc a description of the controller part of the
68    * component to be created. This description is implementation specific.
69    * If it is <tt>null</tt> then a "default" controller part will be used.
70    * @param contentDesc a description of the content part of the
71    * component to be created. This description is implementation specific.
72    * It may be <tt>null</tt> to create component with an empty initial
73    * content. It may also be, in Java, the fully qualified name of a Java
74    * class, to create primitive components.
75    * @return the {@link Component} interface of the created component.
76    * @throws InstantiationException if the component cannot be created.
77    */

78
79   public Component newFcInstance (
80     final Type type,
81     final Object JavaDoc controllerDesc,
82     final Object JavaDoc contentDesc) throws InstantiationException JavaDoc
83   {
84     ClassLoader JavaDoc loader = null;
85     if (controllerDesc instanceof Object JavaDoc[]) {
86       loader = (ClassLoader JavaDoc)((Object JavaDoc[])controllerDesc)[0];
87     }
88     loader = (ClassLoader JavaDoc)getFcLoader(loader);
89
90     checkFcType(type, loader);
91     
92     Object JavaDoc content = contentDesc;
93     if (content instanceof Object JavaDoc[]) {
94       // case of a template content descriptor:
95
// extract the instance content descriptor
96
content = ((Object JavaDoc[])content)[1];
97     }
98     if (content instanceof String JavaDoc) {
99       checkFcContentClass(type, (String JavaDoc)content, loader);
100     }
101     return _super_newFcInstance(type, controllerDesc, contentDesc);
102   }
103
104   public Object JavaDoc getFcLoader (final Object JavaDoc loader) {
105     if (loader == null) {
106       if (useContextClassLoader) {
107         return Thread.currentThread().getContextClassLoader();
108       } else {
109         return getClass().getClassLoader();
110       }
111     } else {
112       return _super_getFcLoader(loader);
113     }
114   }
115   
116   /**
117    * Checks the given component type.
118    *
119    * @param type the component type to be checked.
120    * @param loader the class loader to be used to load the Java interface types.
121    * @throws InstantiationException if the given type is invalid.
122    */

123   
124   public void checkFcType (final Type type, final ClassLoader JavaDoc loader)
125     throws InstantiationException JavaDoc
126   {
127     if (type instanceof ComponentType) {
128       InterfaceType[] itfTypes = ((ComponentType)type).getFcInterfaceTypes();
129       for (int i = 0; i < itfTypes.length; ++i) {
130         InterfaceType itfType = itfTypes[i];
131         String JavaDoc name = itfType.getFcItfName();
132         String JavaDoc signature = itfType.getFcItfSignature();
133         // checks that the interface exists
134
Class JavaDoc itf;
135         try {
136           itf = loader.loadClass(signature);
137         } catch (ClassNotFoundException JavaDoc e) {
138           throw new ChainedInstantiationException(
139             e, null, "No such interface: " + signature);
140         }
141         // checks that it is a public interface
142
if (!(itf.isInterface() && Modifier.isPublic(itf.getModifiers()))) {
143           throw new ChainedInstantiationException(
144             null, null, signature + " is not a public interface");
145         }
146         if (name.equals("attribute-controller")) {
147           // checks that itf is a valid atrribute controller interface
148
Class JavaDoc ac;
149           try {
150             ac = loader.loadClass(
151               "org.objectweb.fractal.api.control.AttributeController");
152           } catch (ClassNotFoundException JavaDoc e) {
153             throw new ChainedInstantiationException(
154               e, null, "Cannot check this operation");
155           }
156           if (ac.isAssignableFrom(itf)) {
157             if (!checkFcAttributeControllerInterface(itf)) {
158               throw new ChainedInstantiationException(
159                 null,
160                 null,
161                 signature + " is not a valid attribute controller interface");
162             }
163           }
164         }
165       }
166     }
167   }
168   
169   /**
170    * Checks that the given class is valid attribute controller interface.
171    *
172    * @param itf a Java interface
173    * @return <tt>true</tt> if the given interface is valid, or <tt>false</tt>
174    * otherwise.
175    */

176
177   public boolean checkFcAttributeControllerInterface (final Class JavaDoc itf) {
178     Map JavaDoc types = new HashMap JavaDoc();
179     Method JavaDoc[] meths = itf.getMethods();
180     // checks each method
181
for (int i = 0; i < meths.length; ++i) {
182       Method JavaDoc m = meths[i];
183       String JavaDoc name = m.getName();
184       Class JavaDoc[] formals = m.getParameterTypes();
185       Class JavaDoc result = m.getReturnType();
186       if (name.startsWith("get")) {
187         if (formals.length == 0 && !result.equals(Void.TYPE)) {
188           types.put(name, result);
189           continue;
190         }
191       } else if (name.startsWith("set")) {
192         if (formals.length == 1 && result.equals(Void.TYPE)) {
193           types.put(name, formals[0]);
194           continue;
195         }
196       }
197       return false;
198     }
199     // checks that if a get/set method has a complementary set/get method,
200
// then the two methods are compatible
201
for (int i = 0; i < meths.length; ++i) {
202       Method JavaDoc m = meths[i];
203       String JavaDoc name = m.getName();
204       if (name.startsWith("get")) {
205         Class JavaDoc type = (Class JavaDoc)types.get("set" + name.substring(3));
206         if (type == null || m.getReturnType().equals(type)) {
207           continue;
208         }
209       } else {
210         Class JavaDoc type = (Class JavaDoc)types.get("get" + name.substring(3));
211         if (type == null || m.getParameterTypes()[0].equals(type)) {
212           continue;
213         }
214       }
215       return false;
216     }
217     return true;
218   }
219
220   /**
221    * Checks the given class against the given component type. This method checks
222    * that the given class exists, that it is public non abstract class with a
223    * default public constructor, that it implements all the server interface
224    * types (except control interface types) of the given type, and that it
225    * implements BindingController (if there is at least one client interface).
226    *
227    * @param type a component type, must be instance of {@link ComponentType}.
228    * @param content the fully qualified name of a Java class.
229    * @param loader the class loader to be used to load the "content" class.
230    * @throws InstantiationException if the given class is not compatible with
231    * the given component type.
232    */

233
234   public void checkFcContentClass (
235     final Type type,
236     final String JavaDoc content,
237     final ClassLoader JavaDoc loader) throws InstantiationException JavaDoc
238   {
239     Class JavaDoc contentClass;
240     // checks that the class exists
241
try {
242       contentClass = loader.loadClass(content);
243     } catch (ClassNotFoundException JavaDoc e) {
244       throw new ChainedInstantiationException(
245         e,
246         null,
247         "Cannot find the component implementation class '" + content + "'");
248     }
249     // checks that the class is public and non abstract class
250
int mods = contentClass.getModifiers();
251     if (!Modifier.isPublic(mods) ||
252         Modifier.isAbstract(mods) ||
253         Modifier.isInterface(mods))
254     {
255       throw new ChainedInstantiationException(
256         null,
257         null,
258         "The component implementation class '" + content +
259         "' is a not public, non abstract class");
260     }
261     // checks that the class has a default public constructor
262
try {
263       contentClass.getConstructor(new Class JavaDoc[0]);
264     } catch (final NoSuchMethodException JavaDoc e) {
265       throw new ChainedInstantiationException(
266         null,
267         null,
268         "The component implementation class '" + content +
269         "' does not have a default public constructor");
270     }
271     // check that the class implements BindingController, if this is required
272
boolean hasDependencies = false;
273     ComponentType compType = (ComponentType)type;
274     InterfaceType[] itfTypes = compType.getFcInterfaceTypes();
275     for (int i = 0; i < itfTypes.length; i++) {
276       InterfaceType itfType = itfTypes[i];
277       if (itfType.isFcClientItf()) {
278         hasDependencies = true;
279       }
280     }
281     if (hasDependencies) {
282       Class JavaDoc bc;
283       try {
284         bc = loader.loadClass(
285           "org.objectweb.fractal.api.control.BindingController");
286       } catch (ClassNotFoundException JavaDoc e) {
287         throw new ChainedInstantiationException(
288           e, null, "Cannot find the BindingController class");
289       }
290       if (!bc.isAssignableFrom(contentClass)) {
291         throw new ChainedInstantiationException(
292           null,
293           null,
294           "The component implementation class '" + content +
295           "' must implement the BindingController interface, " +
296           "since the component type contains client interfaces");
297       }
298     }
299     // check that the class implements all the server interface types
300
for (int i = 0; i < itfTypes.length; ++i) {
301       InterfaceType itfType = itfTypes[i];
302       String JavaDoc itfName = itfType.getFcItfName();
303       if (!itfType.isFcClientItf() &&
304           !itfType.isFcOptionalItf() &&
305           !(itfName.equals("component") ||itfName.endsWith("-controller")))
306       {
307         Class JavaDoc itf;
308         try {
309           itf = loader.loadClass(itfType.getFcItfSignature());
310         } catch (ClassNotFoundException JavaDoc e) {
311           throw new ChainedInstantiationException(
312             e,
313             null,
314             "Cannot find the Java interface '" + itfType.getFcItfSignature() +
315             "' declared in the component type");
316         }
317         if (!itf.isAssignableFrom(contentClass)) {
318           throw new ChainedInstantiationException(
319             null,
320             null,
321             "The component implementation class '" + content +
322             "' does not implement the '" + itf.getName() +
323             "' server interface declared in the component type");
324         }
325       }
326     }
327   }
328
329   // -------------------------------------------------------------------------
330
// Fields and methods required by the mixin class in the base class
331
// -------------------------------------------------------------------------
332

333   /**
334    * The {@link Initializable#initialize initialize} method overriden by
335    * this mixin.
336    *
337    * @param args the arguments to be used to initialize this object. The format
338    * of these arguments depends on the class of this object.
339    * @throws Exception if a problem occurs during the object initialization.
340    */

341
342   public abstract void _super_initialize (Tree args) throws Exception JavaDoc;
343
344   /**
345    * The {@link GenericFactory#newFcInstance newFcInstance} method overriden by
346    * this mixin.
347    *
348    * @param type an arbitrary component type.
349    * @param controllerDesc a description of the controller part of the
350    * component to be created. This description is implementation specific.
351    * If it is <tt>null</tt> then a "default" controller part will be used.
352    * @param contentDesc a description of the content part of the
353    * component to be created. This description is implementation specific.
354    * It may be <tt>null</tt> to create component with an empty initial
355    * content. It may also be, in Java, the fully qualified name of a Java
356    * class, to create primitive components.
357    * @return the {@link Component} interface of the created component.
358    * @throws InstantiationException if the component cannot be created.
359    */

360
361   public abstract Component _super_newFcInstance (
362     Type type,
363     Object JavaDoc controllerDesc,
364     Object JavaDoc contentDesc) throws InstantiationException JavaDoc;
365   
366   public abstract Object JavaDoc _super_getFcLoader (Object JavaDoc loader);
367 }
368
Popular Tags