Subversion Repositories HomeAutomation

Rev

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

Rev Author Line No. Line
15 arune 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
}