Coverage Report - pt.digitalis.dif.codegen.util.DEMLoaderHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
DEMLoaderHelper
0%
0/69
0%
0/42
3,5
 
 1  
 /**
 2  
  * - Digitalis Internal Framework v2.0 -
 3  
  *
 4  
  * (C) 2007, Digitalis Informatica.
 5  
  *
 6  
  * Distribuicao e Gestao de Informatica, Lda. Estrada de Paco de Arcos num.9 -
 7  
  * Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21
 8  
  * 4408999 http://www.digitalis.pt
 9  
  */
 10  
 package pt.digitalis.dif.codegen.util;
 11  
 
 12  
 import java.util.ArrayList;
 13  
 import java.util.HashMap;
 14  
 import java.util.List;
 15  
 import java.util.ListIterator;
 16  
 import java.util.Map;
 17  
 
 18  
 import com.google.inject.Inject;
 19  
 
 20  
 import pt.digitalis.dif.dem.DEMAnnotationLogic;
 21  
 import pt.digitalis.utils.bytecode.holders.AnnotationHolder;
 22  
 import pt.digitalis.utils.bytecode.holders.ClassHolder;
 23  
 import pt.digitalis.utils.inspection.ResourceUtils;
 24  
 import pt.digitalis.utils.inspection.exception.AuxiliaryOperationException;
 25  
 import pt.digitalis.utils.inspection.exception.ResourceNotFoundException;
 26  
 
 27  
 /**
 28  
  * Holds the list of packages that will be searched for Entity classes by the DIFCodeGenerator. Provides methods to add
 29  
  * packages to the list of packages, and to access the list.
 30  
  *
 31  
  * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
 32  
  * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
 33  
  * @created Jul 23, 2007
 34  
  */
 35  0
 final public class DEMLoaderHelper {
 36  
 
 37  
     /** 'Providers' folder name by convention. */
 38  
     final static public String PROVIDERS_DIR = "providers";
 39  
 
 40  
     /** 'Applications' folder name by convention. */
 41  
     final static public String APPLICATIONS_DIR = "applications";
 42  
 
 43  
     /** 'Services' folder name by convention. */
 44  
     final static public String SERVICES_DIR = "services";
 45  
 
 46  
     /** 'Stages' folder name by convention. */
 47  
     final static public String STAGES_DIR = "stages";
 48  
 
 49  
     /** 'Validators' folder name by convention. */
 50  
     final static public String VALIDATORS_DIR = "validators";
 51  
 
 52  
     /** The list of packages to search. */
 53  0
     static private List<String> packagesToSearch = new ArrayList<String>();
 54  
 
 55  
     /** Class path for the DEM Annotations. */
 56  
     final static private String DEM_ANNOTATIONS_CLASS_PATH = "pt.digitalis.dif.dem.annotations";
 57  
 
 58  
     /** Class path for the DEM Entity Annotations. */
 59  
     final static private String DEM_ENTITIES_ANNOTATIONS_CLASS_PATH = DEM_ANNOTATIONS_CLASS_PATH + ".entities";
 60  
 
 61  
     /**
 62  
      * Defines the FQN of the <code>@AnnotationLogicClass</code> annotation.
 63  
      */
 64  
     final static private String ANNOTATION_LOGIC_CLASS = DEM_ANNOTATIONS_CLASS_PATH
 65  
             + ".metaannotations.AnnotationLogicClass";
 66  
 
 67  
     /** The DEM Entity annotations defined on the framework. */
 68  0
     static private List<String> DEMEntitiesAnnontations = null;
 69  
 
 70  
     /** The annotationLogic Map */
 71  0
     static private Map<String, DEMAnnotationLogic> annotationLogicMap = null;
 72  
 
 73  
     /** Default constructor. Enforce noninstantiability */
 74  0
     private DEMLoaderHelper()
 75  0
     {}
 76  
 
 77  
     /**
 78  
      * Adds a package to the packageList after validating that this package does not already exist or is contained in an
 79  
      * existing parent package
 80  
      *
 81  
      * @param packageName
 82  
      *            the name of the package to add
 83  
      * @return T if package was added, F otherwise
 84  
      */
 85  
     static public boolean addPackage(String packageName)
 86  
     {
 87  
 
 88  0
         if (packagesToSearch == null)
 89  0
             packagesToSearch = new ArrayList<String>();
 90  
 
 91  0
         if (!packagesToSearch.contains(packageName))
 92  
         {
 93  0
             if (!isPackageContained(packageName))
 94  
             {
 95  
 
 96  
                 /*
 97  
                  * Remove from registry all eventual packages that will be contained by the new package
 98  
                  *
 99  
                  * <pre>
 100  
                  *
 101  
                  * IMPLEMENTATION NOTE:
 102  
                  *
 103  
                  * The usual "for" loop form (foreach) for collections uses an internal iterator of type Iterator<E>
 104  
                  * which doesn't support list modifying. Calling remove() on a list being iterated in such a loop raises
 105  
                  * a ConcurrentModificationException. To cope with this limitation a "for" loop with an explicit
 106  
                  * ListIterator<E> must be used and all modifying operations must be done through the iterator.
 107  
                  *
 108  
                  * </pre>
 109  
                  */
 110  
 
 111  0
                 for (ListIterator<String> iter = packagesToSearch.listIterator(); iter.hasNext();)
 112  
                 {
 113  0
                     String registeredPackage = (String) iter.next();
 114  
 
 115  0
                     if (registeredPackage.startsWith(packageName))
 116  0
                         iter.remove();
 117  
                 }
 118  
 
 119  
                 // Add the new package to the registry
 120  0
                 packagesToSearch.add(packageName);
 121  
 
 122  0
                 return true;
 123  
             }
 124  
         }
 125  
 
 126  0
         return false;
 127  
     }
 128  
 
 129  
     /**
 130  
      * Verifies if the given package is contained on a previously registered package.
 131  
      *
 132  
      * @param packageName
 133  
      *            the package name
 134  
      * @return T if packageName is contained on any existing package
 135  
      */
 136  
     static private boolean isPackageContained(String packageName)
 137  
     {
 138  
 
 139  0
         for (String registeredPackage: packagesToSearch)
 140  
         {
 141  0
             if (packageName.startsWith(registeredPackage))
 142  0
                 return true;
 143  
         }
 144  0
         return false;
 145  
     }
 146  
 
 147  
     /**
 148  
      * Return the list of packages.
 149  
      *
 150  
      * @return the List of packages
 151  
      */
 152  
     static public List<String> getPackageList()
 153  
     {
 154  0
         return packagesToSearch;
 155  
     }
 156  
 
 157  
     /**
 158  
      * Makes internal package list eligible for GC when it is no longer needed. Must be called explicitly since this is
 159  
      * a static class with static attributes for temporary data.
 160  
      */
 161  
     static public void cleanUp()
 162  
     {
 163  0
         packagesToSearch = null;
 164  0
         DEMEntitiesAnnontations = null;
 165  0
     }
 166  
 
 167  
     /**
 168  
      * Searches a given package for DEM Entity annotated classes.
 169  
      *
 170  
      * @param packageName
 171  
      *            the package to search for DEM classes
 172  
      * @return a List of CGClassHolder
 173  
      * @throws ResourceNotFoundException
 174  
      *             if package is not found
 175  
      */
 176  
     static public List<ClassHolder> getDEMEntityClassesInPackage(String packageName) throws ResourceNotFoundException
 177  
     {
 178  
 
 179  
         // Get all classes for the given package
 180  0
         List<String> packageClasses = ResourceUtils.getClassesInDeepPackage(packageName);
 181  
 
 182  
         // Initialize return object
 183  0
         ArrayList<ClassHolder> entityClasses = new ArrayList<ClassHolder>();
 184  
         // Reuse var
 185  
         ClassHolder tempClass;
 186  
 
 187  
         // Add all DEM Entity classes to the return list
 188  0
         for (String className: packageClasses)
 189  
         {
 190  
 
 191  
             // Build an holder for the class...
 192  
             try
 193  
             {
 194  0
                 tempClass = new ClassHolder(className);
 195  
 
 196  
             }
 197  0
             catch (ResourceNotFoundException e)
 198  
             {
 199  0
                 tempClass = null;
 200  
             }
 201  
 
 202  0
             if (tempClass != null)
 203  
             {
 204  
                 // If it's a DEM Entity add holder to result
 205  0
                 if (isDEMAnnotatedClass(tempClass))
 206  0
                     entityClasses.add(tempClass);
 207  
                 else
 208  
                     // Else delete it from repository (it won't be needed for enhancement)
 209  0
                     tempClass.deleteClassFromRepository();
 210  
             }
 211  
         }
 212  
 
 213  0
         return entityClasses;
 214  
     }
 215  
 
 216  
     /**
 217  
      * Tests a class for DEM Entity annotations.
 218  
      *
 219  
      * @param clazz
 220  
      *            the class to search for annotations
 221  
      * @return T if class is a DEM Entity, F otherwise.
 222  
      * @throws ResourceNotFoundException
 223  
      *             if annotations can't be read
 224  
      */
 225  
     static private boolean isDEMAnnotatedClass(ClassHolder clazz) throws ResourceNotFoundException
 226  
     {
 227  
 
 228  0
         boolean isDEMAnnotatedClass = false;
 229  
 
 230  
         // Check if any of the DEM Annotations is on the class's annotations
 231  0
         for (String annotationName: getDEMEntitiesAnnontations())
 232  
         {
 233  
             // If at least one is present, return immediately
 234  0
             if (clazz.containsAnnotation(annotationName))
 235  
             {
 236  0
                 isDEMAnnotatedClass = true;
 237  0
                 break;
 238  
             }
 239  
         }
 240  
 
 241  0
         return isDEMAnnotatedClass;
 242  
     }
 243  
 
 244  
     /**
 245  
      * Builds a map of all DEM annotations with associated logic.
 246  
      *
 247  
      * @return the Map of annotations
 248  
      * @throws ResourceNotFoundException
 249  
      *             if DEM annotations classes can't be found
 250  
      * @throws AuxiliaryOperationException
 251  
      *             if a DEMAnnotationLogic object can't be created
 252  
      */
 253  
     static public Map<String, DEMAnnotationLogic> getAnnotationLogicMap() throws ResourceNotFoundException,
 254  
             AuxiliaryOperationException
 255  
     {
 256  
 
 257  0
         if (annotationLogicMap == null)
 258  
         {
 259  
 
 260  0
             List<String> demAnnotationsClasses = getDEMAnnotations();
 261  
 
 262  0
             annotationLogicMap = new HashMap<String, DEMAnnotationLogic>();
 263  
 
 264  
             // Reuse vars
 265  
             ClassHolder tempAnnotationClass;
 266  
             AnnotationHolder annotationLogicClassAnnotation;
 267  
 
 268  
             // For each class...
 269  0
             for (String annotationClassName: demAnnotationsClasses)
 270  
             {
 271  
 
 272  
                 // ...build a holder...
 273  0
                 tempAnnotationClass = new ClassHolder(annotationClassName);
 274  
 
 275  
                 // ..get the class that defines the annotation logic
 276  0
                 annotationLogicClassAnnotation = tempAnnotationClass.getAnnotations().get(ANNOTATION_LOGIC_CLASS);
 277  
 
 278  
                 // If annotation @AnnotationLogicClass is present...
 279  0
                 if (annotationLogicClassAnnotation != null)
 280  
                 {
 281  
 
 282  
                     // Build an object of the appropriate type and put it on the map
 283  0
                     annotationLogicMap.put(tempAnnotationClass.getFQName(), DEMAnnotationLogic.makeObject(
 284  0
                             annotationLogicClassAnnotation.getMembers().get("value").toString(), tempAnnotationClass));
 285  
 
 286  
                 }
 287  
                 else
 288  
                 {
 289  
                     // Request the construction of a default annotation logic
 290  
                     // object and put it on the map
 291  0
                     annotationLogicMap.put(tempAnnotationClass.getFQName(), DEMAnnotationLogic.makeObject(
 292  0
                             DEMAnnotationLogic.DEFAULT_DEM_ANNOTATION_LOGIC_CLASS, tempAnnotationClass));
 293  
                 }
 294  
 
 295  
             }
 296  
 
 297  
             // Add the Google Guice inject annotation fot DiF to register injection as present
 298  0
             annotationLogicMap.put(Inject.class.getCanonicalName(), DEMAnnotationLogic.makeObject(
 299  0
                     DEMAnnotationLogic.DEFAULT_DEM_ANNOTATION_LOGIC_CLASS, new ClassHolder(Inject.class
 300  0
                             .getCanonicalName())));
 301  
 
 302  
         }
 303  
 
 304  
         // Return map
 305  0
         return annotationLogicMap;
 306  
     }
 307  
 
 308  
     /**
 309  
      * Returns a list with the names of all DEM annotations classes.
 310  
      *
 311  
      * @return the list with all DEM annotations class names
 312  
      * @throws ResourceNotFoundException
 313  
      *             if some needed resource is not found
 314  
      */
 315  
     static public List<String> getDEMAnnotations() throws ResourceNotFoundException
 316  
     {
 317  0
         return ResourceUtils.getClassesInDeepPackage(DEM_ANNOTATIONS_CLASS_PATH);
 318  
     }
 319  
 
 320  
     /**
 321  
      * Returns a list with the defined DEM Entity Annotation FQNs for the framework
 322  
      *
 323  
      * @return a list with the defined DEM Entity Annotation FQNs
 324  
      * @throws ResourceNotFoundException
 325  
      *             if DEM annotations classes can't be found
 326  
      */
 327  
     public static List<String> getDEMEntitiesAnnontations() throws ResourceNotFoundException
 328  
     {
 329  
         // Lazy loading
 330  0
         if (DEMEntitiesAnnontations == null)
 331  
             try
 332  
             {
 333  
                 try
 334  
                 {
 335  
                     // Fetches the the classes on the framework's DEM Entity
 336  
                     // conventioned package
 337  0
                     DEMEntitiesAnnontations = ResourceUtils.getClassesInPackage(DEM_ENTITIES_ANNOTATIONS_CLASS_PATH);
 338  
                 }
 339  0
                 catch (ResourceNotFoundException resourceNotFoundException)
 340  
                 {
 341  0
                     throw new ResourceNotFoundException("Could not found DEM annotations on "
 342  0
                             + DEM_ENTITIES_ANNOTATIONS_CLASS_PATH, resourceNotFoundException);
 343  
                 }
 344  
 
 345  
                 // Treat the situation where no DEM entities are found...
 346  0
                 if (DEMEntitiesAnnontations.size() == 0 || DEMEntitiesAnnontations == null)
 347  0
                     DEMEntitiesAnnontations = null;
 348  
 
 349  
             }
 350  0
             catch (ResourceNotFoundException resourceNotFoundException)
 351  
             {
 352  
                 // The caught exception is already of the correct type and
 353  
                 // provides the needed information to spot the problem.
 354  
                 // Therefore, wrap it up on another exception seems unnecessary.
 355  0
                 DEMEntitiesAnnontations = null;
 356  
 
 357  0
                 throw resourceNotFoundException;
 358  
             }
 359  
 
 360  0
         return DEMEntitiesAnnontations;
 361  
     }
 362  
 }