source: trunk/src/org/expeditee/reflection/PackageLoader.java@ 748

Last change on this file since 748 was 743, checked in by bln4, 10 years ago

Added a special case to 'getClassesNew' for handling the protocol bundleresource.
This is the protocol that eclipse uses for their packaging of plugins.

File size: 8.9 KB
Line 
1package org.expeditee.reflection;
2
3import java.io.File;
4import java.io.IOException;
5import java.net.JarURLConnection;
6import java.net.URI;
7import java.net.URL;
8import java.net.URLConnection;
9import java.util.ArrayList;
10import java.util.Enumeration;
11import java.util.LinkedList;
12import java.util.List;
13import java.util.jar.JarEntry;
14import java.util.jar.JarFile;
15import java.util.zip.ZipEntry;
16
17
18public class PackageLoader {
19
20 // The following is adapted from:
21 // http://stackoverflow.com/questions/1456930/how-do-i-read-all-classes-from-a-java-package-in-the-classpath
22
23 public static List<Class<?>> getClassesNew(String packageName)
24 throws ClassNotFoundException {
25
26 ClassLoader classLoader = Thread.currentThread()
27 .getContextClassLoader();
28
29 ArrayList<String> names = new ArrayList<String>();
30 ;
31 final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
32
33 String realPackageName = packageName;
34 packageName = packageName.replace(".", "/");
35 URL packageURL = classLoader.getResource(packageName);
36
37 if (packageURL.getProtocol().equals("jar")) {
38
39 // build jar file name, then loop through zipped entries
40
41 String jarFileNameUndecoded = packageURL.getFile();
42
43 try {
44 JarURLConnection ju_connection = (JarURLConnection) packageURL
45 .openConnection();
46 JarFile jf = ju_connection.getJarFile();
47
48 Enumeration<JarEntry> jarEntries = jf.entries();
49 while (jarEntries.hasMoreElements()) {
50 String entryName = jarEntries.nextElement().getName();
51
52 if (entryName.startsWith(packageName)) {
53
54 if (entryName.endsWith(".class")
55 && !entryName.contains("$")) {
56
57 // Deal with situation where the class found might
58 // be a further sub-package
59 // e.g. for "org.expeditee.action"
60 // there is:
61 // org/expeditee/action/widgets/Chart.class
62 // which would produce a value of 'entryName' as
63 // widgets/Chart.class
64
65 entryName = entryName.substring(0,
66 entryName.length() - 6); // 6 = '.class'
67 entryName = entryName.replace('/', '.');
68
69 names.add(entryName);
70 classes.add(Class.forName(entryName));
71 }
72 }
73 }
74 } catch (Exception e) {
75 System.err.println("Failed to decode jar file: "
76 + jarFileNameUndecoded);
77 e.printStackTrace();
78 }
79 } else if (packageURL.getProtocol().equals("bundleresource")) {
80 try {
81 final URLConnection urlConnection = packageURL.openConnection();
82 final Class<?> c = urlConnection.getClass();
83 final java.lang.reflect.Method toInvoke = c.getMethod("getFileURL");
84 final URL fileURL = (URL)toInvoke.invoke(urlConnection);
85 final File folder = new File(fileURL.getFile());
86 final List<String> files = findFiles(folder);
87 for (final String s : files) {
88 String entryName = realPackageName + s;
89 if (entryName.endsWith(".class") && !entryName.contains("$")) {
90 entryName = entryName.substring(0, entryName.lastIndexOf('.'));
91 entryName = entryName.replace('/', '.');
92 names.add(entryName);
93 try {
94 final Class<?> tmpc = Class.forName(entryName);
95 classes.add(tmpc);
96 } catch (NoClassDefFoundError e) {
97 System.err.println("Unable to instantiate class " + entryName);
98 System.err.println(e.getMessage());
99 }
100 }
101 }
102 } catch (final Exception e) {
103 System.err.println("Failed to process file: " + packageName);
104 e.printStackTrace();
105 }
106 } else {
107 // loop through files in classpath
108
109 String packageURLString = packageURL.toString();
110 try {
111 URI uri = new URI(packageURLString);
112 File folder = new File(uri.getPath());
113
114 List<String> files = findFiles(folder);
115 for (String s : files) {
116 String entryName = realPackageName + s;
117
118 if (entryName.endsWith(".class")
119 && !entryName.contains("$")) {
120 entryName = entryName.substring(0,
121 entryName.lastIndexOf('.'));
122 entryName = entryName.replace('/', '.');
123
124 names.add(entryName);
125 classes.add(Class.forName(entryName));
126 }
127 }
128 } catch (Exception e) {
129 System.err.println("Failed to process file: "
130 + packageURLString);
131 e.printStackTrace();
132 }
133 }
134
135 return classes;
136 }
137
138 /**
139 * Finds all files in a directory and it's subdirectories
140 *
141 * @param directory
142 * The folder to start in
143 *
144 * @return A list of Strings containing file paths relative to the starting
145 * directory
146 */
147 private static List<String> findFiles(File directory) {
148 List<String> files = new LinkedList<String>();
149 for (File f : directory.listFiles()) {
150 if (f.isDirectory()) {
151 for (String s : findFiles(f)) {
152 files.add(f.getName() + "/" + s);
153 }
154 } else {
155 files.add(f.getName());
156 }
157 }
158 return files;
159 }
160
161 public static List<Class<?>> getClasses(final String pckgname)
162 throws ClassNotFoundException {
163
164 final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
165
166 // Must be a forward slash for loading resources
167 final String packagePath = pckgname.replace('.', '/');
168
169 if (System.getProperty("eclipse.expeditee.home") == null) {
170 final ClassLoader cld = Thread.currentThread()
171 .getContextClassLoader();
172 if (cld == null) {
173 throw new ClassNotFoundException("Can't get class loader.");
174 }
175 URL resource = null;
176 try {
177 final Enumeration<URL> resources = cld
178 .getResources(packagePath);
179 while (resources.hasMoreElements()) {
180 URL url = resources.nextElement();
181 resource = url;
182 }
183 } catch (IOException e) {
184 System.err
185 .println("A IO Error has occured when trying to use the ContextClassLoader"
186 + System.getProperty("line.separator")
187 + "Are you running from within Eclipse? (or just not with Jar) Then make sure your"
188 + " 'eclipse.expeditee.home' property is set correctly. It is currently: '"
189 + System.getProperty("eclipse.expeditee.home")
190 + "'"
191 + System.getProperty("line.separator")
192 + "You can set it by adding a VM argument. "
193 + "Example: -Declipse.expeditee.home=D:\\Desktop\\Research\\expeditee-svn");
194 e.printStackTrace();
195 }
196 if (resource == null) {
197 throw new ClassNotFoundException("No resource for "
198 + packagePath);
199 }
200 final File directory = new File(resource.getFile());
201
202 final int splitPoint = directory.getPath().indexOf('!');
203 if (splitPoint > 0) {
204 String jarName = directory.getPath().substring(
205 "file:".length(), splitPoint);
206 // Windows HACK
207 if (jarName.indexOf(":") >= 0)
208 jarName = jarName.substring(1);
209
210 if (jarName.indexOf("%20") > 0) {
211 jarName = jarName.replace("%20", " ");
212 }
213 // System.out.println("JarName:" + jarName);
214 try {
215 final JarFile jarFile = new JarFile(jarName);
216 final Enumeration<?> entries = jarFile.entries();
217 while (entries.hasMoreElements()) {
218 final ZipEntry entry = (ZipEntry) entries.nextElement();
219 final String className = entry.getName();
220 if (className.startsWith(packagePath)) {
221 if (className.endsWith(".class")
222 && !className.contains("$")) {
223 // The forward slash below is a forwards slash
224 // for
225 // both windows and linux
226
227 String class_forname = className.substring(0,
228 className.length() - 6);
229 class_forname = class_forname.replace('/', '.');
230
231 classes.add(Class.forName(class_forname));
232 }
233 }
234 }
235 try {
236 jarFile.close();
237 } catch (IOException e) {
238 System.err
239 .println("Error attempting to close Jar file");
240 e.printStackTrace();
241 }
242 } catch (IOException e) {
243 System.err.println("Error Instantiating Jar File Object");
244 e.printStackTrace();
245 }
246 } else {
247
248 System.err
249 .println("A Error has occured when trying to use a Jar file to find actions or agents."
250 + System.getProperty("line.separator")
251 + "Are you running from within Eclipse? (or just not with Jar) Then make sure your"
252 + " 'eclipse.expeditee.home' property is set correctly. It is currently: '"
253 + System.getProperty("eclipse.expeditee.home")
254 + "'"
255 + System.getProperty("line.separator")
256 + "You can set it by adding a VM argument. "
257 + "Example: -Declipse.expeditee.home=D:\\Desktop\\Research\\expeditee-svn");
258 }
259 } else {
260 String eclipse_expeditee_home = System.getProperty(
261 "eclipse.expeditee.home", "");
262 String full_package_path = eclipse_expeditee_home + File.separator
263 + "bin" + File.separator + packagePath;
264
265 final File directory = new File(full_package_path);
266
267 if (directory.exists()) {
268 // Get the list of the files contained in the package
269 String[] files = directory.list();
270 for (int i = 0; i < files.length; i++) {
271 // we are only interested in .class files
272 if (files[i].endsWith(".class") && !files[i].contains("$")
273 && !files[i].equals("Actions.class")) {
274 // removes the .class extension
275 classes.add(Class.forName(pckgname
276 + files[i].substring(0, files[i].length() - 6)));
277 }
278 }
279 } else {
280 throw new ClassNotFoundException("The package '" + pckgname
281 + "' in the directory '" + directory
282 + "' does not appear to be a valid package");
283 }
284 }
285 return classes;
286 }
287
288}
Note: See TracBrowser for help on using the repository browser.