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

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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