Subversion Repositories HomeAutomation

Rev

Blame | Last modification | View Log | SVN | RSS feed

  1. /*
  2.  * File created by Jimmy
  3.  * at 2004-jan-20 16:59:27
  4.  */
  5. package Macbeth.Utilities;
  6.  
  7. import java.io.File;
  8. import java.io.FileNotFoundException;
  9. import java.net.URL;
  10. import java.net.MalformedURLException;
  11. import java.net.URLClassLoader;
  12. import java.lang.reflect.Method;
  13. import java.util.LinkedList;
  14. import java.util.List;
  15.  
  16. /**
  17.  * Dynamic class loader that can enumerate and load classes at runtime.
  18.  * @author Jimmy
  19.  */
  20. public class DynamicClassLoader {
  21.  
  22.     /**
  23.      * Examines a class to find outwhether or not it meets the set requirements.
  24.      * Requirements can be set by passing a list of Superclasses and/or interfaces
  25.      * that the class must inherit/implement.
  26.      * @param theClass The name of the class to examine.
  27.      * @param superClassRequirements A list of names of superclasses that the class must inherit.
  28.      * @param interfaceRequirements A list of names of interfaces that the class must implement.
  29.      * @return true if all the set requirements are met, false otherwise.
  30.      */
  31.     private static boolean examineClass(Class theClass, String[] superClassRequirements, String[] interfaceRequirements) {
  32.         //if there are requirements on superclasses
  33.         if (superClassRequirements!=null) {
  34.             //an array that indicates which superclass requirements have been met
  35.             boolean[] requirementsMet = new boolean[superClassRequirements.length];
  36.             for (int i=0; i<requirementsMet.length; i++) {
  37.                 requirementsMet[i] = false;
  38.             }
  39.             //get the first superclass of our class
  40.             Class sup = theClass.getSuperclass();
  41.             //iterate through all superclass requirements
  42.             for (int i=0; i<superClassRequirements.length; i++) {
  43.                 String superClassRequirement = superClassRequirements[i];
  44.                 //iterate through all superclasses of our class
  45.                 while (sup != null) {
  46.                     //if this superclass equals the required superclass
  47.                     if (sup.getName().toString().equals(superClassRequirement)) {
  48.                         //then this requirement has been met
  49.                         requirementsMet[i] = true;
  50.                         //no need to search for this particular superclass anymore
  51.                         break;
  52.                     }
  53.                     //go to next superclass (if any)
  54.                     else {
  55.                         sup = sup.getSuperclass();
  56.                     }
  57.                 }
  58.             }
  59.             //now, find out if all superclass requirements were met
  60.             for (int i=0; i<requirementsMet.length; i++) {
  61.                 //if any of the requirements were NOT met
  62.                 if (!requirementsMet[i]) {
  63.                     //the whole method fails
  64.                     return false;
  65.                 }
  66.             }
  67.         }
  68.         //if there are requirements on interfaces
  69.         if (interfaceRequirements != null) {
  70.             //an array that indicates which interface requirements have been met
  71.             boolean[] requirementsMet = new boolean[interfaceRequirements.length];
  72.             for (int i = 0; i < requirementsMet.length; i++) {
  73.                 requirementsMet[i] = false;
  74.             }
  75.             //get all interface classes implemented by our class
  76.             Class[] interfaces = theClass.getInterfaces();
  77.             //iterate through all interface requirements
  78.             for (int i = 0; i < interfaceRequirements.length; i++) {
  79.                 String interfaceRequirement = interfaceRequirements[i];
  80.                 //iterate through all the implemented interfaces
  81.                 for (int j=0; j<interfaces.length; j++) {
  82.                     //if this interface equals the required interface
  83.                     if (interfaces[j].getName().toString().equals(interfaceRequirement)) {
  84.                         //then this requirement has been met
  85.                         requirementsMet[i] = true;
  86.                         //no need to search for this particular interface anymore
  87.                         break;
  88.                     }
  89.                 }
  90.             }
  91.             //now, find out if all interface requirements were met
  92.             for (int i = 0; i < requirementsMet.length; i++) {
  93.                 //if any of the requirements were NOT met
  94.                 if (!requirementsMet[i]) {
  95.                     //the whole method fails
  96.                     return false;
  97.                 }
  98.             }
  99.         }
  100.         //if this point is reached, the class met all requirements!
  101.         return true;
  102.     }
  103.  
  104.  
  105.     /**
  106.      * Searches a directory for classes that fulfill some specified requirements.
  107.      * The class names of the classes that are found will be saved in a user
  108.      * specified list. Subdirectories will be recursively searched as well, and the
  109.      * name of each found subdir will be appended to the class names of the classes
  110.      * that are found inside that directory. For instance, if a class is found in
  111.      * the base directory it is assumed to be part of the given base package (both
  112.      * of which you specify with parameters), but if the class is found insude a
  113.      * subdir with the relative path "Macbeth/Modules" it is assumed to be part of a
  114.      * package called [base package].Macbeth.Modules.
  115.      * @param basedirectory The base directory to start looking in.
  116.      * @param basepackage The corresponing package name for the given base directory.
  117.      * @param superClassRequirements A list of superclass names that all classes
  118.      * must inherit from (or else they will be ignored).
  119.      * @param interfaceRequirements A list of interface names that all classes must
  120.      * implement (or else they will be ignored).
  121.      * @param classList A list into which all class names will be put.
  122.      * @throws FileNotFoundException if the specified directory isn't found.
  123.      */
  124.     public static void locateClasses(String basedirectory, String basepackage,String[] superClassRequirements,
  125.                               String[] interfaceRequirements, List classList)
  126.                               throws FileNotFoundException {
  127.         //create file listing for given directory
  128.         File dir = new File(basedirectory);
  129.         File[] dirListing = dir.listFiles();
  130.         //convert directory to an URL (so it can be used with URLClassLoader)
  131.         URL dirURL;
  132.         URL[] urls;
  133.         try {
  134.             dirURL = dir.toURL();
  135.             urls = new URL[]{dirURL};
  136.         } catch (MalformedURLException e) {
  137.             throw new FileNotFoundException("Invalid directory");
  138.         }
  139.         //create an URLClassLoader that can load classes from our directory
  140.         ClassLoader cl = new URLClassLoader(urls);
  141.         //the object to temporarily hold loaded classes
  142.         Class loadedClass;
  143.         //now, for each file in this dir...
  144.         for (int i=0; i<dirListing.length; i++) {
  145.             //if this is a directory
  146.             if (dirListing[i].isDirectory()) {
  147.                 //if no base package is specified
  148.                 if (basepackage.equals("")) {
  149.                     //continue searching recursively through the subdirs
  150.                     locateClasses(basedirectory + System.getProperty("file.separator").toString() +
  151.                                   dirListing[i].getName(), dirListing[i].getName(),
  152.                                   superClassRequirements, interfaceRequirements, classList);
  153.                 }
  154.                 //if base package is specified
  155.                 else {
  156.                     //append a dot, and then continue searching recursively through the subdirs
  157.                     locateClasses(basedirectory + System.getProperty("file.separator").toString() +
  158.                                   dirListing[i].getName(), basepackage + "." + dirListing[i].getName(),
  159.                                   superClassRequirements, interfaceRequirements, classList);
  160.                 }
  161.             }
  162.             //this wasn't a directory
  163.             else {
  164.                 //if this is not a file ending with .class
  165.                 if (!dirListing[i].getName().toString().endsWith(".class")) {
  166.                     //ignore it and go on
  167.                     continue;
  168.                 }
  169.                 //else, work out the class name (so we can try to load the class)
  170.                 String filename = dirListing[i].getName().toString();
  171.                 String classname;
  172.                 //if a base package was given, we need to append a dot as a separator
  173.                 if (basepackage.equals("")) {
  174.                     classname = filename.substring(0, filename.length() - 6);
  175.                 } else {
  176.                     classname = basepackage + "." + filename.substring(0, filename.length() - 6);
  177.                 }
  178.                 //try to load class (so we can examine it)
  179.                 try {
  180.                     //try to load class
  181.                     loadedClass = cl.loadClass(classname);
  182.                     //and check if class meets requirements
  183.                     if (examineClass(loadedClass,superClassRequirements,interfaceRequirements)) {
  184.                         //if it does, save this classname in class list
  185.                         classList.add(classname);
  186.                     }
  187.                 } catch (ClassNotFoundException e) {
  188.                     //something went wrong, so ignore the current class and go on
  189.                     continue;
  190.                 }
  191.             }
  192.         }
  193.     }
  194.  
  195.     /**
  196.      * Loads a class from a directory at runtime.
  197.      * @param baseDirectory The base directory in which the class (or package) is located.
  198.      * @param classname The full classname of the class you want to load.
  199.      * @return The loaded class.
  200.      * @throws FileNotFoundException If the base directory isn't found.
  201.      * @throws ClassNotFoundException If the class isn't found.
  202.      */
  203.     public static Class loadClass(String baseDirectory, String classname)
  204.                                   throws FileNotFoundException, ClassNotFoundException {
  205.         File dir = new File(baseDirectory);
  206.         //convert directory to an URL (so it can be used with URLClassLoader)
  207.         URL dirURL;
  208.         URL[] urls;
  209.         try {
  210.             dirURL = dir.toURL();
  211.             urls = new URL[]{dirURL};
  212.         } catch (MalformedURLException e) {
  213.             throw new FileNotFoundException("Invalid directory");
  214.         }
  215.         //create an URLClassLoader that can load classes from our directory
  216.         ClassLoader cl = new URLClassLoader(urls);
  217.         //try to load and return the class
  218.         return cl.loadClass(classname);
  219.     }
  220.  
  221. }
  222.