KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > annotations > internal > AnnotatedModuleProcessor


1 // Copyright 2007 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.hivemind.annotations.internal;
16
17 import java.lang.annotation.Annotation JavaDoc;
18 import java.lang.reflect.Method JavaDoc;
19 import java.lang.reflect.Modifier JavaDoc;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.hivemind.ApplicationRuntimeException;
24 import org.apache.hivemind.ClassResolver;
25 import org.apache.hivemind.ErrorHandler;
26 import org.apache.hivemind.Location;
27 import org.apache.hivemind.Resource;
28 import org.apache.hivemind.annotations.AnnotationsMessages;
29 import org.apache.hivemind.annotations.definition.Configuration;
30 import org.apache.hivemind.annotations.definition.Module;
31 import org.apache.hivemind.annotations.definition.Service;
32 import org.apache.hivemind.annotations.definition.Submodule;
33 import org.apache.hivemind.definition.Contribution;
34 import org.apache.hivemind.definition.ImplementationConstructor;
35 import org.apache.hivemind.definition.ImplementationDefinition;
36 import org.apache.hivemind.definition.Occurances;
37 import org.apache.hivemind.definition.RegistryDefinition;
38 import org.apache.hivemind.definition.Visibility;
39 import org.apache.hivemind.definition.impl.ConfigurationPointDefinitionImpl;
40 import org.apache.hivemind.definition.impl.ContributionDefinitionImpl;
41 import org.apache.hivemind.definition.impl.ModuleDefinitionImpl;
42 import org.apache.hivemind.definition.impl.ImplementationDefinitionImpl;
43 import org.apache.hivemind.definition.impl.ServicePointDefinitionImpl;
44 import org.apache.hivemind.util.ClasspathResource;
45 import org.apache.hivemind.util.IdUtils;
46
47 /**
48  * Does the work for {@link org.apache.hivemind.annotations.AnnotatedModuleReader}. Processes an
49  * annotated class and registers the defined extension and extension points in a registry
50  * definition.
51  * The construction of extension points and extensions bases on reflective method calls
52  * to an instance of the module class. The module instance is created by a
53  * {@link ModuleInstanceProvider} during registry construction.
54  *
55  * @author Achim Huegen
56  */

57 public class AnnotatedModuleProcessor
58 {
59     private static final Log _log = LogFactory.getLog(AnnotatedModuleProcessor.class);
60
61     private ClassResolver _classResolver;
62
63     private ErrorHandler _errorHandler;
64
65     private RegistryDefinition _registryDefinition;
66
67     public AnnotatedModuleProcessor(RegistryDefinition registryDefinition,
68             ClassResolver classResolver, ErrorHandler errorHandler)
69     {
70         _registryDefinition = registryDefinition;
71         _classResolver = classResolver;
72         _errorHandler = errorHandler;
73     }
74     
75     public void processModule(Class JavaDoc moduleClass)
76     {
77         String JavaDoc moduleId = determineModuleId(moduleClass);
78         processModule(moduleClass, moduleId);
79     }
80
81     /**
82      * Processes a module. Inspects the class.
83      *
84      * @param moduleClass
85      */

86     public void processModule(Class JavaDoc moduleClass, String JavaDoc moduleId)
87     {
88         checkModuleClassPrerequisites(moduleClass);
89         
90         ModuleDefinitionImpl module = new ModuleDefinitionImpl(moduleId,
91                 createModuleLocation(moduleClass), _classResolver, moduleClass.getPackage().getName());
92
93         // processServices(moduleClass);
94

95         ModuleInstanceProvider instanceProvider = new ModuleInstanceProviderImpl(moduleClass,
96                 module.getId());
97         // Register provider as initialization provider so it can acquire a reference to the
98
// registry
99
_registryDefinition.addRegistryInitializationListener(instanceProvider);
100
101         processModuleMethods(moduleClass, module, instanceProvider);
102         _registryDefinition.addModule(module);
103
104     }
105     
106     /**
107      * Ensures that a module class fulfills all prerequisites.
108      *
109      * @param moduleClass
110      */

111     protected void checkModuleClassPrerequisites(Class JavaDoc moduleClass)
112     {
113         // These modifiers are allowed
114
final int validModifiers = Modifier.PUBLIC;
115         
116         int invalidModifiers = moduleClass.getModifiers() & ~validModifiers;
117         if (invalidModifiers > 0) {
118             throw new ApplicationRuntimeException(AnnotationsMessages.moduleClassHasInvalidModifiers(moduleClass, invalidModifiers));
119         }
120         
121         // Check for package-private access
122
if ((moduleClass.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) == 0) {
123             throw new ApplicationRuntimeException(AnnotationsMessages.moduleClassIsPackagePrivate(moduleClass));
124         }
125     }
126
127     private void processModuleMethods(Class JavaDoc moduleClass, ModuleDefinitionImpl module,
128             ModuleInstanceProvider instanceProvider)
129     {
130         // We need access to protected methods via getDeclaredMethods
131
// That means we must visit all superclasses manually
132
Method JavaDoc[] methods = moduleClass.getDeclaredMethods();
133         for (int i = 0; i < methods.length; i++)
134         {
135             Method JavaDoc method = methods[i];
136             processMethod(method, module, instanceProvider);
137             // Process superclass
138
Class JavaDoc superClass = moduleClass.getSuperclass();
139             if (!superClass.equals(Object JavaDoc.class)) {
140                 processModuleMethods(superClass, module, instanceProvider);
141             }
142         }
143     }
144
145     private void processMethod(Method JavaDoc method, ModuleDefinitionImpl module,
146             ModuleInstanceProvider instanceProvider)
147     {
148         if (_log.isDebugEnabled())
149         {
150             _log.debug("Checking method " + method.getName() + " for annotations");
151         }
152
153         Annotation JavaDoc[] annotations = method.getAnnotations();
154         for (int j = 0; j < annotations.length; j++)
155         {
156             Annotation JavaDoc annotation = annotations[j];
157
158             if (Service.class.equals(annotation.annotationType()))
159             {
160                 processAnnotatedServiceMethod(
161                         method,
162                         (Service) annotation,
163                         module,
164                         instanceProvider);
165             }
166             else if (Configuration.class.equals(annotation.annotationType()))
167             {
168                 processAnnotatedConfigurationMethod(
169                         method,
170                         (Configuration) annotation,
171                         module,
172                         instanceProvider);
173             }
174             else if (org.apache.hivemind.annotations.definition.Contribution.class.equals(annotation.annotationType()))
175             {
176                 processAnnotatedContributionMethod(
177                         method,
178                         (org.apache.hivemind.annotations.definition.Contribution) annotation,
179                         module,
180                         instanceProvider);
181             }
182             else if (Submodule.class.equals(annotation.annotationType()))
183             {
184                 processAnnotatedSubmoduleMethod(
185                         method,
186                         (Submodule) annotation,
187                         module,
188                         instanceProvider);
189             }
190         }
191
192     }
193     
194     /**
195      * Ensures that an annotated method has only allowed modifiers.
196      * By default Modifier.PUBLIC and Modifier.PROTECTED are allowed.
197      * @param method the method
198      * @param allowedModifiers allowed {@link Modifier modifiers}.
199      * @param methodType used in error messages to describe what the method is used for
200      */

201     protected void checkMethodModifiers(Method JavaDoc method, int allowedModifiers, String JavaDoc methodType)
202     {
203         // These modifiers are allowed
204
final int validModifiers = Modifier.PUBLIC | Modifier.PROTECTED | allowedModifiers;
205         
206         int invalidModifiers = method.getModifiers() & ~validModifiers;
207         if (invalidModifiers > 0) {
208             throw new ApplicationRuntimeException(AnnotationsMessages.annotatedMethodHasInvalidModifiers(method, methodType, invalidModifiers));
209         }
210
211         // TODO: Check for package access
212

213         // Check for setAccessible-Errors when Modifier.PROTECTED is used
214
if (Modifier.isProtected(method.getModifiers())) {
215             // Try to set method accessible
216
try
217             {
218                 method.setAccessible(true);
219             }
220             catch (SecurityException JavaDoc e)
221             {
222                 throw new ApplicationRuntimeException(AnnotationsMessages.annotatedMethodIsProtectedAndNotAccessible(method, methodType));
223             }
224         }
225     }
226
227     private void processAnnotatedServiceMethod(Method JavaDoc method, Service service,
228             ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
229     {
230         checkMethodModifiers(method, 0, "service point");
231         
232         if (_log.isDebugEnabled())
233         {
234             _log.debug("Method " + method.getName() + "classified as service point.");
235         }
236         
237         Location location = new AnnotatedModuleLocation(module.getLocation().getResource(),
238                 method.getDeclaringClass(), method);
239
240         Visibility visibility = Visibility.PUBLIC;
241         if (Modifier.isProtected(method.getModifiers())) {
242             visibility = Visibility.PRIVATE;
243         }
244         ServicePointDefinitionImpl spd = new ServicePointDefinitionImpl(module, service.id(), location,
245                 visibility, method.getReturnType().getName());
246         module.addServicePoint(spd);
247
248         ImplementationConstructor constructor = new MethodCallImplementationConstructor(location,
249                 method, instanceProvider);
250
251         ImplementationDefinition sid = new ImplementationDefinitionImpl(module, location,
252                 constructor, service.serviceModel(), true);
253
254         spd.addImplementation(sid);
255
256     }
257
258     private void processAnnotatedConfigurationMethod(Method JavaDoc method, Configuration configuration, ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
259     {
260         checkMethodModifiers(method, 0, "configuration point");
261
262         if (_log.isDebugEnabled())
263         {
264             _log.debug("Method " + method.getName() + "classified as configuration point.");
265         }
266         
267         Location location = new AnnotatedModuleLocation(module.getLocation().getResource(),
268                 method.getDeclaringClass(), method);
269         
270         Visibility visibility = Visibility.PUBLIC;
271         if (Modifier.isProtected(method.getModifiers())) {
272             visibility = Visibility.PRIVATE;
273         }
274         ConfigurationPointDefinitionImpl cpd = new ConfigurationPointDefinitionImpl(module, configuration.id(),
275                 location, visibility, method.getReturnType().getName(), Occurances.UNBOUNDED);
276         module.addConfigurationPoint(cpd);
277         
278         // Add method implementation as initial contribution
279
Contribution contribution = new MethodCallContributionConstructor(
280                 location, method, instanceProvider);
281         ContributionDefinitionImpl cd = new ContributionDefinitionImpl(module, location, contribution, true);
282         cpd.addContribution(cd);
283     }
284
285     private void processAnnotatedContributionMethod(Method JavaDoc method, org.apache.hivemind.annotations.definition.Contribution contribution, ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
286     {
287         checkMethodModifiers(method, 0, "contribution");
288
289         if (_log.isDebugEnabled())
290         {
291             _log.debug("Method " + method.getName() + "classified as contribution.");
292         }
293         
294         Location location = new AnnotatedModuleLocation(module.getLocation().getResource(),
295                 method.getDeclaringClass(), method);
296         
297         Contribution constructor = new MethodCallContributionConstructor(
298                 location, method, instanceProvider);
299
300         ContributionDefinitionImpl cd = new ContributionDefinitionImpl(module, location, constructor, false);
301         String JavaDoc qualifiedConfigurationId = IdUtils.qualify(
302                 module.getId(),
303                 contribution.configurationId());
304         module.addContribution(qualifiedConfigurationId, cd);
305
306     }
307     
308     /**
309      * Processes a method that is marked as submodule definition.
310      */

311     private void processAnnotatedSubmoduleMethod(Method JavaDoc method, Submodule submodule, ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
312     {
313         checkMethodModifiers(method, 0, "submodule");
314
315         if (_log.isDebugEnabled())
316         {
317             _log.debug("Method " + method.getName() + "classified as submodule.");
318         }
319         
320         String JavaDoc fullModuleId = IdUtils.qualify(
321                 module.getId(),
322                 submodule.id());
323         // TODO: Check if return type is defined
324
AnnotatedModuleProcessor submoduleProcessor = new AnnotatedModuleProcessor(_registryDefinition,
325                 _classResolver, _errorHandler);
326         submoduleProcessor.processModule(method.getReturnType(), fullModuleId);
327     }
328     
329     /**
330      * Creates a location pointing at the module class.
331      */

332     protected Location createModuleLocation(Class JavaDoc moduleClass)
333     {
334         String JavaDoc path = "/" + moduleClass.getName().replace('.', '/');
335
336         Resource r = new ClasspathResource(_classResolver, path);
337
338         return new AnnotatedModuleLocation(r, moduleClass);
339     }
340
341     /**
342      * Determines the module id of the module defined by the annotated class.
343      * First priority has a {@link Module} annotation. If none is defined the
344      * id is determined from class and package name.
345      *
346      * @param moduleClass
347      * the module class
348      * @return the id
349      */

350     private String JavaDoc determineModuleId(Class JavaDoc moduleClass)
351     {
352         Module moduleAnnotation = (Module) moduleClass.getAnnotation(Module.class);
353         if (moduleAnnotation != null) {
354             return moduleAnnotation.id();
355         } else {
356             return getDefaultModuleId(moduleClass);
357         }
358     }
359
360     private String JavaDoc getDefaultModuleId(Class JavaDoc moduleClass)
361     {
362         return moduleClass.getName();
363     }
364 }
365
Popular Tags