View Javadoc

1   /**
2    * - Digitalis Internal Framework v2.0 - (C) 2007, Digitalis Informatica. Distribuicao e Gestao de Informatica, Lda.
3    * Estrada de Paco de Arcos num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999
4    * http://www.digitalis.pt
5    */
6   package pt.digitalis.dif.codegen.util;
7   
8   import java.util.ArrayList;
9   import java.util.Arrays;
10  import java.util.Collection;
11  import java.util.List;
12  import java.util.Map;
13  
14  import pt.digitalis.dif.codegen.CGAncillaries;
15  import pt.digitalis.dif.controller.ExceptionHandlers;
16  import pt.digitalis.dif.controller.security.managers.IAuthorizationManager;
17  import pt.digitalis.dif.controller.security.managers.IIdentityManager;
18  import pt.digitalis.dif.controller.security.objects.IDIFGroup;
19  import pt.digitalis.dif.controller.security.objects.IDIFUser;
20  import pt.digitalis.dif.dem.DEMAnnotationLogic;
21  import pt.digitalis.dif.dem.Entity;
22  import pt.digitalis.dif.dem.annotations.AnnotationMemberTags;
23  import pt.digitalis.dif.dem.annotations.AnnotationTags;
24  import pt.digitalis.dif.dem.annotations.Registrable;
25  import pt.digitalis.dif.dem.annotations.parameter.BindParameterIDs;
26  import pt.digitalis.dif.dem.annotations.parameter.FormConfigurable;
27  import pt.digitalis.dif.dem.annotations.parameter.Parameter;
28  import pt.digitalis.dif.dem.annotations.parameter.Persist;
29  import pt.digitalis.dif.dem.annotations.parameter.Rule;
30  import pt.digitalis.dif.dem.annotations.parameter.Rules;
31  import pt.digitalis.dif.dem.annotations.security.AccessControl;
32  import pt.digitalis.dif.dem.annotations.security.Group;
33  import pt.digitalis.dif.dem.annotations.security.Groups;
34  import pt.digitalis.dif.dem.annotations.security.User;
35  import pt.digitalis.dif.dem.annotations.security.Users;
36  import pt.digitalis.dif.dem.annotations.stage.ExceptionHandler;
37  import pt.digitalis.dif.dem.managers.IParameterManager;
38  import pt.digitalis.dif.dem.managers.IRegistrationManager;
39  import pt.digitalis.dif.dem.managers.impl.UsageIssuesManagerImpl;
40  import pt.digitalis.dif.dem.objects.issues.IssueScope;
41  import pt.digitalis.dif.dem.objects.issues.IssueType;
42  import pt.digitalis.dif.dem.objects.issues.UsageIssue;
43  import pt.digitalis.dif.dem.objects.parameters.IParameter;
44  import pt.digitalis.dif.dem.objects.parameters.ParameterList;
45  import pt.digitalis.dif.dem.objects.parameters.ParameterScope;
46  import pt.digitalis.dif.dem.objects.parameters.constraints.impl.ParameterConstraintRegexImpl;
47  import pt.digitalis.dif.dem.objects.parameters.rules.IParameterRule;
48  import pt.digitalis.dif.dem.objects.parameters.rules.ParameterRuleAction;
49  import pt.digitalis.dif.exception.InternalFrameworkException;
50  import pt.digitalis.dif.exception.codegen.DIFCodeGenerationException;
51  import pt.digitalis.dif.exception.objects.ParameterException;
52  import pt.digitalis.dif.exception.security.AuthorizationManagerException;
53  import pt.digitalis.dif.exception.security.IdentityManagerException;
54  import pt.digitalis.dif.ioc.DIFIoCRegistry;
55  import pt.digitalis.dif.utils.logging.DIFLogger;
56  import pt.digitalis.utils.bytecode.exceptions.CodeGenerationException;
57  import pt.digitalis.utils.bytecode.holders.AnnotationHolder;
58  import pt.digitalis.utils.bytecode.holders.AnnotationMemberValueHolder;
59  import pt.digitalis.utils.bytecode.holders.AttributeHolder;
60  import pt.digitalis.utils.bytecode.holders.ClassHolder;
61  import pt.digitalis.utils.bytecode.holders.MethodHolder;
62  import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
63  
64  import com.google.inject.Inject;
65  
66  /**
67   * An implementation of the IClassEnhancer that uses Bytecode Utils to enhance the classes.
68   * 
69   * @author Rodrigo Gon�alves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
70   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
71   * @created Jul 5, 2007
72   */
73  /**
74   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a><br/>
75   * @created 17 de Mar de 2011
76   */
77  /**
78   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a><br/>
79   * @created 17 de Mar de 2011
80   */
81  public class ClassEnhancerImpl implements IClassEnhancer {
82  
83      /** Default password for new users */
84      private static final String DEFAULT_PASSWORD = "@bcd1234";
85  
86      /** Map of all annotations and their corresponding Logic objects */
87      private Map<String, DEMAnnotationLogic> annotationLogicMap = null;
88  
89      /** The authorization manager */
90      private final IAuthorizationManager authorizationManager;
91  
92      /** The identity manager */
93      private final IIdentityManager identityManager;
94  
95      /** The parameter manager */
96      private final IParameterManager parameterManager;
97  
98      /** The registration manager */
99      private final IRegistrationManager registrationManager;
100 
101     /**
102      * Constructor.
103      * 
104      * @param registrationManager
105      *            the registration manager instance
106      * @param parameterManager
107      *            the parameter manager instance
108      * @param identityManager
109      *            the identity manager instance
110      * @param authorizationManager
111      *            the authorization manager instance
112      * @throws CodeGenerationException
113      *             if the needed resources for class enhancement could not be properly initialized
114      */
115     @Inject
116     public ClassEnhancerImpl(IRegistrationManager registrationManager, IParameterManager parameterManager,
117             IIdentityManager identityManager, IAuthorizationManager authorizationManager)
118             throws CodeGenerationException
119     {
120 
121         this.registrationManager = registrationManager;
122         this.parameterManager = parameterManager;
123         this.identityManager = identityManager;
124         this.authorizationManager = authorizationManager;
125 
126         try
127         {
128             annotationLogicMap = DEMLoaderHelper.getAnnotationLogicMap();
129 
130         }
131         catch (Exception exception)
132         {
133             throw new CodeGenerationException("Could not properly initialize resources ", exception);
134         }
135     }
136 
137     /**
138      * Enhances the methods of a given class.
139      * 
140      * @param classEnhancementContext
141      *            the class enhancement context
142      * @throws ResourceNotFoundException
143      *             if class can not be loaded
144      * @throws CodeGenerationException
145      *             if class can not be enhanced
146      * @throws DIFCodeGenerationException
147      */
148     private void enhaceMethods(ClassEnhancementContext classEnhancementContext) throws ResourceNotFoundException,
149             CodeGenerationException, DIFCodeGenerationException
150     {
151 
152         ClassHolder clazz = classEnhancementContext.getOriginalClassObject();
153 
154         for (MethodHolder method: clazz.getAllMethods().values())
155         {
156 
157             Collection<AnnotationHolder> annotations = method.getAnnotations().values();
158 
159             // If there are annotations to process (method can have no
160             // annotations!)
161             if (annotations != null && annotations.size() > 0)
162             {
163 
164                 for (AnnotationHolder annotation: annotations)
165                 {
166 
167                     // ...get it's associated object...
168                     DEMAnnotationLogic annotationLogic = annotationLogicMap.get(annotation.getName());
169                     // ...if the object exists...
170                     if (annotationLogic != null)
171                     {
172                         // if annotation usage is correct process it!
173                         annotationLogic.validateUsage(method);
174                         processAnnotation(classEnhancementContext, method, annotation, annotationLogic);
175                     }
176                     else
177                         DIFLogger.getLogger().debug(
178                                 "Annotation @" + annotation.getName()
179                                         + " has no AnnotationLogicClass defined. Skipping...");
180                 }
181             }
182         }
183     }
184 
185     /**
186      * Reads and iterates over the class annotations, processing them according to their target scope.
187      * 
188      * @see pt.digitalis.dif.codegen.util.IClassEnhancer#enhance(ClassHolder)
189      */
190     public ClassHolder enhance(ClassHolder clazz) throws ResourceNotFoundException, CodeGenerationException,
191             DIFCodeGenerationException
192     {
193 
194         ClassEnhancementContext classEnhancementContext = new ClassEnhancementContext(clazz);
195 
196         enhanceClass(classEnhancementContext);
197         enhanceAttributes(classEnhancementContext);
198         enhaceMethods(classEnhancementContext);
199 
200         postProcessActions(classEnhancementContext);
201 
202         // Commit changes
203         classEnhancementContext.commitEnhancements();
204 
205         return classEnhancementContext.getEntityClass();
206     }
207 
208     /**
209      * Enhances the attributes of a given class.
210      * 
211      * @param classEnhancementContext
212      *            the class enhancement context
213      * @throws ResourceNotFoundException
214      *             if class can not be loaded
215      * @throws CodeGenerationException
216      *             if class can not be enhanced
217      * @throws DIFCodeGenerationException
218      */
219     private void enhanceAttributes(ClassEnhancementContext classEnhancementContext) throws ResourceNotFoundException,
220             CodeGenerationException, DIFCodeGenerationException
221     {
222 
223         ClassHolder clazz = classEnhancementContext.getOriginalClassObject();
224 
225         // For each attribute...
226         for (AttributeHolder attribute: clazz.getAttributes().values())
227         {
228             // For each annotation...
229             for (AnnotationHolder annotation: attribute.getAnnotations().values())
230             {
231                 // ...get it's associated object...
232                 DEMAnnotationLogic annotationLogic = annotationLogicMap.get(annotation.getName());
233                 // ...if the object exists...
234                 if (annotationLogic != null)
235                 {
236                     // if annotation usage is correct process it!
237                     annotationLogic.validateUsage(attribute);
238                     processAnnotation(classEnhancementContext, attribute, annotation, annotationLogic);
239                 }
240                 else
241                     DIFLogger.getLogger()
242                             .debug("Annotation @" + annotation.getName()
243                                     + " has no AnnotationLogicClass defined. Skipping...");
244             }
245         }
246     }
247 
248     /**
249      * Enhances a given class. Analyzes class annotations and implements the needed interfaces and methods according.
250      * 
251      * @param classEnhancementContext
252      *            the class enhancement context
253      * @throws ResourceNotFoundException
254      *             if class can not be loaded
255      * @throws CodeGenerationException
256      *             if class can not be enhanced
257      * @throws DIFCodeGenerationException
258      */
259     private void enhanceClass(ClassEnhancementContext classEnhancementContext) throws ResourceNotFoundException,
260             CodeGenerationException, DIFCodeGenerationException
261     {
262 
263         ClassHolder clazz = classEnhancementContext.getOriginalClassObject();
264 
265         for (AnnotationHolder annotation: clazz.getAnnotations().values())
266         {
267             DEMAnnotationLogic annotationLogic = annotationLogicMap.get(annotation.getName());
268 
269             // ...if the object exists...
270             if (annotationLogic != null)
271             {
272                 // if annotation usage is correct process it!
273                 annotationLogic.validateUsage(clazz);
274                 processAnnotation(classEnhancementContext, annotation, annotationLogic);
275             }
276             else
277                 DIFLogger.getLogger().debug(
278                         "Annotation @" + annotation.getName() + " has no AnnotationLogicClass defined. Skipping...");
279         }
280     }
281 
282     /**
283      * Infers a given {@link Rule} annotation to a {@link IParameterRule} object
284      * 
285      * @param parameterID
286      *            the id of the associated stage parameter
287      * @param ruleAnnotation
288      *            the rule annotation
289      * @return the converted {@link IParameterRule}
290      * @throws ResourceNotFoundException
291      */
292     private IParameterRule<?> getRule(String parameterID, AnnotationHolder ruleAnnotation)
293             throws ResourceNotFoundException
294     {
295 
296         IParameterRule<?> paramRule = null;
297 
298         if (ruleAnnotation != null)
299         {
300             String ruleID = null;
301             String ruleParameters = null;
302             ParameterRuleAction ruleAction = ParameterRuleAction.HIDE;
303 
304             Map<String, AnnotationMemberValueHolder> ruleValues = ruleAnnotation.getMembers();
305 
306             AnnotationMemberValueHolder temp;
307 
308             // Override default from the declared parameters in @Persist
309             temp = ruleValues.get(AnnotationMemberTags.RULE_ID);
310 
311             if (temp != null)
312             {
313                 ruleID = temp.toString();
314 
315                 temp = ruleValues.get(AnnotationMemberTags.RULE_PARAMETER_LIST);
316 
317                 if (temp != null)
318                 {
319                     ruleParameters = temp.toString();
320 
321                     temp = ruleValues.get(AnnotationMemberTags.RULE_ACTION);
322 
323                     if (temp != null && temp.enumValuetoString() != null)
324                         ruleAction = ParameterRuleAction.valueOf(temp.enumValuetoString());
325 
326                     String value = ruleValues.get(AnnotationMemberTags.RULE_VALUE).toString();
327                     String first = ruleValues.get(AnnotationMemberTags.RULE_FIRST).toString();
328                     String last = ruleValues.get(AnnotationMemberTags.RULE_LAST).toString();
329 
330                     if (AnnotationTags.NONE.equals(value))
331                         value = null;
332 
333                     if (AnnotationTags.NONE.equals(first))
334                         first = null;
335 
336                     if (AnnotationTags.NONE.equals(last))
337                         last = null;
338 
339                     paramRule = DIFIoCRegistry.getRegistry().getImplementation(IParameterRule.class, ruleID);
340 
341                     if (paramRule != null)
342                         paramRule.init(parameterID, ruleParameters, ruleAction, value, first, last);
343                 }
344             }
345         }
346 
347         return paramRule;
348     }
349 
350     /**
351      * Post processing actions. Will analize the current DEm entity, with their processed annotations and perform
352      * context analisys and code generation
353      * 
354      * @param classEnhancementContext
355      * @throws ResourceNotFoundException
356      */
357     private void postProcessActions(ClassEnhancementContext classEnhancementContext) throws ResourceNotFoundException
358     {
359 
360         String entityID = EntityUtils.getEntityID(classEnhancementContext.getOriginalClassObject());
361         Entity entityType = EntityUtils.getEntityType(classEnhancementContext.getOriginalClassObject());
362 
363         if (entityType != Entity.VALIDATOR)
364         {
365             ParameterList parameters = parameterManager.getParameters(entityType, entityID);
366 
367             // Parse all current entity parameters and each of their optional rules. for each set the dependent
368             // parameter ReferencedInAnotherRule parameter
369             if (parameters != null)
370                 for (IParameter<?> parameter: parameters.getParameters().values())
371                     for (IParameterRule<?> rule: parameter.getRules())
372                         for (String dependentParameterId: rule.getParameters())
373                         {
374 
375                             IParameter<?> param = parameters.getParameter(dependentParameterId.trim());
376 
377                             if (param == null)
378                             {
379                                 UsageIssue issue = new UsageIssue();
380                                 issue.setIssueScope(IssueScope.LOADTIME);
381                                 issue.setIssueType(IssueType.ERROR);
382                                 issue.setIssueDescription("The parameter " + dependentParameterId.trim()
383                                         + " referenced in a @Rule of the parameter " + parameter.getId()
384                                         + " does not exist in the stage");
385                                 issue.setLocation(classEnhancementContext.getOriginalClassObject().getFQName());
386 
387                                 UsageIssuesManagerImpl.getInstance().addIssue(issue);
388                             }
389                             else
390                                 param.setReferencedInARuleFromAnotherParameter(true);
391                         }
392         }
393     }
394 
395     /**
396      * @see pt.digitalis.dif.codegen.util.IClassEnhancer#processAnnotation(pt.digitalis.dif.codegen.util.ClassEnhancementContext,
397      *      pt.digitalis.utils.bytecode.holders.AnnotationHolder, pt.digitalis.dif.dem.DEMAnnotationLogic)
398      */
399     public void processAnnotation(ClassEnhancementContext classEnhancementContext, AnnotationHolder annotation,
400             DEMAnnotationLogic annotationLogic) throws ResourceNotFoundException, CodeGenerationException,
401             DIFCodeGenerationException
402     {
403 
404         String annotationName = annotation.getName();
405 
406         ClassHolder clazz = classEnhancementContext.getOriginalClassObject();
407 
408         // *** Process behavior-triggering annotations ***
409 
410         if (annotationName.equals(ExceptionHandler.class.getCanonicalName()))
411         {
412             String[] exceptions = CGAncillaries.parse(
413                     annotation.getMembers().get(AnnotationMemberTags.ERROR_STAGE_EXCEPTIONS).toString(),
414                     CGAncillaries.COMMA);
415 
416             for (int i = 0; i < exceptions.length; i++)
417                 ExceptionHandlers.addExceptionHandler(exceptions[i], EntityUtils.getEntityID(clazz));
418 
419         }
420         else if (annotationName.equals(Registrable.class.getCanonicalName()))
421         {
422 
423             Entity entityType = EntityUtils.getEntityType(clazz);
424             String entityID = EntityUtils.getEntityID(clazz);
425             String defaultName = annotation.getMembers().get("defaultRegisterName").toString();
426 
427             if (entityType != null)
428             {
429                 // No default name means an unregistered but registrable registration.
430                 // Inaccessible until a valid registration occurs.
431 
432                 // A default name will force a non-registrable so it can be accessed with the default name.
433                 if (defaultName.equals(AnnotationTags.NONE))
434                     defaultName = "";
435 
436                 registrationManager.addToRegistry(entityType, entityID, defaultName, "".equals(defaultName));
437             }
438         }
439         else if (annotationName.equals(BindParameterIDs.class.getCanonicalName()))
440         {
441             // Parse String to array
442             // String[] parametersIDs =
443             // CGAncillaries.parse(annotation.getMembers().get("ids").toString(),
444             // ",");
445 
446             // TODO: call the appropriate method on the ValidatorManager
447             // Throw UnsupportedOpertationException to comply with Java
448             // standards and warn user of unimplemented
449             // feature.
450             throw new UnsupportedOperationException(annotationName + " not yet supported! Please remove it from class "
451                     + clazz.getFQName());
452 
453         }
454         else if (annotationName.equals(Users.class.getCanonicalName()))
455         {
456             for (AnnotationHolder innerUser: annotation.getMembers().get(AnnotationMemberTags.VALUE)
457                     .toAnnotationList(clazz))
458                 processUserAnnotation(clazz, innerUser);
459 
460         }
461         else if (annotationName.equals(Groups.class.getCanonicalName()))
462         {
463             for (AnnotationHolder innerGroup: annotation.getMembers().get(AnnotationMemberTags.VALUE)
464                     .toAnnotationList(clazz))
465             {
466                 processGroupAnnotation(clazz, innerGroup);
467             }
468 
469         }
470 
471         else if (annotationName.equals(User.class.getCanonicalName()))
472         {
473             processUserAnnotation(clazz, annotation);
474 
475         }
476         else if (annotationName.equals(Group.class.getCanonicalName()))
477         {
478             processGroupAnnotation(clazz, annotation);
479 
480         }
481         else if (annotationName.equals(AccessControl.class.getCanonicalName()))
482         {
483 
484             // Get the parent info
485             Entity entityType = EntityUtils.getEntityType(clazz);
486             String entityID = EntityUtils.getEntityID(clazz);
487 
488             if (entityType.equals(Entity.APPLICATION) || entityType.equals(Entity.SERVICE)
489                     || entityType.equals(Entity.STAGE))
490             {
491                 // Get the parameters of the annotation
492                 String[] userIDs = CGAncillaries.parse(annotation.getMembers().get("users").toString(), ",");
493                 String[] groupIDs = CGAncillaries.parse(annotation.getMembers().get("groups").toString(), ",");
494                 boolean accessToNone = annotation.getMembers().get("none").toBoolean();
495 
496                 if (userIDs.length == 0 || userIDs[0].equals(""))
497                     userIDs = new String[0];
498                 if (groupIDs.length == 0 || groupIDs[0].equals(""))
499                     groupIDs = new String[0];
500 
501                 try
502                 {
503                     for (String userID: userIDs)
504                     {
505                         // Parse the user id and profile, using the notation:
506                         // "userID:profileID, userID2:profileID2..."
507                         String[] userData = CGAncillaries.parse(userID, ":");
508 
509                         if (!identityManager.userExists(userData[0]))
510                         {
511 
512                             if (userData.length < 2)
513                             {
514                                 throw new DIFCodeGenerationException(
515                                         "The annotation AccessControl must declare a user with a valid profile. Configuration: "
516                                                 + annotation.getMembers().get("users").toString());
517                             }
518 
519                             if (!identityManager.groupExists(userData[1]))
520                             {
521                                 IDIFGroup group = DIFIoCRegistry.getRegistry().getImplementation(IDIFGroup.class);
522                                 group.setID(userData[1]);
523                                 group.setName(userData[1]);
524 
525                                 identityManager.addGroup(group);
526                             }
527 
528                             IDIFUser user = DIFIoCRegistry.getRegistry().getImplementation(IDIFUser.class);
529                             user.setID(userData[0]);
530                             user.setName(userData[0]);
531                             user.setNick(userData[0]);
532                             user.setPassword(userData[0]);
533                             user.setProfileID(userData[1]);
534 
535                             identityManager.addUser(user);
536                         }
537 
538                         authorizationManager.grantDefaultAccessToUser(userData[0], entityType, entityID);
539                     }
540 
541                     for (String groupID: groupIDs)
542                     {
543                         if (!identityManager.groupExists(groupID))
544                         {
545                             IDIFGroup group = DIFIoCRegistry.getRegistry().getImplementation(IDIFGroup.class);
546                             group.setID(groupID);
547                             group.setName(groupID);
548 
549                             identityManager.addGroup(group);
550                         }
551 
552                         authorizationManager.grantDefaultAccessToGroup(groupID, entityType, entityID);
553                     }
554                 }
555                 catch (IdentityManagerException identityManagerException)
556                 {
557                     if (identityManager.isReadOnly())
558                         DIFLogger.getLogger().info("Identity Manager in Read Only mode.");
559                     else
560                         DIFLogger.getLogger().warn(
561                                 "Could not access the identity manager!" + identityManagerException.getMessage());
562                 }
563                 catch (AuthorizationManagerException authorizationManagerException)
564                 {
565                     throw new ResourceNotFoundException("Could not access the authorization manager!",
566                             authorizationManagerException);
567                 }
568 
569                 if (accessToNone)
570                     authorizationManager.revokeAccessFromPublic(entityType, entityID);
571 
572             }
573         }
574         // *** Process code generation annotations ***
575         else
576             // Get the source code for the annotation
577             annotationLogic.addSourceCodeForAnnotation(annotation, classEnhancementContext);
578     }
579 
580     /**
581      * @see pt.digitalis.dif.codegen.util.IClassEnhancer#processAnnotation(pt.digitalis.dif.codegen.util.ClassEnhancementContext,
582      *      pt.digitalis.utils.bytecode.holders.AttributeHolder, pt.digitalis.utils.bytecode.holders.AnnotationHolder,
583      *      pt.digitalis.dif.dem.DEMAnnotationLogic)
584      */
585     @SuppressWarnings("unchecked")
586     public void processAnnotation(ClassEnhancementContext classEnhancementContext, AttributeHolder attribute,
587             AnnotationHolder annotation, DEMAnnotationLogic annotationLogic) throws ResourceNotFoundException,
588             CodeGenerationException, DIFCodeGenerationException
589     {
590 
591         // *** Process behavior-triggering annotations ***
592 
593         String annotationName = annotation.getName();
594         boolean generateSourceCode = true;
595 
596         // The following section implements the following annotations:
597         // Parameter, Persist, Validator
598         if (annotationName.equals(Parameter.class.getCanonicalName()))
599         {
600             Map<String, AnnotationMemberValueHolder> paramValues = annotation.getMembers();
601 
602             String id = paramValues.get(AnnotationMemberTags.PARAMETER_ID).toString();
603             String constraints = paramValues.get(AnnotationMemberTags.PARAMETER_CONSTRAINTS).toString();
604             String defaultValue = paramValues.get(AnnotationMemberTags.PARAMETER_DEFAULT_VALUE).toString();
605             String linkForm = paramValues.get(AnnotationMemberTags.PARAMETER_LINK_TO_FORM).toString();
606             String[] regexp = paramValues.get(AnnotationMemberTags.PARAMETER_REGEXP_VALUE).toStringArray();
607 
608             // No id given, use the attribute name to lowercase
609             if (id.equals(AnnotationTags.GENERATE_ID))
610                 id = attribute.getName().toLowerCase();
611 
612             // No constraints identifier, set to empty constraint string
613             if (constraints.equals(AnnotationTags.NONE))
614                 constraints = "";
615 
616             if (regexp.length == 1)
617             {
618                 if (constraints.length() > 0)
619                     constraints += ",";
620                 constraints += "regex=" + regexp[0];
621             }
622             else if (regexp.length == 2)
623             {
624                 if (constraints.length() > 0)
625                     constraints += ",";
626 
627                 constraints += "regex=" + ParameterConstraintRegexImpl.REGEXP_LIST_START
628                         + regexp[0].replaceAll(",", ParameterConstraintRegexImpl.REGEXP_COMMA)
629                         + ParameterConstraintRegexImpl.REGEXP_LIST_SEPARATOR
630                         + regexp[1].replaceAll(",", ParameterConstraintRegexImpl.REGEXP_COMMA)
631                         + ParameterConstraintRegexImpl.REGEXP_LIST_END;
632             }
633             else if (regexp.length > 2)
634             {
635                 UsageIssuesManagerImpl.getInstance().addIssue(
636                         IssueType.ERROR,
637                         IssueScope.LOADTIME,
638                         classEnhancementContext.getOriginalClassObject().getFQName(),
639                         "Parameter \"" + annotation.getParentAttribute().getName()
640                                 + "\" has more than 2 regular expressions associated. "
641                                 + "Must have one if common for java and JavaScript or two, if diferent. "
642                                 + "More that two is a configuration error. All regular expressions will be ignored!\"",
643                         null);
644             }
645 
646             // No default value, set to empty string
647             if (defaultValue.equals(AnnotationTags.NONE))
648                 defaultValue = "";
649 
650             // No form to link, set to null
651             if (linkForm.equals(AnnotationTags.NONE))
652                 linkForm = null;
653 
654             // Defaults - Persist
655             ParameterScope scope = ParameterScope.REQUEST;
656             boolean persistentToRepository = false;
657             boolean formConfigurable = false;
658             boolean allowAnonymous = false;
659 
660             // Check for the persist annotation
661             AnnotationHolder persistAnnotation = annotation.getParentAttribute().getAnnotations()
662                     .get(Persist.class.getCanonicalName());
663 
664             if (persistAnnotation != null)
665             {
666 
667                 Map<String, AnnotationMemberValueHolder> persistValues = persistAnnotation.getMembers();
668 
669                 // Override default from the declared parameters in @Persist
670                 scope = ParameterScope.valueOf(persistValues.get(AnnotationMemberTags.PERSIST_SCOPE)
671                         .enumValuetoString());
672                 persistentToRepository = persistValues.get(AnnotationMemberTags.PERSIST_REPOSITORY).toBoolean();
673                 allowAnonymous = persistValues.get(AnnotationMemberTags.PERSIST_ALLOW_ANONYMOUS).toBoolean();
674 
675                 // TODO: Implement this. Wait for the User/Group Manager
676                 // String groupVisibility =
677                 // persistValues.get(AnnotationMemberTags.PERSIST_GROUP_VISIBILITY).toString();
678             }
679 
680             // Check for the formConfigurable annotation
681             formConfigurable = annotation.getParentAttribute().getAnnotations()
682                     .get(FormConfigurable.class.getCanonicalName()) != null;
683 
684             // Defaults - Rule
685             List<IParameterRule<?>> rules = new ArrayList<IParameterRule<?>>();
686             boolean ruleWithError = false;
687 
688             // Check for the rule annotation
689             AnnotationHolder ruleAnnotation = annotation.getParentAttribute().getAnnotations()
690                     .get(Rule.class.getCanonicalName());
691 
692             if (ruleAnnotation != null)
693             {
694                 IParameterRule<?> rule = getRule(id, ruleAnnotation);
695                 if (rule != null)
696                     rules.add(rule);
697                 else
698                     ruleWithError = true;
699             }
700 
701             // Check for the rules annotation
702             AnnotationHolder rulesAnnotation = annotation.getParentAttribute().getAnnotations()
703                     .get(Rules.class.getCanonicalName());
704 
705             if (rulesAnnotation != null)
706                 for (AnnotationHolder innerRule: rulesAnnotation.getMembers().get(AnnotationMemberTags.VALUE)
707                         .toAnnotationList(attribute))
708                 {
709                     IParameterRule<?> rule = getRule(id, innerRule);
710                     if (rule != null)
711                         rules.add(rule);
712                     else
713                         ruleWithError = true;
714                 }
715 
716             // TODO: Implement @Validator
717 
718             @SuppressWarnings("rawtypes")
719             IParameter param = parameterManager.getParameterInstanceForType(annotation.getParentAttribute()
720                     .getAttributeType());
721 
722             if (param == null)
723             {
724                 generateSourceCode = false;
725                 UsageIssuesManagerImpl.getInstance().addIssue(
726                         IssueType.ERROR,
727                         IssueScope.LOADTIME,
728                         classEnhancementContext.getOriginalClassObject().getFQName(),
729                         "Parameter \"" + annotation.getParentAttribute().getName() + "\" has an unsupported type \""
730                                 + annotation.getParentAttribute().getAttributeType() + "\"", null);
731             }
732             else
733             {
734                 Entity parentType = EntityUtils.getEntityType(attribute.getParentClass());
735                 String parentID = EntityUtils.getEntityID(attribute.getParentClass());
736 
737                 if (ruleWithError)
738                 {
739                     UsageIssuesManagerImpl.getInstance().addIssue(IssueType.ERROR, IssueScope.LOADTIME,
740                             classEnhancementContext.getOriginalClassObject().getFQName(),
741                             "Parameter \"" + annotation.getParentAttribute().getName() + "\" has an unsupported rule",
742                             null);
743                 }
744 
745                 try
746                 {
747                     param.initialize(id, parentType, parentID, formConfigurable, persistentToRepository,
748                             allowAnonymous, scope, defaultValue, constraints, null, rules);
749                     param.setFormLinked(linkForm);
750                     parameterManager.registerParameter(param);
751 
752                 }
753                 catch (ParameterException e)
754                 {
755                     // Exception initializing the parameter. This parameter will be
756                     // unavailable.
757                     generateSourceCode = false;
758                 }
759 
760                 // Only generate initialization code if it is a stage. If on another
761                 // entity it will only declare the
762                 // parameter and not inject it
763                 generateSourceCode = (parentType == Entity.STAGE);
764             }
765         }
766 
767         // If the code generation has not been overridden with a
768         // behavior-triggering annotation generate it
769         if (generateSourceCode)
770             annotationLogic.addSourceCodeForAnnotation(classEnhancementContext, annotation, attribute);
771     }
772 
773     /**
774      * @see pt.digitalis.dif.codegen.util.IClassEnhancer#processAnnotation(pt.digitalis.dif.codegen.util.ClassEnhancementContext,
775      *      pt.digitalis.utils.bytecode.holders.MethodHolder, pt.digitalis.utils.bytecode.holders.AnnotationHolder,
776      *      pt.digitalis.dif.dem.DEMAnnotationLogic)
777      */
778     public void processAnnotation(ClassEnhancementContext classEnhancementContext, MethodHolder method,
779             AnnotationHolder annotation, DEMAnnotationLogic annotationLogic) throws ResourceNotFoundException,
780             CodeGenerationException, DIFCodeGenerationException
781     {
782 
783         // Get the source code for the annotation
784         annotationLogic.addSourceCodeForAnnotation(classEnhancementContext, annotation, method);
785     }
786 
787     /**
788      * Process the Group annotation
789      * 
790      * @param clazz
791      *            the class instance
792      * @param annotation
793      *            the annotation to process
794      * @throws ResourceNotFoundException
795      */
796     private void processGroupAnnotation(ClassHolder clazz, AnnotationHolder annotation)
797             throws ResourceNotFoundException
798     {
799         // Get the parent info
800         Entity entityType = EntityUtils.getEntityType(clazz);
801 
802         if (!identityManager.isReadOnly() && entityType.equals(Entity.APPLICATION))
803         {
804             String groupName = annotation.getMembers().get("groupName").toString();
805 
806             try
807             {
808                 if (!identityManager.groupExists(groupName))
809                 {
810                     String fullName = annotation.getMembers().get("fullName").toString();
811                     String groupParent = annotation.getMembers().get("groupParent").toString();
812 
813                     // Set dynamic default values...
814                     if ("".equals(fullName))
815                         fullName = groupName;
816 
817                     // Check for parent group...
818                     if (!"".equals(groupParent) && !identityManager.groupExists(groupParent))
819                     {
820                         IDIFGroup group = DIFIoCRegistry.getRegistry().getImplementation(IDIFGroup.class);
821                         group.setID(groupParent);
822                         group.setName(groupParent);
823                         group.setDescription(groupParent);
824                         group.setDefault(true);
825 
826                         identityManager.addGroup(group);
827                     }
828 
829                     // Create the group
830                     IDIFGroup group = DIFIoCRegistry.getRegistry().getImplementation(IDIFGroup.class);
831                     group.setID(groupName);
832                     group.setName(groupName);
833                     group.setDescription(fullName);
834 
835                     if (!"".equals(groupParent))
836                         group.setParentGroupID(groupParent);
837 
838                     group.setDefault(true);
839 
840                     identityManager.addGroup(group);
841                 }
842             }
843             catch (IdentityManagerException identityManagerException)
844             {
845                 if (identityManager.isReadOnly())
846                     DIFLogger.getLogger().info("Identity Manager in Read Only mode.");
847                 else
848                     DIFLogger.getLogger().warn(
849                             "Could not access the identity manager!" + identityManagerException.getMessage());
850             }
851         }
852 
853     }
854 
855     /**
856      * Process the User annotation
857      * 
858      * @param clazz
859      *            the class instance
860      * @param annotation
861      *            the annotation to process
862      * @throws ResourceNotFoundException
863      */
864     private void processUserAnnotation(ClassHolder clazz, AnnotationHolder annotation) throws ResourceNotFoundException
865     {
866         // Get the parent info
867         Entity entityType = EntityUtils.getEntityType(clazz);
868 
869         if (!identityManager.isReadOnly() && entityType.equals(Entity.APPLICATION))
870         {
871             String userName = annotation.getMembers().get("userName").toString();
872 
873             try
874             {
875                 // If the user does not already exist...
876                 if (!identityManager.userExists(userName))
877                 {
878                     String password = annotation.getMembers().get("password").toString();
879                     String fullName = annotation.getMembers().get("fullName").toString();
880                     String nick = annotation.getMembers().get("nick").toString();
881                     String email = annotation.getMembers().get("email").toString();
882                     String profile = annotation.getMembers().get("profile").toString();
883 
884                     // Set dynamic default values...
885                     if ("".equals(password))
886                         password = DEFAULT_PASSWORD;
887 
888                     if ("".equals(fullName))
889                         fullName = userName;
890 
891                     if ("".equals(nick))
892                         nick = userName;
893 
894                     if ("".equals(email))
895                         email = userName + "@domain.com";
896 
897                     String[] groups = CGAncillaries.parse(annotation.getMembers().get("groups").toString(), ",");
898                     String[] attributes = CGAncillaries
899                             .parse(annotation.getMembers().get("attributes").toString(), ",");
900 
901                     // Add the profile to the group list...
902                     List<String> allGroups = new ArrayList<String>(Arrays.asList(groups));
903                     allGroups.add(profile);
904 
905                     // Check all groups and create inexisting ones...
906                     for (String groupName: allGroups)
907                         if (!identityManager.groupExists(groupName))
908                         {
909                             IDIFGroup group = DIFIoCRegistry.getRegistry().getImplementation(IDIFGroup.class);
910                             group.setID(groupName);
911                             group.setName(groupName);
912                             group.setDescription(groupName);
913                             group.setDefault(true);
914 
915                             identityManager.addGroup(group);
916                         }
917 
918                     // Create the user...
919                     IDIFUser user = DIFIoCRegistry.getRegistry().getImplementation(IDIFUser.class);
920                     user.setID(userName);
921                     user.setName(fullName);
922                     user.setNick(fullName);
923                     user.setPassword(password);
924                     user.setEmail(email);
925                     user.setProfileID(profile);
926                     user.setDefault(true);
927 
928                     identityManager.addUser(user);
929 
930                     // Only after all groups and user have been created can we add the user to the groups
931                     for (String groupName: allGroups)
932                         identityManager.addUserToGroup(userName, groupName);
933 
934                     // Refresh the user, to pick up the repository bindings...
935                     user = identityManager.getUser(userName);
936 
937                     // Parse and set all attributes
938                     for (String attrPair: attributes)
939                     {
940                         String[] values = CGAncillaries.parse(attrPair, "=");
941 
942                         if (values.length == 2)
943                             try
944                             {
945                                 user.setAttribute(values[0], values[1]);
946 
947                             }
948                             catch (InternalFrameworkException e)
949                             {
950                                 DIFLogger.getLogger().error(
951                                         "Could not add default attribute \"" + values[0] + " for user \"" + userName
952                                                 + "\"!");
953                             }
954                     }
955                 }
956             }
957             catch (IdentityManagerException identityManagerException)
958             {
959                 if (identityManager.isReadOnly())
960                     DIFLogger.getLogger().info("Identity Manager in Read Only mode.");
961                 else
962                     DIFLogger.getLogger().warn(
963                             "Could not access the identity manager!" + identityManagerException.getMessage());
964             }
965         }
966     }
967 }