View Javadoc

1   /**
2    * - Digitalis Internal Framework v2.0 - (C) 2007, Digitalis Informatica. Distribuicao e Gestao de Informatica, Lda.
3    * Estrada de Paco de Arcos num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999
4    * http://www.digitalis.pt
5    */
6   package pt.digitalis.dif.codegen.util;
7   
8   import java.util.List;
9   import java.util.Map;
10  
11  import pt.digitalis.dif.dem.Entity;
12  import pt.digitalis.dif.dem.annotations.AnnotationTags;
13  import pt.digitalis.dif.dem.config.IDEMRegistrator;
14  import pt.digitalis.dif.utils.logging.DIFLogger;
15  import pt.digitalis.utils.bytecode.holders.AnnotationHolder;
16  import pt.digitalis.utils.bytecode.holders.ClassHolder;
17  import pt.digitalis.utils.common.collections.CaseInsensitiveHashMap;
18  import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
19  
20  /**
21   * A temporary registry of DEM entities that helps the codegen utility to track down all entities on a first pass
22   * 
23   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
24   * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
25   * @created Jul 23, 2007
26   */
27  final public class DEMLoaderEntityRegistry {
28  
29      /** Map of application IDs and their class objects */
30      static private Map<String, ClassHolder> applications = new CaseInsensitiveHashMap<ClassHolder>();
31  
32      /** Map of provider IDs and their class objects */
33      static private Map<String, ClassHolder> providers = new CaseInsensitiveHashMap<ClassHolder>();
34  
35      /** Map of service IDs and their class objects */
36      static private Map<String, ClassHolder> services = new CaseInsensitiveHashMap<ClassHolder>();
37  
38      /** Map of stage IDs and their class objects */
39      static private Map<String, ClassHolder> stages = new CaseInsensitiveHashMap<ClassHolder>();
40  
41      /** Map of validator IDs and their class objects */
42      static private Map<String, ClassHolder> validators = new CaseInsensitiveHashMap<ClassHolder>();
43  
44      /**
45       * Adds a application class to the temp DEM registry
46       * 
47       * @param id
48       *            the ID of the DEM Entity
49       * @param clazz
50       *            the class object that represents the Entity
51       */
52      static public void addApplication(String id, ClassHolder clazz)
53      {
54          applications.put(id.toLowerCase(), clazz);
55      }
56  
57      /**
58       * Adds a provider class to the temp DEM registry
59       * 
60       * @param id
61       *            the ID of the DEM Entity
62       * @param clazz
63       *            the class object that represents the Entity
64       */
65      static public void addProvider(String id, ClassHolder clazz)
66      {
67          providers.put(id.toLowerCase(), clazz);
68      }
69  
70      /**
71       * Adds a service class to the temp DEM registry
72       * 
73       * @param id
74       *            the ID of the DEM Entity
75       * @param clazz
76       *            the class object that represents the Entity
77       */
78      static public void addService(String id, ClassHolder clazz)
79      {
80          services.put(id.toLowerCase(), clazz);
81      }
82  
83      /**
84       * Adds a stage class to the temp DEM registry
85       * 
86       * @param id
87       *            the ID of the DEM Entity
88       * @param clazz
89       *            the class object that represents the Entity
90       */
91      static public void addStage(String id, ClassHolder clazz)
92      {
93          stages.put(id.toLowerCase(), clazz);
94      }
95  
96      /**
97       * Adds a validator class to the temp DEM registry
98       * 
99       * @param id
100      *            the ID of the DEM Entity
101      * @param clazz
102      *            the class object that represents the Entity
103      */
104     static public void addValidator(String id, ClassHolder clazz)
105     {
106         validators.put(id.toLowerCase(), clazz);
107     }
108 
109     /**
110      * Performs memory clean up by releasing the internal Maps of entities when they are no longer needed. Must be
111      * called since this is a static class with static attributes for temporary data.
112      */
113     static public void cleanUp()
114     {
115 
116         // Detach all classes...
117         if (providers != null)
118             for (ClassHolder clazz: providers.values())
119                 clazz.cleanUp();
120 
121         if (applications != null)
122             for (ClassHolder clazz: applications.values())
123                 clazz.cleanUp();
124 
125         if (services != null)
126             for (ClassHolder clazz: services.values())
127                 clazz.cleanUp();
128 
129         if (stages != null)
130             for (ClassHolder clazz: stages.values())
131                 clazz.cleanUp();
132 
133         if (validators != null)
134             for (ClassHolder clazz: validators.values())
135                 clazz.cleanUp();
136 
137         providers = new CaseInsensitiveHashMap<ClassHolder>();
138         applications = new CaseInsensitiveHashMap<ClassHolder>();
139         services = new CaseInsensitiveHashMap<ClassHolder>();
140         stages = new CaseInsensitiveHashMap<ClassHolder>();
141         validators = new CaseInsensitiveHashMap<ClassHolder>();
142     }
143 
144     /**
145      * Searches the applications for the entry with the given ID
146      * 
147      * @param id
148      *            the ID of the Entity to search
149      * @return the class object of the Entity
150      */
151     static public ClassHolder getApplication(String id)
152     {
153         if (applications == null)
154             return null;
155         else
156             return applications.get(id.toLowerCase());
157     }
158 
159     /**
160      * Returns the registered applications count
161      * 
162      * @return the number of Applications
163      */
164     static public int getApplicationCount()
165     {
166         return (applications == null) ? 0 : applications.size();
167     }
168 
169     /**
170      * Returns the Map of registered applications with the ID and their class objects
171      * 
172      * @return the Applications Map
173      */
174     static public Map<String, ClassHolder> getApplications()
175     {
176         return applications;
177     }
178 
179     /**
180      * Returns the total number of entities registered
181      * 
182      * @return the entity count
183      */
184     static public int getEntityCount()
185     {
186 
187         int entityTotal = 0;
188 
189         entityTotal += DEMLoaderEntityRegistry.getProviderCount();
190         entityTotal += DEMLoaderEntityRegistry.getApplicationCount();
191         entityTotal += DEMLoaderEntityRegistry.getServiceCount();
192         entityTotal += DEMLoaderEntityRegistry.getStageCount();
193         entityTotal += DEMLoaderEntityRegistry.getValidatorCount();
194 
195         return entityTotal;
196     }
197 
198     /**
199      * Searches the providers for the entry with the given ID
200      * 
201      * @param id
202      *            the ID of the Entity to search
203      * @return the class object of the Entity
204      */
205     static public ClassHolder getProvider(String id)
206     {
207         if (providers == null)
208             return null;
209         else
210             return providers.get(id.toLowerCase());
211     }
212 
213     /**
214      * Returns the registered providers count
215      * 
216      * @return the number of Providers
217      */
218     static public int getProviderCount()
219     {
220         return (providers == null) ? 0 : providers.size();
221     }
222 
223     /**
224      * Returns the Map of registered providers with the ID and their class objects
225      * 
226      * @return the Providers Map
227      */
228     static public Map<String, ClassHolder> getProviders()
229     {
230         return providers;
231     }
232 
233     /**
234      * Searches the services for the entry with the given ID
235      * 
236      * @param id
237      *            the ID of the Entity to search
238      * @return the class object of the Entity
239      */
240     static public ClassHolder getService(String id)
241     {
242         if (services == null)
243             return null;
244         else
245             return services.get(id.toLowerCase());
246     }
247 
248     /**
249      * Returns the registered services count
250      * 
251      * @return the number of Services
252      */
253     static public int getServiceCount()
254     {
255         return (services == null) ? 0 : services.size();
256     }
257 
258     /**
259      * Returns the Map of registered services with the ID and their class objects
260      * 
261      * @return the Services Map
262      */
263     static public Map<String, ClassHolder> getServices()
264     {
265         return services;
266     }
267 
268     /**
269      * Searches the stages for the entry with the given ID
270      * 
271      * @param id
272      *            the ID of the Entity to search
273      * @return the class object of the Entity
274      */
275     static public ClassHolder getStage(String id)
276     {
277         if (stages == null)
278             return null;
279         else
280             return stages.get(id.toLowerCase());
281     }
282 
283     /**
284      * Returns the registered stages count
285      * 
286      * @return the number of Stages
287      */
288     static public int getStageCount()
289     {
290         return (stages == null) ? 0 : stages.size();
291     }
292 
293     /**
294      * Returns the Map of registered stages with the ID and their class objects
295      * 
296      * @return the Stages Map
297      */
298     static public Map<String, ClassHolder> getStages()
299     {
300         return stages;
301     }
302 
303     /**
304      * Searches the validators for the entry with the given ID
305      * 
306      * @param id
307      *            the ID of the Entity to search
308      * @return the class object of the Entity
309      */
310     static public ClassHolder getValidator(String id)
311     {
312         if (validators == null)
313             return null;
314         else
315             return validators.get(id.toLowerCase());
316     }
317 
318     /**
319      * Returns the registered validators count
320      * 
321      * @return the number if Validators
322      */
323     static public int getValidatorCount()
324     {
325         return (validators == null) ? 0 : validators.size();
326     }
327 
328     /**
329      * Returns the Map of registered validators with the ID and their class objects
330      * 
331      * @return the Validators Map
332      */
333     static public Map<String, ClassHolder> getValidators()
334     {
335         return validators;
336     }
337 
338     /**
339      * Analyzes the given classes to determine witch of them are DEM Entity. It adds them to the corresponding DEM list.
340      * All read operations are executed by Javassist so classes are not loaded by the JVM.
341      * 
342      * @param classes
343      *            the classes to analyze
344      * @param demRegistrator
345      *            the DEM registrator
346      * @throws ResourceNotFoundException
347      *             if any class could not be found or an annotation can't be read
348      * @throws IllegalAccessException
349      * @throws InstantiationException
350      * @throws ClassNotFoundException
351      */
352     static public void loadEntityClasses(List<ClassHolder> classes, IDEMRegistrator demRegistrator)
353             throws ResourceNotFoundException, ClassNotFoundException, InstantiationException, IllegalAccessException
354     {
355 
356         // For all defined classes...
357         for (ClassHolder clazz: classes)
358         {
359             /*
360              * Treat class according the annotation. Implementation Note: The algorithm just considers the first primary
361              * DEM-Entity Annotation Entity found.
362              */
363 
364             // If it's a @ValidationDefinition
365             if (clazz.containsAnnotation(Entity.VALIDATOR.getFullyQualifiedName()))
366             {
367                 if (!demRegistrator.getEntitiesToExclude(Entity.VALIDATOR).contains(
368                         clazz.getFQName()))
369                     processValidator(clazz);
370                 else
371                 {
372                     DIFLogger.getLogger().info(
373                             "The Validator '" + clazz.getClassInstance().getClass().getCanonicalName()
374                                     + "' was excluded from load process");
375                 }
376             }
377             // If it's a @ProviderDefinition
378             else if (clazz.containsAnnotation(Entity.PROVIDER.getFullyQualifiedName()))
379             {
380                 if (!demRegistrator.getEntitiesToExclude(Entity.PROVIDER).contains(
381                         clazz.getFQName()))
382                     processProvider(clazz);
383                 else
384                 {
385                     DIFLogger.getLogger().info(
386                             "The Provider '" + clazz.getClassInstance().getClass().getCanonicalName()
387                                     + "' was excluded from load process");
388                 }
389             }
390 
391             // If it's a @ApplicationDefinition
392             else if (clazz.containsAnnotation(Entity.APPLICATION.getFullyQualifiedName()))
393             {
394                 if (!demRegistrator.getEntitiesToExclude(Entity.APPLICATION).contains(
395                         clazz.getFQName()))
396                     processApplication(clazz);
397                 else
398                 {
399                     DIFLogger.getLogger().info(
400                             "The Application '" + clazz.getClassInstance().getClass().getCanonicalName()
401                                     + "' was excluded from load process");
402                 }
403             }
404 
405             // If it's a @ServiceDefinition
406             else if (clazz.containsAnnotation(Entity.SERVICE.getFullyQualifiedName()))
407             {
408                 if (!demRegistrator.getEntitiesToExclude(Entity.SERVICE).contains(
409                         clazz.getFQName()))
410                     processService(clazz);
411                 else
412                 {
413                     DIFLogger.getLogger().info(
414                             "The Service '" + clazz.getClassInstance().getClass().getCanonicalName()
415                                     + "' was excluded from load process");
416                 }
417             }
418 
419             // If it's a @StageDefinition
420             else if (clazz.containsAnnotation(Entity.STAGE.getFullyQualifiedName()))
421             {
422                 if (!demRegistrator.getEntitiesToExclude(Entity.STAGE).contains(
423                         clazz.getFQName()))
424                     processStage(clazz);
425                 else
426                 {
427                     DIFLogger.getLogger().info(
428                             "The Stage '" + clazz.getClassInstance().getClass().getCanonicalName()
429                                     + "' was excluded from load process");
430                 }
431             }
432         }
433     }
434 
435     /**
436      * Process the <code>@ProviderDefinition</code> annotation, Reads it's member values and
437      * 
438      * @param clazz
439      *            the Provider class
440      * @throws ResourceNotFoundException
441      *             if annotation member values can't be read
442      */
443     static private void processApplication(ClassHolder clazz) throws ResourceNotFoundException
444     {
445 
446         // Add application to DEMLoaderEntityRegistry
447         addApplication(processEntity(clazz, Entity.APPLICATION), clazz);
448     }
449 
450     /**
451      * Process the entity annotation.
452      * 
453      * @param clazz
454      *            the Entity class
455      * @param entity
456      *            the entity to process
457      * @return the processed Entity ID
458      * @throws ResourceNotFoundException
459      *             if annotation member values can't be read
460      */
461     static private String processEntity(ClassHolder clazz, Entity entity) throws ResourceNotFoundException
462     {
463         // Get the Annotation
464         AnnotationHolder entityAnnotation = clazz.getAnnotations().get(entity.getFullyQualifiedName());
465 
466         if (entityAnnotation == null)
467             throw new ResourceNotFoundException("Could not get @" + entity.getName()
468                     + " annotation instance! Unable to proceed...");
469 
470         String entityID = entityAnnotation.getMembers().get("id").toString();
471 
472         if (AnnotationTags.GENERATE_ID.equals(entityID))
473             entityID = clazz.generateID();
474 
475         return entityID;
476     }
477 
478     /**
479      * Process the <code>@ProviderDefinition</code> annotation.
480      * 
481      * @param clazz
482      *            the Provider class
483      * @throws ResourceNotFoundException
484      *             if annotation member values can't be read
485      */
486     static private void processProvider(ClassHolder clazz) throws ResourceNotFoundException
487     {
488 
489         // Add provider to DEMLoaderEntityRegistry
490         addProvider(processEntity(clazz, Entity.PROVIDER), clazz);
491     }
492 
493     /**
494      * Process the <code>@ServiceDefinition</code> annotation.
495      * 
496      * @param clazz
497      *            the Service class
498      * @throws ResourceNotFoundException
499      *             if annotation member values can't be read
500      */
501     static private void processService(ClassHolder clazz) throws ResourceNotFoundException
502     {
503 
504         // Add service to DEMLoaderEntityRegistry
505         addService(processEntity(clazz, Entity.SERVICE), clazz);
506     }
507 
508     /**
509      * Process the <code>@StageDefinition</code> annotation.
510      * 
511      * @param clazz
512      *            the Stage class
513      * @throws ResourceNotFoundException
514      *             if annotation member values can't be read
515      */
516     static private void processStage(ClassHolder clazz) throws ResourceNotFoundException
517     {
518 
519         // Add stage to DEMLoaderEntityRegistry
520         addStage(processEntity(clazz, Entity.STAGE), clazz);
521     }
522 
523     /**
524      * Process the <code>@ValidatorDefinition</code> annotation.
525      * 
526      * @param clazz
527      *            the Validator class
528      * @throws ResourceNotFoundException
529      *             if annotation member values can't be read
530      */
531     static private void processValidator(ClassHolder clazz) throws ResourceNotFoundException
532     {
533 
534         // Add validator to DEMLoaderEntityRegistry
535         addValidator(processEntity(clazz, Entity.VALIDATOR), clazz);
536     }
537 }