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

Last change on this file since 570 was 570, checked in by jts21, 11 years ago

Add settings package which uses reflection to allow changing settings without hard coding the code to change every setting.

  • Currently only works for String/Int/Boolean/Double values
  • Supports default values by looking for fields with the prefix 'default', and will reset unset values to their default if a default exists.
  • For more complex settings (e.g. proxy settings), there is a "onParsed()" callback which can be used to run additional code, and (in the case of the password widget) parse abnormal items.
  • Some of the settings code in FrameUtils.ParseProfile has already been commented out since it's handled by default with the new Settings package. The rest could be moved over to UserSettings.onParsed(). Given the number of settings that remain to be moved, it may be a good idea to add the possibility for setting-specific onParsed() callbacks (could be done quite easily, similarly to how default values are handled).
File size: 7.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.URLDecoder;
9import java.util.ArrayList;
10import java.util.Arrays;
11import java.util.Enumeration;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.jar.JarEntry;
15import java.util.jar.JarFile;
16import java.util.zip.ZipEntry;
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) throws ClassNotFoundException {
24
25 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
26
27 ArrayList<String> names = new ArrayList<String>();
28 ;
29 final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
30
31 String realPackageName = packageName;
32 packageName = packageName.replace(".", "/");
33 URL packageURL = classLoader.getResource(packageName);
34
35 if (packageURL.getProtocol().equals("jar")) {
36
37 // build jar file name, then loop through zipped entries
38
39 String jarFileNameUndecoded = packageURL.getFile();
40
41 try {
42 String jarFileName = URLDecoder.decode(jarFileNameUndecoded, "UTF-8");
43
44 JarURLConnection ju_connection = (JarURLConnection) packageURL.openConnection();
45 JarFile jf = ju_connection.getJarFile();
46
47 Enumeration<JarEntry> jarEntries = jf.entries();
48 while (jarEntries.hasMoreElements()) {
49 String entryName = jarEntries.nextElement().getName();
50
51 if (entryName.startsWith(packageName)) {
52
53 if (entryName.endsWith(".class") && !entryName.contains("$")) {
54
55 // Deal with situation where the class found might be a further sub-package
56 // e.g. for "org.expeditee.action"
57 // there is: org/expeditee/action/widgets/Chart.class
58 // which would produce a value of 'entryName' as widgets/Chart.class
59
60 entryName = entryName.substring(0, entryName.length() - 6); // 6 = '.class'
61 entryName = entryName.replace('/', '.');
62
63 names.add(entryName);
64 classes.add(Class.forName(entryName));
65 }
66 }
67 }
68 } catch (Exception e) {
69 System.err.println("Failed to decode jar file: " + jarFileNameUndecoded);
70 e.printStackTrace();
71 }
72 } else {
73 // loop through files in classpath
74
75 String packageURLString = packageURL.toString();
76 try {
77 URI uri = new URI(packageURLString);
78 File folder = new File(uri.getPath());
79
80 List<String> files = findFiles(folder);
81 for(String s : files) {
82 String entryName = realPackageName + s;
83
84 if (entryName.endsWith(".class") && !entryName.contains("$")) {
85 entryName = entryName.substring(0, entryName.lastIndexOf('.'));
86 entryName = entryName.replace('/', '.');
87
88 names.add(entryName);
89 classes.add(Class.forName(entryName));
90 }
91 }
92 } catch (Exception e) {
93 System.err.println("Failed to process file: " + packageURLString);
94 e.printStackTrace();
95 }
96 }
97
98 return classes;
99 }
100
101 /**
102 * Finds all files in a directory and it's subdirectories
103 *
104 * @param directory The folder to start in
105 *
106 * @return A list of Strings containing file paths relative to the starting directory
107 */
108 private static List<String> findFiles(File directory) {
109 List<String> files = new LinkedList<String>();
110 for(File f : directory.listFiles()) {
111 if(f.isDirectory()) {
112 for(String s : findFiles(f)) {
113 files.add(f.getName() + "/" + s);
114 }
115 } else {
116 files.add(f.getName());
117 }
118 }
119 return files;
120 }
121
122 public static List<Class<?>> getClasses(final String pckgname) throws ClassNotFoundException {
123
124 final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
125
126 // Must be a forward slash for loading resources
127 final String packagePath = pckgname.replace('.', '/');
128
129 if (System.getProperty("eclipse.expeditee.home") == null) {
130 final ClassLoader cld = Thread.currentThread().getContextClassLoader();
131 if (cld == null) {
132 throw new ClassNotFoundException("Can't get class loader.");
133 }
134 URL resource = null;
135 try {
136 final Enumeration<URL> resources = cld.getResources(packagePath);
137 while (resources.hasMoreElements()) {
138 URL url = resources.nextElement();
139 resource = url;
140 }
141 } catch (IOException e) {
142 System.err.println("A IO Error has occured when trying to use the ContextClassLoader"
143 + System.getProperty("line.separator")
144 + "Are you running from within Eclipse? (or just not with Jar) Then make sure your"
145 + " 'eclipse.expeditee.home' property is set correctly. It is currently: '"
146 + System.getProperty("eclipse.expeditee.home") + "'" + System.getProperty("line.separator")
147 + "You can set it by adding a VM argument. "
148 + "Example: -Declipse.expeditee.home=D:\\Desktop\\Research\\expeditee-svn");
149 e.printStackTrace();
150 }
151 if (resource == null) {
152 throw new ClassNotFoundException("No resource for " + packagePath);
153 }
154 final File directory = new File(resource.getFile());
155
156 final int splitPoint = directory.getPath().indexOf('!');
157 if (splitPoint > 0) {
158 String jarName = directory.getPath().substring("file:".length(), splitPoint);
159 // Windows HACK
160 if (jarName.indexOf(":") >= 0)
161 jarName = jarName.substring(1);
162
163 if (jarName.indexOf("%20") > 0) {
164 jarName = jarName.replace("%20", " ");
165 }
166 // System.out.println("JarName:" + jarName);
167 try {
168 final JarFile jarFile = new JarFile(jarName);
169 final Enumeration<?> entries = jarFile.entries();
170 while (entries.hasMoreElements()) {
171 final ZipEntry entry = (ZipEntry) entries.nextElement();
172 final String className = entry.getName();
173 if (className.startsWith(packagePath)) {
174 if (className.endsWith(".class") && !className.contains("$")) {
175 // The forward slash below is a forwards slash for
176 // both windows and linux
177
178 String class_forname = className.substring(0, className.length() - 6);
179 class_forname = class_forname.replace('/', '.');
180
181 classes.add(Class.forName(class_forname));
182 }
183 }
184 }
185 try {
186 jarFile.close();
187 } catch (IOException e) {
188 System.err.println("Error attempting to close Jar file");
189 e.printStackTrace();
190 }
191 } catch (IOException e) {
192 System.err.println("Error Instantiating Jar File Object");
193 e.printStackTrace();
194 }
195 } else {
196
197 System.err.println("A Error has occured when trying to use a Jar file to find actions or agents."
198 + System.getProperty("line.separator")
199 + "Are you running from within Eclipse? (or just not with Jar) Then make sure your"
200 + " 'eclipse.expeditee.home' property is set correctly. It is currently: '"
201 + System.getProperty("eclipse.expeditee.home") + "'" + System.getProperty("line.separator")
202 + "You can set it by adding a VM argument. "
203 + "Example: -Declipse.expeditee.home=D:\\Desktop\\Research\\expeditee-svn");
204 }
205 } else {
206 String eclipse_expeditee_home = System.getProperty("eclipse.expeditee.home", "");
207 String full_package_path = eclipse_expeditee_home + File.separator + "bin" + File.separator + "src"
208 + File.separator + packagePath;
209
210 final File directory = new File(full_package_path);
211
212 if (directory.exists()) {
213 // Get the list of the files contained in the package
214 String[] files = directory.list();
215 for (int i = 0; i < files.length; i++) {
216 // we are only interested in .class files
217 if (files[i].endsWith(".class") && !files[i].contains("$") && !files[i].equals("Actions.class")) {
218 // removes the .class extension
219 classes.add(Class.forName(pckgname + files[i].substring(0, files[i].length() - 6)));
220 }
221 }
222 } else {
223 throw new ClassNotFoundException("The package '" + pckgname + "' in the directory '" + directory
224 + "' does not appear to be a valid package");
225 }
226 }
227 return classes;
228 }
229
230}
Note: See TracBrowser for help on using the repository browser.