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;
7   
8   import java.util.ArrayList;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.Map.Entry;
12  
13  import pt.digitalis.dif.codegen.util.DEMLoaderEntityRegistry;
14  import pt.digitalis.dif.codegen.util.DEMLoaderHelper;
15  import pt.digitalis.dif.codegen.util.IClassEnhancer;
16  import pt.digitalis.dif.dem.DEMRegistryImpl;
17  import pt.digitalis.dif.dem.Entity;
18  import pt.digitalis.dif.dem.annotations.AnnotationMemberTags;
19  import pt.digitalis.dif.dem.annotations.entities.ApplicationDefinition;
20  import pt.digitalis.dif.dem.annotations.entities.ServiceDefinition;
21  import pt.digitalis.dif.dem.annotations.entities.StageDefinition;
22  import pt.digitalis.dif.dem.config.IDEMRegistrator;
23  import pt.digitalis.dif.dem.config.IEntityRegistration;
24  import pt.digitalis.dif.dem.managers.impl.UsageIssuesManagerImpl;
25  import pt.digitalis.dif.dem.objects.issues.IssueScope;
26  import pt.digitalis.dif.dem.objects.issues.IssueType;
27  import pt.digitalis.dif.exception.codegen.AnnotationMisuseException;
28  import pt.digitalis.dif.exception.codegen.DIFCodeGenerationException;
29  import pt.digitalis.dif.ioc.DIFIoCRegistry;
30  import pt.digitalis.dif.utils.logging.DIFLogger;
31  import pt.digitalis.utils.bytecode.exceptions.CodeGenerationException;
32  import pt.digitalis.utils.bytecode.holders.AnnotationHolder;
33  import pt.digitalis.utils.bytecode.holders.ClassHolder;
34  import pt.digitalis.utils.bytecode.holders.HolderRepository;
35  import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
36  
37  import com.google.inject.Inject;
38  
39  /**
40   * The framework's main code generation facility. It is an utility class that is called by the frameworks initialization
41   * procedure
42   * 
43   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
44   * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
45   * @created Jul 23, 2007
46   */
47  public class DIFCodeGenerator {
48  
49      /** The class enhancer */
50      @Inject
51      private IClassEnhancer classEnhancer;
52  
53      /** The package registrator */
54      @Inject
55      private IDEMRegistrator demRegistrator;
56  
57      /**
58       * Performs cleanup operations.
59       */
60      public void cleanUp()
61      {
62          // Perform memory cleanup
63          DEMLoaderEntityRegistry.cleanUp();
64          DEMLoaderHelper.cleanUp();
65          HolderRepository.cleanUp();
66  
67          /*
68           * TODO: After these cleanups, some containers are set to null and not reinitialized again. This might originate
69           * NullPointerExceptions. The unit tests might not run properly. If such a situation arises it will be
70           * appropriated to move these clean-up operations to a separate method that will be called explicitly by the
71           * developer.
72           */
73      }
74  
75      /**
76       * Collects all contributed package registrations in the registry
77       * 
78       * @throws ResourceNotFoundException
79       *             if it can't get no classes to enhancement
80       * @throws CodeGenerationException
81       *             if a class can't be enhanced
82       */
83      public void collectRegisteredPackages() throws ResourceNotFoundException, CodeGenerationException
84      {
85  
86          // Get all contributed implementation of the EntityRegistration class
87          List<IEntityRegistration> entityRegistrators = DIFIoCRegistry.getRegistry().getImplementations(
88                  IEntityRegistration.class);
89  
90          // ...and run them
91          for (IEntityRegistration entityRegistration: entityRegistrators)
92              entityRegistration.registerEntitys(demRegistrator);
93      }
94  
95      /**
96       * Searches all registered packages for DEM entities and performs the Class enhance operations.
97       * 
98       * @throws CodeGenerationException
99       *             if a class can't be enhanced
100      * @throws ResourceNotFoundException
101      *             if it can't get no classes to enhancement
102      * @throws DIFCodeGenerationException
103      */
104     public void enhanceDEMClasses() throws CodeGenerationException, ResourceNotFoundException,
105             DIFCodeGenerationException
106     {
107 
108         List<String> stagesToRemove = new ArrayList<String>();
109         List<String> servicesToRemove = new ArrayList<String>();
110         List<String> applicationsToRemove = new ArrayList<String>();
111 
112         /* Remove from Registry the incoherent entities */
113         for (Entry<String, ClassHolder> entry: DEMLoaderEntityRegistry.getStages().entrySet())
114         {
115             String stageID = entry.getKey();
116             ClassHolder clazz = entry.getValue();
117 
118             AnnotationHolder annotationHolder = clazz.getAnnotations().get(StageDefinition.class.getCanonicalName());
119             String serviceID = annotationHolder.getMembers().get(AnnotationMemberTags.STAGE_DEFINITION_SERVICE)
120                     .toString();
121 
122             if (DEMLoaderEntityRegistry.getServices().containsKey(serviceID))
123             {
124                 clazz = DEMLoaderEntityRegistry.getServices().get(serviceID);
125 
126                 annotationHolder = clazz.getAnnotations().get(ServiceDefinition.class.getCanonicalName());
127                 String applicationID = annotationHolder.getMembers()
128                         .get(AnnotationMemberTags.SERVICE_DEFINITION_APPLICATION).toString();
129 
130                 if (DEMLoaderEntityRegistry.getApplications().containsKey(applicationID))
131                 {
132                     clazz = DEMLoaderEntityRegistry.getApplications().get(applicationID);
133 
134                     annotationHolder = clazz.getAnnotations().get(ApplicationDefinition.class.getCanonicalName());
135                     String providerID = annotationHolder.getMembers()
136                             .get(AnnotationMemberTags.APPLICATION_DEFINITION_PROVIDER).toString();
137 
138                     if (!DEMLoaderEntityRegistry.getProviders().containsKey(providerID))
139                     {
140                         applicationsToRemove.add(applicationID);
141                         servicesToRemove.add(serviceID);
142                         stagesToRemove.add(stageID);
143                     }
144                 }
145                 else
146                 {
147                     servicesToRemove.add(serviceID);
148                     stagesToRemove.add(stageID);
149                 }
150             }
151             else
152             {
153                 stagesToRemove.add(stageID);
154             }
155         }
156 
157         for (String applicationId: applicationsToRemove)
158         {
159             DEMLoaderEntityRegistry.getServices().remove(applicationId);
160             DIFLogger.getLogger().info(
161                     "The application '" + applicationId + "' has been excluded due to the lack of suitable provider");
162         }
163 
164         for (String serviceId: servicesToRemove)
165         {
166             DEMLoaderEntityRegistry.getServices().remove(serviceId);
167             DIFLogger.getLogger().info(
168                     "The service '" + serviceId + "' has been excluded due to the lack of suitable application");
169         }
170 
171         for (String stageId: stagesToRemove)
172         {
173             DEMLoaderEntityRegistry.getStages().remove(stageId);
174             DIFLogger.getLogger().info(
175                     "The stage '" + stageId + "' has been excluded due to the lack of suitable service");
176         }
177 
178         /*
179          * Enhance each entity class. Note that the enhancement order is relevant and respects the DEM hierarchy. Each
180          * class is also added to the respective slot in the DEMRegistry
181          */
182 
183         enhanceEntities(Entity.VALIDATOR, DEMLoaderEntityRegistry.getValidators());
184         enhanceEntities(Entity.PROVIDER, DEMLoaderEntityRegistry.getProviders());
185         enhanceEntities(Entity.APPLICATION, DEMLoaderEntityRegistry.getApplications());
186         enhanceEntities(Entity.SERVICE, DEMLoaderEntityRegistry.getServices());
187         enhanceEntities(Entity.STAGE, DEMLoaderEntityRegistry.getStages());
188 
189     }
190 
191     /**
192      * Performs the bytecode enhancement to the given entity classes
193      * 
194      * @param entityType
195      *            the entity type
196      * @param entityMap
197      *            the map of entities to add
198      * @throws CodeGenerationException
199      *             if a class can't be enhanced
200      * @throws ResourceNotFoundException
201      *             if it can't get no classes to enhancement
202      * @throws DIFCodeGenerationException
203      */
204     private void enhanceEntities(Entity entityType, Map<String, ClassHolder> entityMap) throws CodeGenerationException,
205             ResourceNotFoundException, DIFCodeGenerationException
206     {
207 
208         ClassHolder entityClazz;
209 
210         if (entityMap != null)
211             for (ClassHolder clazz: entityMap.values())
212             {
213                 try
214                 {
215 
216                     entityClazz = classEnhancer.enhance(clazz);
217 
218                     if (!entityType.equals(Entity.VALIDATOR))
219                     {
220                         DEMRegistryImpl.addEntity(entityType, entityClazz);
221                     }
222 
223                 }
224                 catch (AnnotationMisuseException annotationMisuseException)
225                 {
226                     UsageIssuesManagerImpl.getInstance().addIssue(
227                             IssueType.ERROR,
228                             IssueScope.LOADTIME,
229                             annotationMisuseException.getExceptionContext()
230                                     .get(AnnotationMisuseException.ContextKeys.CLASS).toString(),
231                             annotationMisuseException.getMessage(), annotationMisuseException);
232                 }
233             }
234     }
235 
236     /**
237      * Searches all registered packages for DEM entities and other DIF elements.
238      * 
239      * @throws ResourceNotFoundException
240      *             if it can't get no classes to enhancement
241      * @throws CodeGenerationException
242      *             if a class can't be enhanced
243      */
244     public void searchRegisteredPackages() throws ResourceNotFoundException, CodeGenerationException
245     {
246 
247         /*
248          * Iterate through the DEM-registered folders for annotated classes and separate them by their corresponding
249          * entity types in the DEM load time registry
250          */
251         for (String packageName: DEMLoaderHelper.getPackageList())
252         {
253 
254             // Get all classes in this folder
255             List<ClassHolder> classes = new ArrayList<ClassHolder>();
256 
257             try
258             {
259                 classes = DEMLoaderHelper.getDEMEntityClassesInPackage(packageName);
260 
261             }
262             catch (ResourceNotFoundException resourceNotFoundException)
263             {
264                 throw new ResourceNotFoundException("Could not find any classes for enhancement in package "
265                         + packageName, resourceNotFoundException);
266             }
267 
268             // Load the classes which are entities
269             try
270             {
271                 DEMLoaderEntityRegistry.loadEntityClasses(classes, demRegistrator);
272             }
273             catch (ClassNotFoundException e)
274             {
275                 throw new CodeGenerationException(e);
276             }
277             catch (InstantiationException e)
278             {
279                 throw new CodeGenerationException(e);
280             }
281             catch (IllegalAccessException e)
282             {
283                 throw new CodeGenerationException(e);
284             }
285         }
286     }
287 }