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.dem;
7   
8   import java.lang.reflect.Constructor;
9   import java.lang.reflect.InvocationTargetException;
10  import java.net.URL;
11  import java.util.ArrayList;
12  import java.util.HashMap;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.Set;
16  
17  import javassist.bytecode.annotation.MemberValue;
18  
19  import org.apache.commons.lang.StringUtils;
20  
21  import pt.digitalis.dif.codegen.CGAncillaries;
22  import pt.digitalis.dif.codegen.util.ClassEnhancementContext;
23  import pt.digitalis.dif.codegen.util.DEMLoaderEntityRegistry;
24  import pt.digitalis.dif.codegen.util.DEMLoaderHelper;
25  import pt.digitalis.dif.codegen.util.EntityUtils;
26  import pt.digitalis.dif.controller.security.managers.IAuthorizationManager;
27  import pt.digitalis.dif.dem.annotations.AnnotationMemberTags;
28  import pt.digitalis.dif.dem.annotations.AnnotationTags;
29  import pt.digitalis.dif.dem.annotations.Application;
30  import pt.digitalis.dif.dem.annotations.Provider;
31  import pt.digitalis.dif.dem.annotations.ProviderList;
32  import pt.digitalis.dif.dem.annotations.Service;
33  import pt.digitalis.dif.dem.annotations.entities.ApplicationDefinition;
34  import pt.digitalis.dif.dem.annotations.entities.ProviderDefinition;
35  import pt.digitalis.dif.dem.annotations.entities.ServiceDefinition;
36  import pt.digitalis.dif.dem.annotations.entities.StageDefinition;
37  import pt.digitalis.dif.dem.annotations.entities.ValidatorDefinition;
38  import pt.digitalis.dif.dem.annotations.metaannotations.MetaAnnotationMemberTags;
39  import pt.digitalis.dif.dem.annotations.metaannotations.Primary;
40  import pt.digitalis.dif.dem.annotations.parameter.AddDocumentToRepository;
41  import pt.digitalis.dif.dem.annotations.parameter.CustomParameters;
42  import pt.digitalis.dif.dem.annotations.parameter.FormConfigurable;
43  import pt.digitalis.dif.dem.annotations.parameter.InjectParameter;
44  import pt.digitalis.dif.dem.annotations.parameter.InjectParameterErrors;
45  import pt.digitalis.dif.dem.annotations.parameter.InjectParameters;
46  import pt.digitalis.dif.dem.annotations.parameter.Parameter;
47  import pt.digitalis.dif.dem.annotations.parameter.Persist;
48  import pt.digitalis.dif.dem.annotations.security.AccessControl;
49  import pt.digitalis.dif.dem.annotations.stage.Callback;
50  import pt.digitalis.dif.dem.annotations.stage.Context;
51  import pt.digitalis.dif.dem.annotations.stage.ErrorStage;
52  import pt.digitalis.dif.dem.annotations.stage.ErrorView;
53  import pt.digitalis.dif.dem.annotations.stage.Execute;
54  import pt.digitalis.dif.dem.annotations.stage.Finalize;
55  import pt.digitalis.dif.dem.annotations.stage.Init;
56  import pt.digitalis.dif.dem.annotations.stage.InjectMessages;
57  import pt.digitalis.dif.dem.annotations.stage.Stage;
58  import pt.digitalis.dif.dem.annotations.stage.View;
59  import pt.digitalis.dif.dem.annotations.stage.controller.DispatcherMode;
60  import pt.digitalis.dif.dem.annotations.stage.controller.InjectAuthenticationError;
61  import pt.digitalis.dif.dem.interfaces.IApplication;
62  import pt.digitalis.dif.dem.interfaces.IProvider;
63  import pt.digitalis.dif.dem.managers.IDEMManager;
64  import pt.digitalis.dif.dem.managers.IMessageManager;
65  import pt.digitalis.dif.dem.managers.IParameterManager;
66  import pt.digitalis.dif.dem.managers.impl.UsageIssuesManagerImpl;
67  import pt.digitalis.dif.dem.objects.ViewType;
68  import pt.digitalis.dif.dem.objects.issues.IssueScope;
69  import pt.digitalis.dif.dem.objects.issues.IssueType;
70  import pt.digitalis.dif.dem.objects.messages.MessageList;
71  import pt.digitalis.dif.dem.objects.parameters.IParameter;
72  import pt.digitalis.dif.dem.objects.parameters.IParameters;
73  import pt.digitalis.dif.dem.objects.parameters.ParameterScope;
74  import pt.digitalis.dif.exception.codegen.AnnotationMisuseException;
75  import pt.digitalis.dif.exception.codegen.DIFCodeGenerationException;
76  import pt.digitalis.dif.exception.codegen.IllegalAnnotationUsage;
77  import pt.digitalis.dif.exception.codegen.IncompatiblePrimaryAnnotationsException;
78  import pt.digitalis.dif.ioc.DIFIoCRegistry;
79  import pt.digitalis.dif.startup.DIFStartupConfiguration;
80  import pt.digitalis.dif.utils.extensions.document.DocumentRepositoryEntry;
81  import pt.digitalis.log.LogLevel;
82  import pt.digitalis.utils.CodeGenUtils;
83  import pt.digitalis.utils.bytecode.holders.AnnotationHolder;
84  import pt.digitalis.utils.bytecode.holders.AnnotationMemberValueHolder;
85  import pt.digitalis.utils.bytecode.holders.AttributeHolder;
86  import pt.digitalis.utils.bytecode.holders.ClassHolder;
87  import pt.digitalis.utils.bytecode.holders.MethodHolder;
88  import pt.digitalis.utils.inspection.exception.AuxiliaryOperationException;
89  import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
90  
91  import com.google.inject.Inject;
92  
93  /**
94   * Defines validation and enrichment logic for an annotationName or family of annotations. A set of methods validate
95   * general rules for any annotationName. Specific methods that can be overrided on sub-classes allow fine-grained
96   * validation rules. Methods that define the source code used on the code generation are also part of this class. TODO:
97   * Some logic that read the annotation values for processing is repeated here and in the ClassEnhancerImpl. Should be
98   * refactored for a single read operation. Maybe in 2.1 TODO: Making the xHolder classes inherit from a parent would
99   * eliminate the need of several similar methods with just different parameter types (as in validate() and
100  * validatePrimary()).
101  * 
102  * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
103  * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
104  * @author João Galaio <a href="mailto:jgalaio@digitalis.pt">jgalaio@digitalis.pt</a>
105  * @created Aug 29, 2007
106  */
107 public class DEMAnnotationLogic {
108 
109     /** The 'application' attribute name. */
110     final static protected String APPLICATION_ATTRIBUTE_NAME = "application";
111 
112     /** The authorization manager instance */
113     static private IAuthorizationManager authorizationManager;
114 
115     /** The the default DEM Annotation Logic class. */
116     final static public String DEFAULT_DEM_ANNOTATION_LOGIC_CLASS = DEMAnnotationLogic.class.getSimpleName();
117 
118     /** List of invalid characters for entity names/id's */
119     static private final String ENTITY_NAME_BAD_CHARS = "\"\'?&";
120 
121     /** The 'provider' attribute name. */
122     final static protected String PROVIDER_ATTRIBUTE_NAME = "provider";
123 
124     /** The 'service' attribute name. */
125     final static protected String SERVICE_ATTRIBUTE_NAME = "service";
126 
127     /** The 'target' attribute name. */
128     final static protected String TARGET_ATTRIBUTE_NAME = "target";
129 
130     /**
131      * Factory method for DEMAnnotationLogic objects. Gets the name of a DEMAnnotationLogic subtype and generates the
132      * appropriate object. Encapsulates the complex code used to create the objects by reflection. This method's client
133      * is the <code>pt.digitalis.dif.codegen.util.DEMLoaderHelper#getAnnotationLogicMap()</code> which generates a map
134      * whose values are DEMAnnotationLogic subclasses. These values can't be inserted on the map if they belong to a
135      * runtime determined type.
136      * 
137      * @param annotationLogicClassName
138      *            The name of the annotationName logic class
139      * @param annotationClass
140      *            The argument annotationName
141      * @return a new DEMAnnotationLogic instance of the appropriate subclass
142      * @throws ResourceNotFoundException
143      *             if any needed class cannot be found
144      * @throws AuxiliaryOperationException
145      *             if any illegal operation or instantiation exceptions are raised
146      */
147     static public DEMAnnotationLogic makeObject(String annotationLogicClassName, ClassHolder annotationClass)
148             throws ResourceNotFoundException, AuxiliaryOperationException
149     {
150 
151         String annotationClassName = annotationClass.getName();
152         boolean isPrimary = annotationClass.containsAnnotation(Primary.class.getCanonicalName());
153 
154         DEMAnnotationLogic annotationLogicClassObject = null;
155 
156         if (annotationLogicClassName.equals(DEMAnnotationLogic.DEFAULT_DEM_ANNOTATION_LOGIC_CLASS))
157             annotationLogicClassObject = new DEMAnnotationLogic(annotationClass.getFQName(), annotationClassName,
158                     isPrimary);
159 
160         else
161         {
162 
163             // TODO: All this should be in the inspection utils utility classes.
164             // Move it there.
165 
166             Class<?> annotationLogicClass = null;
167 
168             try
169             {
170                 // Create an instance of the logic class
171                 annotationLogicClass = Class.forName(annotationLogicClassName);
172 
173             }
174             catch (ClassNotFoundException classNotFoundException)
175             {
176                 throw new ResourceNotFoundException("Could not create class " + annotationLogicClassName
177                         + " (Does such type exists?)", classNotFoundException);
178             }
179 
180             // Convert to subclass (NOTE: any class is a subclass of itself)
181             Class<? extends DEMAnnotationLogic> annotationLogicClassAsSubclass = annotationLogicClass
182                     .asSubclass(DEMAnnotationLogic.class);
183 
184             // DIFInitializer ctor holder
185             Constructor<? extends DEMAnnotationLogic> constructor;
186             try
187             {
188                 // Get the constructor with the appropriate number of args
189                 constructor = annotationLogicClassAsSubclass.getConstructor(String.class, String.class, boolean.class);
190 
191             }
192             catch (NoSuchMethodException noSuchMethodException)
193             {
194                 throw new ResourceNotFoundException("Could not found an appropriate constructor for "
195                         + annotationLogicClassAsSubclass.getCanonicalName() + " (Wrong number or type of args?)",
196                         noSuchMethodException);
197             }
198 
199             try
200             {
201                 // Create object of the exact type
202                 annotationLogicClassObject = constructor.newInstance(annotationClass.getFQName(), annotationClassName,
203                         isPrimary);
204 
205             }
206             catch (IllegalArgumentException illegalArgumentException)
207             {
208                 throw new AuxiliaryOperationException("Could not create "
209                         + annotationLogicClassAsSubclass.getCanonicalName() + " object! (Illegal argument?)",
210                         illegalArgumentException);
211             }
212             catch (InstantiationException instantiationException)
213             {
214                 throw new AuxiliaryOperationException(
215                         "Could not create " + annotationLogicClassAsSubclass.getCanonicalName()
216                                 + " object! (Interface or abstract class?)", instantiationException);
217             }
218             catch (IllegalAccessException illegalAccessException)
219             {
220                 throw new AuxiliaryOperationException("Could not create "
221                         + annotationLogicClassAsSubclass.getCanonicalName() + " object! (Non-public constructor?)",
222                         illegalAccessException);
223             }
224             catch (InvocationTargetException invocationTargetException)
225             {
226                 throw new AuxiliaryOperationException(
227                         "Could not create " + annotationLogicClassAsSubclass.getCanonicalName()
228                                 + " object! (Previously thrown exception?)", invocationTargetException);
229             }
230         }
231 
232         // Return result
233         return annotationLogicClassObject;
234     }
235 
236     /** The canonical annotation name to validate. */
237     private final String annotationFQName;
238 
239     /** The annotation name to validate. */
240     private String annotationName;
241 
242     /** DEM primary annotationName flag. */
243     private final boolean primary;
244 
245     /**
246      * Constructor.
247      * 
248      * @param annotationFQName
249      *            the annotation fully qualified name
250      * @param annotationName
251      *            the annotation simple name
252      * @param isPrimary
253      *            T if annotation is primary, F otherwise
254      */
255     public DEMAnnotationLogic(String annotationFQName, String annotationName, boolean isPrimary)
256     {
257         this.annotationFQName = annotationFQName;
258         this.annotationName = annotationName;
259         this.primary = isPrimary;
260     }
261 
262     /**
263      * This method will define the code to enhance the classes based on the annotations. It will create the appropriate
264      * methods and their code and add them to the classEnhancement object.
265      * 
266      * @param classEnhancementContext
267      *            the class enhancement context
268      * @param annotation
269      *            the annotation used to define the source code needed for enhancement
270      * @throws ResourceNotFoundException
271      *             if annotation members can't be accessed
272      * @throws DIFCodeGenerationException
273      */
274     public void addSourceCodeForAnnotation(AnnotationHolder annotation, ClassEnhancementContext classEnhancementContext)
275             throws ResourceNotFoundException, DIFCodeGenerationException
276     {
277         try
278         {
279             // Get the class holder
280             ClassHolder clazz = classEnhancementContext.getOriginalClassObject();
281 
282             // Get member values
283             Map<String, AnnotationMemberValueHolder> memberValues = annotation.getMembers();
284 
285             // Get annotation type name
286             String annotationName = annotation.getName();
287 
288             // Prepare source for annotations...
289             if (annotationName.equals(ProviderDefinition.class.getCanonicalName()))
290             {
291                 // Get annotation member values
292                 String id = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_ID).toString();
293                 boolean defaultProvider = memberValues.get(AnnotationMemberTags.PROVIDER_DEFINITION_DEFAULT_PROVIDER)
294                         .toBoolean();
295 
296                 // Check if id generation is needed...
297                 if (AnnotationTags.GENERATE_ID.equals(id))
298                     id = CodeGenUtils.generateID(clazz.getName());
299 
300                 // Add source to class enhancement context
301                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ID_METHOD, "{return \"" + id.toString()
302                         + "\";}");
303 
304                 // Get annotation member values for name
305                 String name = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_NAME).toString();
306                 // Add source to class enhancement context
307                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_NAME_METHOD,
308                         "{return \"" + name.toString() + "\";}");
309                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ORIGINALCLASSNAME_METHOD, "{return \""
310                         + clazz.getFQName() + "\";}");
311 
312                 if (!StringUtils.containsNone(id, ENTITY_NAME_BAD_CHARS.toCharArray()))
313                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
314                             classEnhancementContext.getOriginalClassObject().getFQName(),
315                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity id's", null);
316                 if (!StringUtils.containsNone(name, ENTITY_NAME_BAD_CHARS.toCharArray()))
317                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
318                             classEnhancementContext.getOriginalClassObject().getFQName(),
319                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity names", null);
320 
321                 if (defaultProvider)
322                     DEMRegistryImpl.setDefaultProvider(id);
323 
324             }
325             else if (annotationName.equals(ApplicationDefinition.class.getCanonicalName()))
326             {
327                 // Get annotation member values for id
328                 String id = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_ID).toString();
329 
330                 // Check if id generation is needed...
331                 if (AnnotationTags.GENERATE_ID.equals(id))
332                     id = CodeGenUtils.generateID(clazz.getName());
333 
334                 // Add source to class enhancement context
335                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ID_METHOD, "{return \"" + id.toString()
336                         + "\";}");
337 
338                 // Get annotation member values for name
339                 String name = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_NAME).toString();
340 
341                 if (!StringUtils.containsNone(id, ENTITY_NAME_BAD_CHARS.toCharArray()))
342                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
343                             classEnhancementContext.getOriginalClassObject().getFQName(),
344                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity id's", null);
345                 if (!StringUtils.containsNone(name, ENTITY_NAME_BAD_CHARS.toCharArray()))
346                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
347                             classEnhancementContext.getOriginalClassObject().getFQName(),
348                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity names", null);
349 
350                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_NAME_METHOD,
351                         "{return \"" + name.toString() + "\";}");
352                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ORIGINALCLASSNAME_METHOD, "{return \""
353                         + clazz.getFQName() + "\";}");
354 
355                 // Get annotation member values for provider
356                 String provider = memberValues.get(AnnotationMemberTags.APPLICATION_DEFINITION_PROVIDER).toString();
357 
358                 // Check if it's the default provider and proceed accordingly
359                 if (AnnotationTags.DEFAULT_PROVIDER.equals(provider))
360                     classEnhancementContext.addEnhancement(CGAncillaries.APPLICATION_GET_PROVIDER_METHOD,
361                             "{return getTemplateResources().getDEMManager().getDefaultProvider();}");
362                 else
363                     classEnhancementContext.addEnhancement(CGAncillaries.APPLICATION_GET_PROVIDER_METHOD,
364                             "{return getTemplateResources().getDEMManager().getProvider(\"" + provider + "\");}");
365 
366                 // Add default access. If access control exists it will be processed
367                 // later on
368                 if (!clazz.containsAnnotation(AccessControl.class.getCanonicalName()))
369                     getAuthorizationManager().grantDefaultPublicAccess(Entity.APPLICATION, id);
370 
371             }
372             else if (annotationName.equals(ServiceDefinition.class.getCanonicalName()))
373             {
374 
375                 // Get annotation member values for id
376                 String id = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_ID).toString();
377 
378                 // Check if id generation is needed...
379                 if (AnnotationTags.GENERATE_ID.equals(id))
380                     id = CodeGenUtils.generateID(clazz.getName());
381 
382                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ID_METHOD, "{return \"" + id.toString()
383                         + "\";}");
384 
385                 // Get annotation member values for name
386                 String name = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_NAME).toString();
387                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_NAME_METHOD,
388                         "{return \"" + name.toString() + "\";}");
389                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ORIGINALCLASSNAME_METHOD, "{return \""
390                         + clazz.getFQName() + "\";}");
391 
392                 // Get annotation member values for application
393                 String application = memberValues.get(AnnotationMemberTags.SERVICE_DEFINITION_APPLICATION).toString();
394 
395                 classEnhancementContext.addEnhancement(CGAncillaries.SERVICE_GET_APPLICATION_METHOD,
396                         "{return getTemplateResources().getDEMManager().getApplication(\"" + application + "\");}");
397 
398                 if (!StringUtils.containsNone(id, ENTITY_NAME_BAD_CHARS.toCharArray()))
399                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
400                             classEnhancementContext.getOriginalClassObject().getFQName(),
401                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity id's", null);
402                 if (!StringUtils.containsNone(name, ENTITY_NAME_BAD_CHARS.toCharArray()))
403                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
404                             classEnhancementContext.getOriginalClassObject().getFQName(),
405                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity names", null);
406 
407                 // Add default access. If access control exists it will be processed
408                 // later on
409                 if (!clazz.containsAnnotation(AccessControl.class.getCanonicalName()))
410                     getAuthorizationManager().grantDefaultPublicAccess(Entity.SERVICE, id);
411 
412             }
413             else if (annotationName.equals(StageDefinition.class.getCanonicalName()))
414             {
415 
416                 // Get annotation member values for id and override stage
417                 String id = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_ID).toString();
418                 String override = memberValues.get(AnnotationMemberTags.STAGE_OVERRIDE_DEFAULT).toString();
419 
420                 // Check if id generation is needed...
421                 if (AnnotationTags.GENERATE_ID.equals(id))
422                     id = CodeGenUtils.generateID(clazz.getName());
423                 else
424                     id = id.toLowerCase();
425 
426                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ID_METHOD, "{return \"" + id + "\";}");
427 
428                 if (!AnnotationTags.NONE.equals(override))
429                     classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_OVERRIDE_METHOD, "{return \""
430                             + override + "\";}");
431 
432                 // Get annotation member values for name
433                 String name = memberValues.get(AnnotationMemberTags.ENTITY_DEFINITION_NAME).toString();
434                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_NAME_METHOD,
435                         "{return \"" + name.toString() + "\";}");
436                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ORIGINALCLASSNAME_METHOD, "{return \""
437                         + clazz.getFQName() + "\";}");
438                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_STAGEINSTANCECLASSNAME_METHOD,
439                         "{return \"" + clazz.getFQName() + CGAncillaries.STAGE_INSTANCE_ID + "\";}");
440 
441                 // Get annotation member values for service
442                 String service = memberValues.get(AnnotationMemberTags.STAGE_DEFINITION_SERVICE).toString();
443 
444                 if (!StringUtils.containsNone(id, ENTITY_NAME_BAD_CHARS.toCharArray()))
445                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
446                             classEnhancementContext.getOriginalClassObject().getFQName(),
447                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity id's", null);
448                 if (!StringUtils.containsNone(name, ENTITY_NAME_BAD_CHARS.toCharArray()))
449                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
450                             classEnhancementContext.getOriginalClassObject().getFQName(),
451                             "Cannot use any of \"" + ENTITY_NAME_BAD_CHARS + "\" for entity names", null);
452 
453                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_GET_SERVICE_METHOD,
454                         "{return getTemplateResources().getDEMManager().getService(\"" + service + "\");}");
455 
456                 // Add default access. If access control exists it will be processed
457                 // later on
458                 if (!clazz.containsAnnotation(AccessControl.class.getCanonicalName()))
459                     getAuthorizationManager().grantDefaultPublicAccess(Entity.STAGE, id);
460 
461             }
462             else if (annotationName.equals(ValidatorDefinition.class.getCanonicalName()))
463             {
464 
465                 // TODO: Create Unit tests for this annotation when the ValidatorManager is implemented
466 
467                 String validatorID = annotation.getMembers().get(AnnotationMemberTags.ENTITY_DEFINITION_ID).toString();
468 
469                 // Implementing IValidator interface methods
470                 classEnhancementContext.addEnhancement(CGAncillaries.ENTITY_GET_ID_METHOD, "{return \"" + validatorID
471                         + "\";}");
472 
473                 // TODO: This validatorManager does not exist. Determine what this
474                 // implementation should be.
475                 classEnhancementContext.addEnhancement(CGAncillaries.VALIDATOR_GET_BOUND_PARAMETER_IDS_METHOD,
476                         "{return getTemplateResources().getValidatorManager().getBoundParameters(\"" + validatorID
477                                 + "\");}");
478 
479                 // Throw UnsupportedOpertationException to comply with Java
480                 // standards and warn user of unimplemented
481                 // feature.
482                 throw new UnsupportedOperationException(annotationName
483                         + " not yet supported! Please remove it from class " + clazz.getFQName());
484             }
485 
486             else if (annotationName.equals(Callback.class.getCanonicalName()))
487             {
488 
489                 CallbackType callbackType;
490 
491                 // Get Callback type
492                 AnnotationMemberValueHolder memberValue = memberValues.get(AnnotationMemberTags.ANNOTATION_VALUE);
493 
494                 if (memberValue.getManagedAnnotationValue() == null)
495                     callbackType = CallbackType.SIMPLE;
496                 else
497                     callbackType = CallbackType.getCallbackTypeByName(memberValue.enumValuetoString());
498 
499                 // If callback type is OFF the code is the same copied from the
500                 // template
501                 if (!callbackType.equals(CallbackType.OFF))
502                 {
503                     classEnhancementContext.addEnhancement(CGAncillaries.CALLBACK_GET_CALLBACK_TYPE_METHOD,
504                             "{return getTemplateResources().getCallBack(\"" + callbackType + "\");}");
505 
506                     classEnhancementContext.addEnhancement(CGAncillaries.CALLBACK_HAS_CALLBACK_ENABLED_METHOD,
507                             "{return true;}");
508                 }
509 
510             }
511             else if (annotationName.equals(ErrorStage.class.getCanonicalName()))
512             {
513                 addStage(annotation, classEnhancementContext, true, true, null);
514             }
515             else if (annotationName.equals(View.class.getCanonicalName()))
516             {
517                 addView(annotation, classEnhancementContext, false, true, null);
518             }
519             else if (annotationName.equals(ErrorView.class.getCanonicalName()))
520             {
521                 addView(annotation, classEnhancementContext, true, true, null);
522             }
523             else if (annotationName.equals(DispatcherMode.class.getCanonicalName()))
524             {
525 
526                 /*
527                  * Implementation Note: This annotation treatment is done if the members evaluate to false!
528                  */
529 
530                 if (annotation.getMembers().containsKey(AnnotationMemberTags.DISPATCHER_MODE_AUTHENTICATE)
531                         && !annotation.getMembers().get(AnnotationMemberTags.DISPATCHER_MODE_AUTHENTICATE).toBoolean())
532                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_HAS_AUTHENTICATION, "{return false;}");
533 
534                 if (annotation.getMembers().containsKey(AnnotationMemberTags.DISPATCHER_MODE_AUTHORIZE)
535                         && !annotation.getMembers().get(AnnotationMemberTags.DISPATCHER_MODE_AUTHORIZE).toBoolean())
536                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_HAS_AUTHORIZATION, "{return false;}");
537             }
538         }
539         catch (ResourceNotFoundException e)
540         {
541             // Rethrow for outer handling
542             throw e;
543         }
544         catch (Exception e)
545         {
546             DIFCodeGenerationException codeGenException;
547 
548             if (e instanceof DIFCodeGenerationException)
549             {
550                 codeGenException = (DIFCodeGenerationException) e;
551             }
552             else
553             {
554 
555                 codeGenException = new DIFCodeGenerationException(e);
556                 codeGenException.addToExceptionContext("Original Class Name", classEnhancementContext
557                         .getOriginalClassObject().getFQName());
558             }
559 
560             codeGenException.addToExceptionContext("Annotation", annotation.getName());
561 
562             throw codeGenException;
563         }
564     }
565 
566     /**
567      * This method will define the code to enhance the attributes based on the annotations. It will create the
568      * appropriate methods and their code and add them to the classEnhancement object.
569      * 
570      * @param classEnhancementContext
571      *            the class enhancement context
572      * @param annotation
573      *            the annotation used to define the source code needed for enhancement
574      * @param attribute
575      *            the attribute to be enhanced (to make the context available to the source building process)
576      * @throws ResourceNotFoundException
577      *             if annotation members can't be accessed
578      * @throws DIFCodeGenerationException
579      */
580     public void addSourceCodeForAnnotation(ClassEnhancementContext classEnhancementContext,
581             AnnotationHolder annotation, AttributeHolder attribute) throws ResourceNotFoundException,
582             DIFCodeGenerationException
583     {
584         try
585         {
586             // Get the attribute name
587             String attributeName = attribute.getName();
588 
589             // Get annotation type name
590             String annotationName = annotation.getName();
591 
592             // Get member values
593             Map<String, AnnotationMemberValueHolder> memberValues = annotation.getMembers();
594 
595             if (annotationName.equals(Context.class.getCanonicalName()))
596             {
597                 // DIFContext is the 1st argument of
598                 // EntityCGTemplate.DIF_INIT_METHOD_NAME
599                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
600                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, "this." + attributeName
601                                 + "=this.getContext();");
602 
603             }
604             else if (annotationName.equals(InjectMessages.class.getCanonicalName()))
605             {
606                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
607                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, "this." + attributeName
608                                 + "=this.getMessages();");
609             }
610             else if (annotationName.equals(Stage.class.getCanonicalName()))
611             {
612                 addStage(annotation, classEnhancementContext, false, false, attributeName);
613             }
614             else if (annotationName.equals(ErrorStage.class.getCanonicalName()))
615             {
616                 addStage(annotation, classEnhancementContext, true, false, attributeName);
617             }
618             else if (annotationName.equals(View.class.getCanonicalName()))
619             {
620                 addView(annotation, classEnhancementContext, false, annotation.getMembers().get("defaultView")
621                         .toBoolean(), attributeName);
622             }
623             else if (annotationName.equals(ErrorView.class.getCanonicalName()))
624             {
625                 addView(annotation, classEnhancementContext, true, false, attributeName);
626             }
627             else if (annotationName.equals(Provider.class.getCanonicalName()))
628             {
629                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
630                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName
631                                 + "=getService().getApplication().getProvider();");
632             }
633             else if (annotationName.equals(Application.class.getCanonicalName()))
634             {
635                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
636                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName
637                                 + "=getService().getApplication();");
638             }
639             else if (annotationName.equals(Service.class.getCanonicalName()))
640             {
641                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
642                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName + "=getService();");
643 
644                 // The following section implements the following annotations:
645                 // Parameter, Persist, Validator
646             }
647             else if (annotationName.equals(Parameter.class.getCanonicalName()))
648             {
649                 // Fetch id
650                 String id = memberValues.get(AnnotationMemberTags.PARAMETER_ID).toString();
651 
652                 // No id given, use the attribute name to lower case
653                 if (id.equals(AnnotationTags.GENERATE_ID))
654                     id = attribute.getName().toLowerCase();
655 
656                 // Get the ID and the type of the parent...
657                 String parentID = EntityUtils.getEntityID(attribute.getParentClass());
658                 Entity parentType = EntityUtils.getEntityType(attribute.getParentClass());
659 
660                 IParameterManager parameterManager = DIFIoCRegistry.getRegistry().getImplementation(
661                         IParameterManager.class);
662 
663                 IParameter<?> param = parameterManager.getParameter(parentType, parentID, id);
664 
665                 if (param == null)
666                 {
667                     // Parameter was erronious. Report it.
668                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME, parentID,
669                             "Bad parameter: \"" + id + "\"", null);
670                 }
671                 else
672                 {
673                     // Init/finalize code...
674                     String attrInitializer = attributeName
675                             + " = ("
676                             + annotation.getParentAttribute().getAttributeType()
677                             + ")_CG_parameterErrors.refreshParameter(getParameters().getStageParameters().getParameter(\""
678                             + id + "\"), this);";
679 
680                     if (attribute.containsAnnotation(AddDocumentToRepository.class.getCanonicalName()))
681                     {
682                         if (annotation.getParentAttribute().getAttributeType()
683                                 .equals(DocumentRepositoryEntry.class.getCanonicalName()))
684                             attrInitializer += " if (" + attributeName + " != null && " + attributeName
685                                     + ".getId() == null ) {" + attributeName
686                                     + " = getTemplateResources().getDocumentRepositoryManager().addDocument("
687                                     + attributeName + ");" + "}";
688                     }
689 
690                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
691                             CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attrInitializer);
692 
693                     if (!param.isReadonly())
694                     {
695                         String attrFinalizer = "getParameters().getStageParameters().getParameter(\"" + id
696                                 + "\").setValue(" + attributeName + ", this);";
697                         classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
698                                 CGAncillaries.STAGE_POSTPROCESSING_METHOD_NAME, attrFinalizer);
699                     }
700                 }
701 
702             }
703             else if (annotationName.equals(InjectParameter.class.getCanonicalName()))
704             {
705 
706                 // Fetch id
707                 String id = memberValues.get(AnnotationMemberTags.PARAMETER_ID).toString();
708 
709                 // No id given, use the attribute name to lower case
710                 if (id.equals(AnnotationTags.GENERATE_ID))
711                     id = attribute.getName().toLowerCase();
712 
713                 // Get the parent service ID...
714                 AnnotationHolder stageDefinitionAnnotation = attribute.getParentClass().getAnnotations()
715                         .get(StageDefinition.class.getCanonicalName());
716                 String serviceID = stageDefinitionAnnotation.getMembers()
717                         .get(AnnotationMemberTags.STAGE_DEFINITION_SERVICE).toString();
718 
719                 IParameterManager parameterManager = DIFIoCRegistry.getRegistry().getImplementation(
720                         IParameterManager.class);
721 
722                 IParameter<?> param = parameterManager.getParameter(Entity.SERVICE, serviceID, id);
723                 String parameterGetter = null;
724 
725                 // Try to find the parameter through the DEM hierarchy
726                 if (param != null)
727                     parameterGetter = "getServiceParameters()";
728                 else
729                 {
730                     IDEMManager demManager = DIFIoCRegistry.getRegistry().getImplementation(IDEMManager.class);
731                     IApplication application = demManager.getService(serviceID).getApplication();
732                     param = parameterManager.getParameters(application).getParameter(id);
733 
734                     if (param != null)
735                         parameterGetter = "getApplicationParameters()";
736                     else
737                     {
738                         IProvider provider = application.getProvider();
739                         param = parameterManager.getParameters(provider).getParameter(id);
740 
741                         if (param != null)
742                             parameterGetter = "getProviderParameters()";
743                     }
744                 }
745 
746                 if (parameterGetter == null)
747                     // Throw UnsupportedOpertationException to comply with Java
748                     // standards and warn user of the misusage.
749                     throw new UnsupportedOperationException("Parameter injection failed for attribute: \""
750                             + attributeName + "\"\n" + "Could not find a parameter for the id \"" + id
751                             + "\" in the DEM hierarchy.");
752 
753                 // Init/finalize code...
754                 String attrInitializer = attributeName + " = (" + annotation.getParentAttribute().getAttributeType()
755                         + ")_CG_parameterErrors.refreshParameter(getParameters()." + parameterGetter
756                         + ".getParameter(\"" + id + "\"), this);";
757 
758                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
759                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attrInitializer);
760 
761                 if (param != null && !param.isReadonly())
762                 {
763                     String attrFinalizer = "getParameters()." + parameterGetter + ".getParameter(\"" + id
764                             + "\").setValue(" + attributeName + ", this);";
765                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
766                             CGAncillaries.STAGE_POSTPROCESSING_METHOD_NAME, attrFinalizer);
767                 }
768 
769             }
770             else if (annotationName.equals(InjectParameters.class.getCanonicalName()))
771             {
772                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
773                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName + "= getParameters();");
774 
775             }
776             else if (annotationName.equals(InjectParameterErrors.class.getCanonicalName()))
777             {
778                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
779                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName
780                                 + "= getParameterErrors();");
781                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
782                         CGAncillaries.STAGE_POSTPROCESSING_METHOD_NAME, "setParameterErrors(" + attributeName + ");");
783 
784                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_HAS_PARAMETER_ERROR_INJECTION,
785                         "return true;");
786 
787             }
788             else if (annotationName.equals(ProviderList.class.getCanonicalName()))
789             {
790 
791                 String source = null;
792                 String signature = attribute.getSignature();
793 
794                 // TODO: The invocation of other classes is slow to compile
795                 // in Javassist. This line is taking 50 to
796                 // 100 times more to compile than all other ones.
797 
798                 if (signature.contains(CGAncillaries.MAP_RETURN))
799                 {
800                     source = attributeName + "=getTemplateResources().getDEMManager().getProviders();";
801                 }
802                 else if (signature.contains(CGAncillaries.LIST_RETURN))
803                 {
804                     source = attributeName + "= getTemplateResources().getProvidersAsList();";
805                 }
806 
807                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
808                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, source);
809 
810             }
811             else if (annotationName.equals(Inject.class.getCanonicalName()))
812             {
813                 Entity parentType = EntityUtils.getEntityType(attribute.getParentClass());
814                 if (parentType == Entity.STAGE)
815                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_PROXY_ID,
816                             CGAncillaries.STAGE_HAS_INJECTED_CONTRIBUTIONS, "return true;");
817                 else
818                     throw new UnsupportedOperationException("Dependency injection failed for attribute: \""
819                             + attributeName + "\"\n" + "@Inject can only be used in STAGE classes and not in "
820                             + parentType.toString() + ".");
821             }
822             else if (annotationName.equals(InjectAuthenticationError.class.getCanonicalName()))
823             {
824                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
825                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName
826                                 + "= getAuthenticationError();");
827                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_PROXY_ID,
828                         CGAncillaries.STAGE_HAS_AUTHENTICATION_ERROR_INJECTION, "return true;");
829             }
830         }
831         catch (ResourceNotFoundException e)
832         {
833             // Rethrow for outer handling
834             throw e;
835         }
836         catch (Exception e)
837         {
838             DIFCodeGenerationException codeGenException;
839 
840             if (e instanceof DIFCodeGenerationException)
841             {
842                 codeGenException = (DIFCodeGenerationException) e;
843             }
844             else
845             {
846 
847                 codeGenException = new DIFCodeGenerationException(e);
848                 codeGenException.addToExceptionContext("Original Class Name", classEnhancementContext
849                         .getOriginalClassObject().getFQName());
850             }
851 
852             codeGenException.addToExceptionContext("Annotation", annotation.getName());
853             codeGenException.addToExceptionContext("Attribute", attribute.getName());
854 
855             throw codeGenException;
856         }
857     }
858 
859     /**
860      * This method will define the code to enhance the methods based on the annotations. It will create the appropriate
861      * methods and their code and add them to the classEnhancement object.
862      * 
863      * @param classEnhancementContext
864      *            the class enhancement context
865      * @param annotation
866      *            the annotation used to define the source code needed for enhancement
867      * @param method
868      *            the method to be enhanced (to make the context available to the source building process)
869      * @throws ResourceNotFoundException
870      *             if annotation members can't be accessed
871      * @throws DIFCodeGenerationException
872      */
873     public void addSourceCodeForAnnotation(ClassEnhancementContext classEnhancementContext,
874             AnnotationHolder annotation, MethodHolder method) throws ResourceNotFoundException,
875             DIFCodeGenerationException
876     {
877         try
878         {
879             // Get annotation and method info
880             String annotationName = annotation.getName();
881             String methodName = method.getName();
882             String signature = method.getSignature();
883 
884             if (annotationName.equals(CustomParameters.class.getCanonicalName()))
885             {
886 
887                 // Get the ID and the type of the parent...
888                 String parentID = EntityUtils.getEntityID(method.getParentClass());
889                 Entity parentType = EntityUtils.getEntityType(method.getParentClass());
890 
891                 if (parentType == Entity.STAGE)
892                 {
893                     if (signature.equals(CGAncillaries.IPARAMETERS_ARGS + CGAncillaries.VOID_RETURN))
894                     {
895                         classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
896                                 CGAncillaries.CALL_INIT_CUSTOM_PARAMETERS_METHOD, "{this." + methodName
897                                         + "($1);_CG_hasCustomParameters = true;}");
898                     }
899                     else
900                     {
901                         throw new UnsupportedOperationException("(" + parentType.toString() + ": " + parentID
902                                 + ", method: " + methodName + ") @" + CustomParameters.class.getSimpleName()
903                                 + " can only be used on methods with void return and a single parameter of type "
904                                 + IParameters.class.getSimpleName() + ".");
905                     }
906                 }
907                 else
908                     throw new UnsupportedOperationException("(" + parentType.toString() + ": " + parentID + ") @"
909                             + CustomParameters.class.getSimpleName() + " can only be used for Stage entities.");
910             }
911             else if (annotationName.equals(Init.class.getCanonicalName()))
912             {
913 
914                 // Get the ID and the type of the parent...
915                 String parentID = EntityUtils.getEntityID(method.getParentClass());
916                 Entity parentType = EntityUtils.getEntityType(method.getParentClass());
917 
918                 if (parentType == Entity.APPLICATION)
919                 {
920                     if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.VOID_RETURN))
921                     {
922                         classEnhancementContext.addEnhancement(CGAncillaries.APP_INIT_METHOD, "{this." + methodName
923                                 + "();}");
924                     }
925                     else
926                     {
927                         throw new UnsupportedOperationException("(" + parentType.toString() + ": " + parentID
928                                 + ") @Init events for applications must comply with: no arguments and void return.");
929                     }
930                 }
931                 else if (parentType == Entity.STAGE)
932                 {
933                     if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.VOID_RETURN))
934                     {
935                         /*
936                          * IMPLEMENTATION NOTE: Albeit the annotated method's return is void, IStage#init(DIFContext)
937                          * returns a boolean, so the code generation must inject a boolean return. It always returns T.
938                          */
939                         classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
940                                 CGAncillaries.CALL_INIT_METHOD, "{this." + methodName + "(); return true;}");
941 
942                     }
943                     else if (signature.equals(CGAncillaries.IDIF_CONTEXT_ARGS + CGAncillaries.VOID_RETURN))
944                     {
945                         /*
946                          * IMPLEMENTATION NOTE: Albeit the annotated method's return is void, IStage#init(DIFContext)
947                          * returns a boolean, so the code generation must inject a boolean return. It always returns T.
948                          */
949                         classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
950                                 CGAncillaries.CALL_INIT_METHOD, "{this." + methodName + "($1); return true;}");
951 
952                     }
953                     else if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.BOOLEAN_RETURN))
954                     {
955                         classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
956                                 CGAncillaries.CALL_INIT_METHOD, "{return this." + methodName + "();}");
957 
958                     }
959                     else if (signature.equals(CGAncillaries.IDIF_CONTEXT_ARGS + CGAncillaries.BOOLEAN_RETURN))
960                     {
961                         classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
962                                 CGAncillaries.CALL_INIT_METHOD, "{return this." + methodName + "($1);}");
963                     }
964                 }
965                 else
966                     throw new UnsupportedOperationException("(" + parentType.toString() + ": " + parentID
967                             + ") @Init can only be user for Stage or Application entities.");
968             }
969             else if (annotationName.equals(Execute.class.getCanonicalName()))
970             {
971 
972                 String code = getCodeForExecutionMethod(signature, methodName);
973 
974                 if (code != null)
975                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
976                             CGAncillaries.CALL_EXEC_METHOD, code);
977 
978             }
979             else if (annotationName.equals(Finalize.class.getCanonicalName()))
980             {
981 
982                 if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.VOID_RETURN))
983                 {
984                     /*
985                      * IMPLEMENTATION NOTE: Although the annotated method's return is void, IStage#finalize(DIFContext)
986                      * returns a boolean, so the code generation must inject a boolean return. It always returns T.
987                      */
988                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
989                             CGAncillaries.CALL_FINALIZE_METHOD, "{this." + methodName + "(); return true;}");
990                 }
991                 else if (signature.equals(CGAncillaries.IDIF_CONTEXT_ARGS + CGAncillaries.VOID_RETURN))
992                 {
993                     /*
994                      * IMPLEMENTATION NOTE: Albeit the annotated method's return is void, IStage#finalize(DIFContext)
995                      * returns a boolean, so the code generation must inject a boolean return. It always returns T.
996                      */
997                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
998                             CGAncillaries.CALL_FINALIZE_METHOD, "{this." + methodName + "($1); return true;}");
999                 }
1000                 else if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.BOOLEAN_RETURN))
1001                 {
1002                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
1003                             CGAncillaries.CALL_FINALIZE_METHOD, "{return this." + methodName + "();}");
1004                 }
1005                 else if (signature.equals(CGAncillaries.IDIF_CONTEXT_ARGS + CGAncillaries.BOOLEAN_RETURN))
1006                 {
1007                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
1008                             CGAncillaries.CALL_FINALIZE_METHOD, "{return this." + methodName + "($1);}");
1009                 }
1010             }
1011             else if (annotationName.equals(Inject.class.getCanonicalName()))
1012             {
1013                 Entity parentType = EntityUtils.getEntityType(method.getParentClass());
1014                 if (parentType == Entity.STAGE)
1015                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_PROXY_ID,
1016                             CGAncillaries.STAGE_HAS_INJECTED_CONTRIBUTIONS, "return true;");
1017                 else
1018                     throw new UnsupportedOperationException("Dependency injection failed for method: \"" + method
1019                             + "\"\n" + "@Inject can only be used in STAGE classes and not in " + parentType.toString()
1020                             + ".");
1021             }
1022         }
1023         catch (ResourceNotFoundException e)
1024         {
1025             // Rethrow for outer handling
1026             throw e;
1027         }
1028         catch (Exception e)
1029         {
1030             DIFCodeGenerationException codeGenException;
1031 
1032             if (e instanceof DIFCodeGenerationException)
1033             {
1034                 codeGenException = (DIFCodeGenerationException) e;
1035             }
1036             else
1037             {
1038 
1039                 codeGenException = new DIFCodeGenerationException(e);
1040                 codeGenException.addToExceptionContext("Original Class Name", classEnhancementContext
1041                         .getOriginalClassObject().getFQName());
1042             }
1043 
1044             codeGenException.addToExceptionContext("Annotation", annotation.getName());
1045             codeGenException.addToExceptionContext("Method", method.getName());
1046 
1047             throw codeGenException;
1048         }
1049     }
1050 
1051     /**
1052      * Adds an injected stage to the current stage to enhance. Injects it the the attribute associated (if passed) and
1053      * to the inner Maps.
1054      * 
1055      * @param annotation
1056      *            the annotation that declared the stage
1057      * @param classEnhancementContext
1058      *            the class enhancement context
1059      * @param errorStage
1060      *            if the stage to add is an error stage
1061      * @param defaultStage
1062      *            if the current stage is the default stage
1063      * @param attributeName
1064      *            the name of the attribute to assign the new stage to
1065      * @throws ResourceNotFoundException
1066      *             if the annotation cannot be read
1067      * @throws DIFCodeGenerationException
1068      */
1069     protected void addStage(AnnotationHolder annotation, ClassEnhancementContext classEnhancementContext,
1070             boolean errorStage, boolean defaultStage, String attributeName) throws ResourceNotFoundException,
1071             DIFCodeGenerationException
1072     {
1073         try
1074         {
1075             String stageID;
1076 
1077             AnnotationMemberValueHolder target = annotation.getMembers().get("target");
1078 
1079             if (target == null)
1080                 target = annotation.getMembers().get("value");
1081 
1082             if (target != null)
1083                 stageID = "\"" + target.toString() + "\"";
1084             else
1085                 stageID = attributeName + ".getID()";
1086 
1087             String stageDeclaration = "getTemplateResources().getDEMManager().getStage(" + stageID + ")";
1088 
1089             // If no attribute is available the stage will be obtained from the
1090             // manager...
1091             if (attributeName != null)
1092                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
1093                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName + " = "
1094                                 + stageDeclaration + ";");
1095 
1096             classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INJECTED_STAGES_BUILDER, "injectedStages.add("
1097                     + stageID + ");");
1098 
1099             if (errorStage)
1100             {
1101                 String[] exceptions = CGAncillaries.parse(
1102                         annotation.getMembers().get(AnnotationMemberTags.ERROR_STAGE_EXCEPTIONS).toString(),
1103                         CGAncillaries.COMMA);
1104 
1105                 for (int i = 0; i < exceptions.length; i++)
1106                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INJECTED_ERRORSTAGES_BUILDER,
1107                             "errorStages.put(\"" + exceptions[i] + "\"," + stageID + ");");
1108             }
1109 
1110             String key = CGAncillaries.STAGE_GET_DEFAULT_ERROR_STAGE;
1111 
1112             // If it's the default error stage or there is none yet defined yet,
1113             // this will become it!
1114             if (errorStage && (defaultStage || !classEnhancementContext.containsEnhancement(key)))
1115             {
1116                 classEnhancementContext.addEnhancement(key, "{return " + stageDeclaration + ";}");
1117             }
1118         }
1119         catch (ResourceNotFoundException e)
1120         {
1121             // Rethrow for outer handling
1122             throw e;
1123         }
1124         catch (Exception e)
1125         {
1126             DIFCodeGenerationException codeGenException;
1127 
1128             if (e instanceof DIFCodeGenerationException)
1129             {
1130                 codeGenException = (DIFCodeGenerationException) e;
1131             }
1132             else
1133             {
1134 
1135                 codeGenException = new DIFCodeGenerationException(e);
1136                 codeGenException.addToExceptionContext("Original Class Name", classEnhancementContext
1137                         .getOriginalClassObject().getFQName());
1138             }
1139 
1140             codeGenException.addToExceptionContext("Annotation", annotation.getName());
1141             codeGenException.addToExceptionContext("Attribute", attributeName);
1142 
1143             throw codeGenException;
1144         }
1145     }
1146 
1147     /**
1148      * Adds an injected view to the current stage to enhance. Injects it the the attribute associated (if passed) and to
1149      * the inner Maps.
1150      * 
1151      * @param annotation
1152      *            the annotation that declared the stage
1153      * @param classEnhancementContext
1154      *            the class enhancement context
1155      * @param errorView
1156      *            if the view to add is an error view
1157      * @param defaultView
1158      *            if the view to add is the default stage view
1159      * @param attributeName
1160      *            the name of the attribute to assign the new view to
1161      * @throws ResourceNotFoundException
1162      *             if the annotation cannot be read
1163      * @throws DIFCodeGenerationException
1164      */
1165     protected void addView(AnnotationHolder annotation, ClassEnhancementContext classEnhancementContext,
1166             boolean errorView, boolean defaultView, String attributeName) throws ResourceNotFoundException,
1167             DIFCodeGenerationException
1168     {
1169         try
1170         {
1171             // Get Error Stage id
1172             String target = annotation.getMembers().get(AnnotationMemberTags.VIEW_TARGET).toString();
1173 
1174             // Get view engine
1175             String engine = annotation.getMembers().get(AnnotationMemberTags.VIEW_ENGINE).toString();
1176 
1177             // Infer the view engine if not passed
1178             if (engine.equals(AnnotationTags.NONE))
1179             {
1180                 int posExtension = target.lastIndexOf(".");
1181 
1182                 if (posExtension != -1)
1183                     engine = target.substring(posExtension + 1);
1184             }
1185 
1186             // Set view type
1187             ViewType viewType = null;
1188 
1189             if (errorView)
1190                 viewType = ViewType.ERROR;
1191             else
1192                 viewType = ViewType.NORMAL;
1193 
1194             String viewDeclaration = "createView(\"" + engine + "\",\"" + viewType + "\",\"" + target + "\","
1195                     + defaultView + ")";
1196 
1197             // If no attribute is available the view will be generated...
1198             if (attributeName != null)
1199                 classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INSTANCE_ID,
1200                         CGAncillaries.STAGE_INJECTED_ATTRIBUTES_INIT_METHOD_NAME, attributeName + " = "
1201                                 + viewDeclaration + ";");
1202 
1203             classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INJECTED_VIEWS_BUILDER, "injectedViews.add("
1204                     + viewDeclaration + ");");
1205 
1206             if (errorView)
1207             {
1208                 String[] exceptions = CGAncillaries.parse(
1209                         annotation.getMembers().get(AnnotationMemberTags.ERROR_STAGE_EXCEPTIONS).toString(),
1210                         CGAncillaries.COMMA);
1211 
1212                 for (int i = 0; i < exceptions.length; i++)
1213                     classEnhancementContext.addEnhancement(CGAncillaries.STAGE_INJECTED_ERRORVIEWS_BUILDER,
1214                             "\nerrorViews.put(\"" + exceptions[i] + "\"," + viewDeclaration + ");");
1215             }
1216 
1217             String key = errorView ? CGAncillaries.STAGE_GET_DEFAULT_ERROR_VIEW : CGAncillaries.STAGE_GET_DEFAULT_VIEW;
1218 
1219             // If it's the default error stage or there is none yet defined yet,
1220             // this will become it!
1221             if (defaultView || !classEnhancementContext.containsEnhancement(key))
1222             {
1223                 classEnhancementContext.addEnhancement(key, "{return " + viewDeclaration + ";}");
1224             }
1225         }
1226         catch (ResourceNotFoundException e)
1227         {
1228             // Rethrow for outer handling
1229             throw e;
1230         }
1231         catch (Exception e)
1232         {
1233             DIFCodeGenerationException codeGenException;
1234 
1235             if (e instanceof DIFCodeGenerationException)
1236             {
1237                 codeGenException = (DIFCodeGenerationException) e;
1238             }
1239             else
1240             {
1241 
1242                 codeGenException = new DIFCodeGenerationException(e);
1243                 codeGenException.addToExceptionContext("Original Class Name", classEnhancementContext
1244                         .getOriginalClassObject().getFQName());
1245             }
1246 
1247             codeGenException.addToExceptionContext("Annotation", annotation.getName());
1248             codeGenException.addToExceptionContext("Attribute", attributeName);
1249 
1250             throw codeGenException;
1251         }
1252     }
1253 
1254     /**
1255      * Checks if a given annotation can be used with another.
1256      * 
1257      * @param annotationToCheck
1258      *            the annotation to check
1259      * @param thisAnnotation
1260      *            the annotation to validate against
1261      * @return F if the annotation to check is primary and doesn't yield to the other, T otherwise
1262      * @throws ResourceNotFoundException
1263      *             if any resource needed for validation could not be found.
1264      */
1265     protected boolean checkUseWith(AnnotationHolder annotationToCheck, AnnotationHolder thisAnnotation)
1266             throws ResourceNotFoundException
1267     {
1268 
1269         if (annotationToCheck.getName().equals(thisAnnotation.getName()))
1270             return true;
1271 
1272         if (isPrimary(annotationToCheck) && isPrimary(thisAnnotation))
1273         {
1274             if (yieldsTo(annotationToCheck, thisAnnotation.getName())
1275                     || yieldsTo(thisAnnotation, annotationToCheck.getName()))
1276                 return true;
1277             else
1278                 return false;
1279         }
1280 
1281         return true;
1282     }
1283 
1284     /**
1285      * Returns the annotationName.
1286      * 
1287      * @return the value of the annotationName
1288      */
1289     public String getAnnotation()
1290     {
1291         return this.annotationName;
1292     }
1293 
1294     /**
1295      * @return the authorizationManager
1296      */
1297     protected IAuthorizationManager getAuthorizationManager()
1298     {
1299         if (authorizationManager == null)
1300             authorizationManager = DIFIoCRegistry.getRegistry().getImplementation(IAuthorizationManager.class);
1301 
1302         return authorizationManager;
1303     }
1304 
1305     /**
1306      * Return the appropriated execute method call injecting a return view if necessary and the appropriated parameters
1307      * 
1308      * @param signature
1309      *            the method to call signature
1310      * @param methodName
1311      *            the method name to call
1312      * @return the line of code for the calling of the method
1313      */
1314     protected String getCodeForExecutionMethod(String signature, String methodName)
1315     {
1316 
1317         /*
1318          * IMPLEMENTATION NOTE: Although the annotated method's return is void, IStage#execute(DIFContext) returns a
1319          * ViewObject, so the code generation must inject a ViewObject return. It returns the default view.
1320          */
1321 
1322         if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.VOID_RETURN))
1323         {
1324             return "{this." + methodName + "(); return this.getDefaultView();}";
1325 
1326         }
1327         else if (signature.equals(CGAncillaries.IDIF_CONTEXT_ARGS + CGAncillaries.VOID_RETURN))
1328         {
1329             return "{this." + methodName + "($1); return this.getDefaultView();}";
1330 
1331         }
1332         else if (signature.equals(CGAncillaries.IDIF_CONTEXT_ARGS + CGAncillaries.VIEW_OBJECT_RETURN))
1333         {
1334             return "{return this." + methodName + "($1);}";
1335 
1336         }
1337         else if (signature.equals(CGAncillaries.VOID_ARGS + CGAncillaries.VIEW_OBJECT_RETURN))
1338         {
1339             return "{return this." + methodName + "();}";
1340 
1341         }
1342         else
1343             return null;
1344     }
1345 
1346     /**
1347      * @return T if the current annotation is a DEM annotation
1348      */
1349     protected boolean isDEMAnnotation()
1350     {
1351         try
1352         {
1353             // Google Guice's @Inject is a special case since it exists in the DEMLogicMap but is not itself a DEM
1354             // annotation
1355             return (!annotationFQName.equals(Inject.class.getCanonicalName()))
1356                     && (DEMLoaderHelper.getAnnotationLogicMap().keySet().contains(this.annotationFQName));
1357 
1358         }
1359         catch (ResourceNotFoundException e)
1360         {
1361             return false;
1362         }
1363         catch (AuxiliaryOperationException e)
1364         {
1365             return false;
1366         }
1367     }
1368 
1369     /**
1370      * Returns the value of the primary annotationName flag.
1371      * 
1372      * @return T if the annotationName is primary, F otherwise
1373      */
1374     final public boolean isPrimary()
1375     {
1376         return primary;
1377     }
1378 
1379     /**
1380      * Checks if a given annotation is primary.
1381      * 
1382      * @param annotation
1383      *            the annotation to check
1384      * @return T if annotation is meta-annotated with <code>@Primary</code>, F otherwise.
1385      * @throws ResourceNotFoundException
1386      *             if meta-annotations can't be found
1387      */
1388     protected boolean isPrimary(AnnotationHolder annotation) throws ResourceNotFoundException
1389     {
1390         return annotation.getMetaAnnotations().keySet().contains(Primary.class.getCanonicalName());
1391     }
1392 
1393     /**
1394      * Checks if a given set of access flags matches a static member.
1395      * 
1396      * @param accessFlags
1397      *            the members access flags
1398      * @return T if it's a private member, F otherwise
1399      */
1400     private boolean isPrivate(int accessFlags)
1401     {
1402         if ((accessFlags & 2) == 2)
1403             return true;
1404         else
1405             return false;
1406     }
1407 
1408     /**
1409      * Checks if a given set of access flags matches a static member.
1410      * 
1411      * @param accessFlags
1412      *            the member's access flags
1413      * @return T if it's a static member, F otherwise
1414      */
1415     private boolean isStatic(int accessFlags)
1416     {
1417         // 8 is the static flag on the JVM. See the JVM Specs for more info.
1418         if ((accessFlags & 8) == 8)
1419             return true;
1420         else
1421             return false;
1422     }
1423 
1424     /**
1425      * Prepares the exception context from the attribute.
1426      * 
1427      * @param attribute
1428      *            the class object
1429      * @return the exception context
1430      */
1431     protected Map<String, Object> prepareExceptionContext(AttributeHolder attribute)
1432     {
1433         // Set exception context
1434         Map<String, Object> exceptionContext = new HashMap<String, Object>();
1435 
1436         exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATION_SCOPE,
1437                 IncompatiblePrimaryAnnotationsException.ATTRIBUTE_SCOPE);
1438         exceptionContext.put(AnnotationMisuseException.ContextKeys.CLASS, attribute.getParentClassName());
1439         exceptionContext.put(AnnotationMisuseException.ContextKeys.METHOD, attribute.getName());
1440 
1441         try
1442         {
1443 
1444             List<String> annotationsFound = new ArrayList<String>();
1445 
1446             for (AnnotationHolder annotation: attribute.getAnnotations().values())
1447             {
1448                 if (annotation.getMetaAnnotations().containsKey(Primary.class.getCanonicalName()))
1449                 {
1450                     annotationsFound.add(annotation.getName());
1451                 }
1452             }
1453 
1454             exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATIONS_FOUND, annotationsFound);
1455 
1456         }
1457         catch (ResourceNotFoundException resourceNotFoundException)
1458         {
1459             exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATIONS_FOUND, resourceNotFoundException);
1460         }
1461 
1462         return exceptionContext;
1463     }
1464 
1465     /**
1466      * Prepares the exception context from the class.
1467      * 
1468      * @param clazz
1469      *            the class object
1470      * @return the exception context
1471      */
1472     protected Map<String, Object> prepareExceptionContext(ClassHolder clazz)
1473     {
1474         // Set exception context
1475         Map<String, Object> exceptionContext = new HashMap<String, Object>();
1476 
1477         exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATION_SCOPE,
1478                 IncompatiblePrimaryAnnotationsException.CLASS_SCOPE);
1479         exceptionContext.put(AnnotationMisuseException.ContextKeys.CLASS, clazz.getFQName());
1480 
1481         try
1482         {
1483 
1484             List<String> annotationsFound = new ArrayList<String>();
1485 
1486             for (AnnotationHolder annotation: clazz.getAnnotations().values())
1487             {
1488                 if (annotation.getMetaAnnotations().containsKey(Primary.class.getCanonicalName()))
1489                 {
1490                     annotationsFound.add(annotation.getName());
1491                 }
1492             }
1493 
1494             exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATIONS_FOUND, annotationsFound);
1495 
1496         }
1497         catch (ResourceNotFoundException resourceNotFoundException)
1498         {
1499             exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATIONS_FOUND, resourceNotFoundException);
1500         }
1501 
1502         return exceptionContext;
1503     }
1504 
1505     /**
1506      * Prepares the exception context from the method.
1507      * 
1508      * @param method
1509      *            the class object
1510      * @return the exception context
1511      */
1512     protected Map<String, Object> prepareExceptionContext(MethodHolder method)
1513     {
1514         // Set exception context
1515         Map<String, Object> exceptionContext = new HashMap<String, Object>();
1516 
1517         exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATION_SCOPE,
1518                 IncompatiblePrimaryAnnotationsException.METHOD_SCOPE);
1519         exceptionContext.put(AnnotationMisuseException.ContextKeys.CLASS, method.getParentClassName());
1520         exceptionContext.put(AnnotationMisuseException.ContextKeys.METHOD, method.getName());
1521 
1522         try
1523         {
1524 
1525             List<String> annotationsFound = new ArrayList<String>();
1526 
1527             for (AnnotationHolder annotation: method.getAnnotations().values())
1528             {
1529                 if (annotation.getMetaAnnotations().containsKey(Primary.class.getCanonicalName()))
1530                 {
1531                     annotationsFound.add(annotation.getName());
1532                 }
1533             }
1534 
1535             exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATIONS_FOUND, annotationsFound);
1536 
1537         }
1538         catch (ResourceNotFoundException resourceNotFoundException)
1539         {
1540             exceptionContext.put(AnnotationMisuseException.ContextKeys.ANNOTATIONS_FOUND, resourceNotFoundException);
1541         }
1542 
1543         return exceptionContext;
1544     }
1545 
1546     /**
1547      * Sets the annotationName value.
1548      * 
1549      * @param newAnnotation
1550      *            the new annotationName value
1551      */
1552     public void setAnnotation(String newAnnotation)
1553     {
1554         this.annotationName = newAnnotation;
1555     }
1556 
1557     /**
1558      * Validates if the entities referred on the annotation parameters are valid on the DEM context.
1559      * 
1560      * @param annotationName
1561      *            the name of the annotation to validate
1562      * @param clazz
1563      *            the class holder
1564      * @throws ResourceNotFoundException
1565      *             if any resource needed for the validation can't be found
1566      */
1567     protected void validateDEMConsistency(String annotationName, ClassHolder clazz) throws ResourceNotFoundException
1568     {
1569 
1570         // Fetch class annotations
1571         Map<String, AnnotationHolder> classAnnotations = clazz.getAnnotations();
1572 
1573         AnnotationHolder theAnnotation = null;
1574 
1575         // @ApplicationDefinition annotation
1576         if (ApplicationDefinition.class.getCanonicalName().contains(annotationName)
1577                 && classAnnotations.containsKey(ApplicationDefinition.class.getCanonicalName()))
1578         {
1579 
1580             theAnnotation = classAnnotations.get(ApplicationDefinition.class.getCanonicalName());
1581 
1582             String provider = theAnnotation.getMembers().get(PROVIDER_ATTRIBUTE_NAME).toString();
1583 
1584             if (DEMLoaderEntityRegistry.getProvider(provider.toLowerCase()) == null)
1585                 warnOfEnityMisuseOnClass(clazz.getFQName(), provider);
1586         }
1587         // @ServiceDefinition annotation
1588         else if (ServiceDefinition.class.getCanonicalName().contains(annotationName)
1589                 && classAnnotations.containsKey(ServiceDefinition.class.getCanonicalName()))
1590         {
1591             theAnnotation = classAnnotations.get(ServiceDefinition.class.getCanonicalName());
1592 
1593             String application = theAnnotation.getMembers().get(APPLICATION_ATTRIBUTE_NAME).toString();
1594 
1595             if (DEMLoaderEntityRegistry.getApplication(application.toLowerCase()) == null)
1596                 warnOfEnityMisuseOnClass(clazz.getFQName(), application);
1597         }
1598         // @StageDefinition annotation
1599         else if (StageDefinition.class.getCanonicalName().contains(annotationName)
1600                 && classAnnotations.containsKey(StageDefinition.class.getCanonicalName()))
1601         {
1602             theAnnotation = classAnnotations.get(StageDefinition.class.getCanonicalName());
1603 
1604             String service = theAnnotation.getMembers().get(SERVICE_ATTRIBUTE_NAME).toString();
1605 
1606             if (DEMLoaderEntityRegistry.getService(service.toLowerCase()) == null)
1607                 warnOfEnityMisuseOnClass(clazz.getFQName(), service);
1608         }
1609     }
1610 
1611     /**
1612      * Validates if a given class message file exists. Only works if DiF is in DEBUG mode.
1613      * 
1614      * @param clazz
1615      *            the class to validate the messages *
1616      * @throws ResourceNotFoundException
1617      *             if any resource needed for the validation can't be found
1618      */
1619     protected void validateMessages(ClassHolder clazz) throws ResourceNotFoundException
1620     {
1621 
1622         // If DiF's in DEBUG...
1623         if (LogLevel.DEBUG.equals(DIFStartupConfiguration.getLogLevel()))
1624         {
1625 
1626             Entity entityType = null;
1627             String parentID = null;
1628 
1629             Map<String, AnnotationHolder> annotations = clazz.getAnnotations();
1630 
1631             // @ProviderDefinition annotation (does not have a parent, parentID will be null)
1632             if (annotations.containsKey(ProviderDefinition.class.getCanonicalName()))
1633             {
1634                 entityType = Entity.PROVIDER;
1635             }
1636             // @ApplicationDefinition annotation
1637             else if (annotations.containsKey(ApplicationDefinition.class.getCanonicalName()))
1638             {
1639                 entityType = Entity.APPLICATION;
1640                 parentID = annotations.get(ApplicationDefinition.class.getCanonicalName()).getMembers()
1641                         .get(PROVIDER_ATTRIBUTE_NAME).getManagedAnnotationValue().toString();
1642             }
1643             // @ServiceDefinition annotation
1644             else if (annotations.containsKey(ServiceDefinition.class.getCanonicalName()))
1645             {
1646                 entityType = Entity.SERVICE;
1647                 parentID = annotations.get(ServiceDefinition.class.getCanonicalName()).getMembers()
1648                         .get(APPLICATION_ATTRIBUTE_NAME).getManagedAnnotationValue().toString();
1649             }
1650             // @StageDefinition annotation
1651             else if (annotations.containsKey(StageDefinition.class.getCanonicalName()))
1652             {
1653                 entityType = Entity.STAGE;
1654                 parentID = annotations.get(StageDefinition.class.getCanonicalName()).getMembers()
1655                         .get(SERVICE_ATTRIBUTE_NAME).getManagedAnnotationValue().toString();
1656 
1657             }
1658 
1659             // Remove the leading and trailing quotation marks
1660             if (parentID != null)
1661                 parentID = parentID.substring(1, parentID.length() - 1);
1662 
1663             // Get the message manager...
1664             IMessageManager messageManager = DIFIoCRegistry.getRegistry().getImplementation(IMessageManager.class);
1665 
1666             // ...fetch messages for this class from the message manager
1667             MessageList messages = messageManager.collectEntityMessagesFromRepository(entityType, clazz.generateID(),
1668                     clazz.getFQName(), parentID);
1669 
1670             // If there are no messages, warn user..
1671             if (messages == null || messages.getMessageIDs().size() == 0)
1672             {
1673                 UsageIssuesManagerImpl.getInstance().addIssue(IssueType.WARN, IssueScope.LOADTIME, clazz.getFQName(),
1674                         "Missing messages file!", null);
1675             }
1676         }
1677     }
1678 
1679     /**
1680      * Validates that the attribute is non-private.
1681      * 
1682      * @param attribute
1683      *            the attribute to validate
1684      * @return T if the attribute is non-private, F otherwise
1685      */
1686     protected boolean validateNonPrivate(AttributeHolder attribute)
1687     {
1688 
1689         // Should only validate DEM annotations
1690         if (isDEMAnnotation())
1691         {
1692             int accessFlags = attribute.getManagedAttribute().getModifiers();
1693 
1694             if (isPrivate(accessFlags))
1695                 return false;
1696             else
1697                 return true;
1698 
1699         }
1700         else
1701             return true;
1702     }
1703 
1704     /**
1705      * Validates the use of primary annotations on a given attribute.
1706      * 
1707      * @param attribute
1708      *            the attribute to search for primary annotations
1709      * @throws AnnotationMisuseException
1710      *             if an annotation is misused
1711      * @throws ResourceNotFoundException
1712      *             if any resource needed for validation could not be found.
1713      */
1714     protected void validatePrimary(AttributeHolder attribute) throws AnnotationMisuseException,
1715             ResourceNotFoundException
1716     {
1717         // If this annotation is primary...
1718         if (this.isPrimary())
1719         {
1720 
1721             // Find the FQN for the current annotation
1722             Set<String> annotationNames = attribute.getAnnotations().keySet();
1723 
1724             String thisAnnotationFQN = null;
1725 
1726             for (String annotationName: annotationNames)
1727             {
1728                 if (annotationName.contains(this.annotationName))
1729                 {
1730                     thisAnnotationFQN = annotationName;
1731                     break;
1732                 }
1733             }
1734 
1735             // Fetch instance of current annotation
1736             AnnotationHolder thisAnnotation = new AnnotationHolder(attribute, attribute.getAnnotations()
1737                     .get(thisAnnotationFQN).getManagedAnnotation());
1738 
1739             // Get all the method's annotations...
1740             for (AnnotationHolder annotation: attribute.getAnnotations().values())
1741             {
1742                 // Check use with the the present annotation
1743                 if (!checkUseWith(annotation, thisAnnotation))
1744                     // If annotation is misused throw an exception
1745                     throw new IncompatiblePrimaryAnnotationsException(
1746                             IncompatiblePrimaryAnnotationsException.INCOMPATIBLE_PRIMARY_ANNOTATIONS_MESSAGE,
1747                             prepareExceptionContext(attribute));
1748             }
1749         }
1750     }
1751 
1752     /**
1753      * Validates the use of primary annotations on a given class.
1754      * 
1755      * @param clazz
1756      *            the class to search for primary annotations
1757      * @throws AnnotationMisuseException
1758      *             if an annotation is misused
1759      * @throws ResourceNotFoundException
1760      *             if any resource needed for validation could not be found.
1761      */
1762     protected void validatePrimary(ClassHolder clazz) throws AnnotationMisuseException, ResourceNotFoundException
1763     {
1764         // If this annotation is primary...
1765         if (this.isPrimary())
1766         {
1767 
1768             // Find the FQN for the current annotation
1769             Set<String> annotationNames = clazz.getAnnotations().keySet();
1770 
1771             String thisAnnotationFQN = null;
1772 
1773             for (String annotationName: annotationNames)
1774             {
1775                 if (annotationName.contains(this.annotationName))
1776                 {
1777                     thisAnnotationFQN = annotationName;
1778                     break;
1779                 }
1780             }
1781 
1782             // Fetch instance of current annotation
1783             AnnotationHolder thisAnnotation = new AnnotationHolder(clazz, clazz.getAnnotations().get(thisAnnotationFQN)
1784                     .getManagedAnnotation());
1785 
1786             for (AnnotationHolder annotation: clazz.getAnnotations().values())
1787             {
1788                 // Check use with the the present annotation
1789                 if (!checkUseWith(annotation, thisAnnotation))
1790                     // If annotation is misused throw an exception
1791                     throw new IncompatiblePrimaryAnnotationsException(
1792                             IncompatiblePrimaryAnnotationsException.INCOMPATIBLE_PRIMARY_ANNOTATIONS_MESSAGE,
1793                             prepareExceptionContext(clazz));
1794             }
1795         }
1796     }
1797 
1798     /**
1799      * Validates the use of primary annotations on a given method.
1800      * 
1801      * @param method
1802      *            the method to search for primary annotations
1803      * @throws AnnotationMisuseException
1804      *             if an annotation is misused
1805      * @throws ResourceNotFoundException
1806      *             if any resource needed for validation could not be found.
1807      */
1808     protected void validatePrimary(MethodHolder method) throws AnnotationMisuseException, ResourceNotFoundException
1809     {
1810         // If this annotation is primary...
1811         if (this.isPrimary())
1812         {
1813 
1814             // Find the FQN for the current annotation
1815             Set<String> annotationNames = method.getAnnotations().keySet();
1816 
1817             String thisAnnotationFQN = null;
1818 
1819             for (String annotationName: annotationNames)
1820             {
1821                 if (annotationName.contains(this.annotationName))
1822                 {
1823                     thisAnnotationFQN = annotationName;
1824                     break;
1825                 }
1826             }
1827 
1828             // Fetch instance of current annotation
1829             AnnotationHolder thisAnnotation = new AnnotationHolder(method, method.getAnnotations()
1830                     .get(thisAnnotationFQN).getManagedAnnotation());
1831 
1832             // Get all the method's annotations...
1833             for (AnnotationHolder annotation: method.getAnnotations().values())
1834             {
1835                 // Check use with the the present annotation
1836                 if (!checkUseWith(annotation, thisAnnotation))
1837                     // If annotation is misused throw an exception
1838                     throw new IncompatiblePrimaryAnnotationsException(
1839                             IncompatiblePrimaryAnnotationsException.INCOMPATIBLE_PRIMARY_ANNOTATIONS_MESSAGE,
1840                             prepareExceptionContext(method));
1841             }
1842         }
1843     }
1844 
1845     /**
1846      * Validates the usage scope of attribute annotations.
1847      * 
1848      * @param annotationName
1849      *            the name of the annotation to validate
1850      * @param attribute
1851      *            the attribute to validate
1852      * @return T if the scope is correct, F otherwise
1853      * @throws ResourceNotFoundException
1854      *             if any resource needed for the validation can't be found
1855      */
1856     protected boolean validateScope(String annotationName, AttributeHolder attribute) throws ResourceNotFoundException
1857     {
1858 
1859         Map<String, AnnotationHolder> attributeAnnotations = attribute.getAnnotations();
1860 
1861         // @Persist annotation
1862         if (Persist.class.getCanonicalName().contains(annotationName)
1863                 && attributeAnnotations.containsKey(Persist.class.getCanonicalName()))
1864         {
1865             final String SCOPE_ID = "scope";
1866             // Check scope
1867             if ((attributeAnnotations.get(Persist.class.getCanonicalName())).getMembers().containsKey(SCOPE_ID))
1868             {
1869                 AnnotationMemberValueHolder scope = attributeAnnotations.get(Persist.class.getName()).getMembers()
1870                         .get(SCOPE_ID);
1871                 MemberValue scopeValue = scope.getManagedAnnotationValue();
1872 
1873                 if (scopeValue.toString().contains(ParameterScope.STATIC.toString())
1874                         && !isStatic(attribute.getManagedAttribute().getModifiers()))
1875                 {
1876                     UsageIssuesManagerImpl.getInstance().addIssue(
1877                             IssueType.WARN,
1878                             IssueScope.LOADTIME,
1879                             attribute.getParentClassName(),
1880                             "Using @" + Persist.class.getSimpleName() + " scope " + ParameterScope.STATIC
1881                                     + " on non-static attribute: " + attribute.getName(), null);
1882                     return false;
1883                 }
1884             }
1885         }
1886         else if (FormConfigurable.class.getCanonicalName().contains(annotationName)
1887                 && attributeAnnotations.containsKey(FormConfigurable.class.getCanonicalName()))
1888         {
1889             final String LINKED_FORM_ID = "linkToForm";
1890 
1891             // Check linkedToForm
1892             AnnotationMemberValueHolder linkedToForm = null;
1893             AnnotationHolder parameterAnnotation = attributeAnnotations.get(Parameter.class.getName());
1894             if (parameterAnnotation != null)
1895                 linkedToForm = parameterAnnotation.getMembers().get(LINKED_FORM_ID);
1896 
1897             if (linkedToForm == null)
1898             {
1899                 UsageIssuesManagerImpl.getInstance().addIssue(
1900                         IssueType.WARN,
1901                         IssueScope.LOADTIME,
1902                         attribute.getParentClassName(),
1903                         "Using @" + FormConfigurable.class.getSimpleName() + " for attribute: " + attribute.getName()
1904                                 + ", that does not have a @" + Parameter.class.getSimpleName() + " with the "
1905                                 + LINKED_FORM_ID + " attribute defined", null);
1906                 return false;
1907             }
1908         }
1909 
1910         return true;
1911     }
1912 
1913     /**
1914      * Defines specific rules for applying the annotationName on a given attribute. Returns T by default.
1915      * 
1916      * @param attribute
1917      *            the annotated attribute
1918      * @param annotationName
1919      *            the annotationName
1920      * @return T if all conditions are verified, F otherwise
1921      * @throws ResourceNotFoundException
1922      */
1923     protected boolean validateSpecificRules(String annotationName, AttributeHolder attribute)
1924             throws ResourceNotFoundException
1925     {
1926         // TODO: Uncomment after bug #9863
1927         // validateViewExistence(attribute.getName(), attribute.getParentClassName(), attribute.getAnnotations());
1928         return true;
1929     }
1930 
1931     /**
1932      * Defines specific rules for applying the annotationName on a given class. Returns T by default.
1933      * 
1934      * @param annotationName
1935      *            the annotationName
1936      * @param clazz
1937      *            the annotated class
1938      * @return T if all conditions are verified, F otherwise
1939      * @throws ResourceNotFoundException
1940      *             if any needed resource for validation is not found
1941      */
1942     protected boolean validateSpecificRules(String annotationName, ClassHolder clazz) throws ResourceNotFoundException
1943     {
1944         // TODO: Uncomment after bug #9863
1945         // validateViewExistence(null, clazz.getFQName(), clazz.getAnnotations());
1946 
1947         if (annotationName.equals(ProviderDefinition.class.getSimpleName())
1948                 || annotationName.equals(ApplicationDefinition.class.getSimpleName())
1949                 || annotationName.equals(ServiceDefinition.class.getSimpleName())
1950                 || annotationName.equals(StageDefinition.class.getSimpleName()))
1951         {
1952             validateMessages(clazz);
1953         }
1954 
1955         return true;
1956     }
1957 
1958     /**
1959      * Defines specific rules for applying the annotationName on a given method. Returns T by default.
1960      * 
1961      * @param method
1962      *            the annotated method
1963      * @param annotationName
1964      *            the annotationName
1965      * @return T if all conditions are verified, F otherwise
1966      * @throws ResourceNotFoundException
1967      */
1968     protected boolean validateSpecificRules(String annotationName, MethodHolder method)
1969             throws ResourceNotFoundException
1970     {
1971         return true;
1972     }
1973 
1974     /**
1975      * Validates the use of the annotation on a given attribute. Validation includes checking if multiple primary
1976      * annotations are used, if the scope is correct, if the annotation members provide information consistent with the
1977      * DEM and if any other specific rules apply.
1978      * 
1979      * @param attribute
1980      *            the attribute on which the annotationName is used
1981      * @throws AnnotationMisuseException
1982      *             if an inappropriate annotation usage was made
1983      * @throws ResourceNotFoundException
1984      *             if any resource needed for the validation can't be found
1985      */
1986     final public void validateUsage(AttributeHolder attribute) throws AnnotationMisuseException,
1987             ResourceNotFoundException
1988     {
1989         if (!validateNonPrivate(attribute))
1990         {
1991             throw new IllegalAnnotationUsage("Annotated attribute " + attribute.getName() + " on class "
1992                     + attribute.getParentClassName()
1993                     + " is private! (Annotations can only be applied on non-private members)",
1994                     prepareExceptionContext(attribute));
1995         }
1996         validatePrimary(attribute);
1997         validateScope(annotationName, attribute);
1998         validateSpecificRules(annotationName, attribute);
1999     }
2000 
2001     /**
2002      * Validates the use of the annotation on a given class. Validation includes checking if multiple primary
2003      * annotations are used, if the scope is correct, if the annotation members provide information consistent with the
2004      * DEM and if any other specific rules apply.
2005      * 
2006      * @param clazz
2007      *            the class on which the annotation is used
2008      * @throws AnnotationMisuseException
2009      *             if an inappropriate annotation usage was made
2010      * @throws ResourceNotFoundException
2011      *             if any resource needed for the validation can't be found
2012      */
2013     final public void validateUsage(ClassHolder clazz) throws AnnotationMisuseException, ResourceNotFoundException
2014     {
2015         validatePrimary(clazz);
2016         // validateScope(clazz);
2017         validateDEMConsistency(annotationName, clazz);
2018         validateSpecificRules(annotationName, clazz);
2019     }
2020 
2021     /**
2022      * Validates the use of the annotation on a given method. Validation includes checking if multiple primary
2023      * annotations are used, if the scope is correct and if any other specific rules apply.
2024      * 
2025      * @param method
2026      *            the method on which the annotation is used
2027      * @throws AnnotationMisuseException
2028      *             if an inappropriate annotation usage was made
2029      * @throws ResourceNotFoundException
2030      *             if any resource needed for the validation can't be found
2031      */
2032     final public void validateUsage(MethodHolder method) throws AnnotationMisuseException, ResourceNotFoundException
2033     {
2034         validatePrimary(method);
2035         // validateScope(method);
2036         validateSpecificRules(annotationName, method);
2037     }
2038 
2039     /**
2040      * Checks if the received set of annotations contains the
2041      * 
2042      * @View annotation and if the referenced view exists. Logs a warning if the view doesn't exist.
2043      * @param attributeName
2044      *            the name of the annotated attribute if it exists
2045      * @param className
2046      *            the name of the annotated class or the attribute's class name
2047      * @param annotations
2048      *            the annotation set to validate
2049      * @throws ResourceNotFoundException
2050      *             if any resource needed for the validation can't be found
2051      */
2052     protected void validateViewExistence(String attributeName, String className,
2053             Map<String, AnnotationHolder> annotations) throws ResourceNotFoundException
2054     {
2055         AnnotationHolder theAnnotation = null;
2056 
2057         if (View.class.getCanonicalName().contains(annotationName)
2058                 && annotations.containsKey(View.class.getCanonicalName()))
2059         {
2060             theAnnotation = annotations.get(View.class.getCanonicalName());
2061 
2062             String target = theAnnotation.getMembers().get(TARGET_ATTRIBUTE_NAME).toString();
2063 
2064             URL view = this.getClass().getClassLoader().getResource(target);
2065 
2066             if (view == null)
2067             {
2068                 if (attributeName != null)
2069                 {
2070                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.WARN, IssueScope.LOADTIME, className,
2071                             "Attribute " + attributeName + " refers to inexistant view: " + target, null);
2072                 }
2073                 else
2074                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.WARN, IssueScope.LOADTIME, className,
2075                             "Class refers to inexistant view: " + target, null);
2076             }
2077         }
2078     }
2079 
2080     /**
2081      * Warns of an entity misuse on a given class.
2082      * 
2083      * @param className
2084      *            the name of the class where the reference is being made
2085      * @param entityName
2086      *            the name of the referred entity
2087      */
2088     protected void warnOfEnityMisuseOnClass(String className, String entityName)
2089     {
2090         UsageIssuesManagerImpl.getInstance().addIssue(IssueType.WARN, IssueScope.LOADTIME, className,
2091                 "Class refers to an inexistant DEM entity: " + entityName, null);
2092     }
2093 
2094     /**
2095      * Checks if a given primary annotation has the 'yieldTo' member value and if it contains a given annotation name.
2096      * 
2097      * @param annotation
2098      *            the primary annotation to check
2099      * @param yieldToAnnotationName
2100      *            the name on the 'yieldTo' value
2101      * @return T if the primary annotation yields to the passed name, F otherwise
2102      */
2103     protected boolean yieldsTo(AnnotationHolder annotation, String yieldToAnnotationName)
2104     {
2105 
2106         try
2107         {
2108             AnnotationHolder primaryMetaAnnotation = annotation.getMetaAnnotations().get(
2109                     Primary.class.getCanonicalName());
2110 
2111             if (primaryMetaAnnotation.getMembers().get(MetaAnnotationMemberTags.PRIMARY_YIELD_TO).toString()
2112                     .contains(yieldToAnnotationName))
2113             {
2114                 return true;
2115             }
2116 
2117         }
2118         catch (ResourceNotFoundException resourceNotFoundException)
2119         {
2120 
2121         }
2122 
2123         return false;
2124     }
2125 }