1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.any23.util;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.UnsupportedEncodingException;
23 import java.net.URL;
24 import java.net.URLDecoder;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.List;
29 import java.util.jar.JarEntry;
30 import java.util.jar.JarFile;
31
32
33
34
35
36
37 public class DiscoveryUtils {
38
39 private static final String FILE_PREFIX = "file:";
40 private static final String CLASS_SUFFIX = ".class";
41
42
43
44
45
46
47
48
49
50 public static List<Class> getClassesInPackage(String packageName) {
51 final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
52 assert classLoader != null;
53 final String path = packageName.replace('.', '/');
54 final Enumeration<URL> resources;
55 try {
56 resources = classLoader.getResources(path);
57 } catch (IOException ioe) {
58 throw new IllegalStateException("Error while retrieving internal resource path.", ioe);
59 }
60 final List<File> dirs = new ArrayList<File>();
61 while (resources.hasMoreElements()) {
62 final URL resource = resources.nextElement();
63 final String fileName = resource.getFile();
64 final String fileNameDecoded;
65 try {
66 fileNameDecoded = URLDecoder.decode(fileName, "UTF-8");
67 } catch (UnsupportedEncodingException uee) {
68 throw new IllegalStateException("Error while decoding class file name.", uee);
69 }
70 dirs.add(new File(fileNameDecoded));
71 }
72 @SuppressWarnings("rawtypes")
73 final ArrayList<Class> classes = new ArrayList<Class>();
74 for (File directory : dirs) {
75 classes.addAll(findClasses(directory, packageName));
76 }
77 return classes;
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91 public static List<Class> getClassesInPackage(String packageName, Class<?> filter) {
92 final List<Class> classesInPackage = getClassesInPackage(packageName);
93 @SuppressWarnings("rawtypes")
94 final List<Class> result = new ArrayList<Class>();
95 Class<?> superClazz;
96 for (Class<?> clazz : classesInPackage) {
97 if (clazz.equals(filter)) {
98 continue;
99 }
100 superClazz = clazz.getSuperclass();
101 if ((superClazz != null && superClazz.equals(filter)) || contains(clazz.getInterfaces(), filter)) {
102 result.add(clazz);
103 }
104 }
105 return result;
106 }
107
108
109
110
111
112
113
114
115
116
117
118 private static List<Class> findClasses(File location, String packageName) {
119 final String locationPath = location.getPath();
120 if (locationPath.indexOf(FILE_PREFIX) == 0) {
121 return findClassesInJAR(locationPath);
122 }
123 return findClassesInDir(location, packageName);
124 }
125
126
127
128
129
130
131
132
133
134 private static List<Class> findClassesInJAR(String location) {
135 final String[] sections = location.split("!");
136 if (sections.length != 2) {
137 throw new IllegalArgumentException("Invalid JAR location.");
138 }
139 final String jarLocation = sections[0].substring(FILE_PREFIX.length());
140 final String packagePath = sections[1].substring(1);
141
142 try {
143 @SuppressWarnings("resource")
144 final JarFile jarFile = new JarFile(jarLocation);
145 final Enumeration<JarEntry> entries = jarFile.entries();
146 @SuppressWarnings("rawtypes")
147 final List<Class> result = new ArrayList<Class>();
148 JarEntry current;
149 String entryName;
150 String clazzName;
151 Class<?> clazz;
152 while (entries.hasMoreElements()) {
153 current = entries.nextElement();
154 entryName = current.getName();
155 if (StringUtils.isPrefix(packagePath, entryName) && StringUtils.isSuffix(CLASS_SUFFIX, entryName)
156 && !entryName.contains("$")) {
157 try {
158 clazzName = entryName.substring(0, entryName.length() - CLASS_SUFFIX.length()).replaceAll("/",
159 ".");
160 clazz = Class.forName(clazzName);
161 } catch (ClassNotFoundException cnfe) {
162 throw new IllegalStateException("Error while loading detected class.", cnfe);
163 }
164 result.add(clazz);
165 }
166 }
167 return result;
168 } catch (IOException ioe) {
169 throw new RuntimeException("Error while opening JAR file.", ioe);
170 }
171 }
172
173
174
175
176
177
178
179
180
181
182
183 private static List<Class> findClassesInDir(File directory, String packageName) {
184 if (!directory.exists()) {
185 return Collections.emptyList();
186 }
187 @SuppressWarnings("rawtypes")
188 final List<Class> classes = new ArrayList<Class>();
189 File[] files = directory.listFiles();
190 for (File file : files) {
191 String fileName = file.getName();
192 if (file.isDirectory()) {
193 assert !fileName.contains(".");
194 classes.addAll(findClassesInDir(file, packageName + "." + fileName));
195 } else if (fileName.endsWith(".class") && !fileName.contains("$")) {
196 try {
197 Class<?> clazz;
198 try {
199 clazz = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6));
200 } catch (ExceptionInInitializerError e) {
201
202
203
204
205 clazz = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6), false,
206 Thread.currentThread().getContextClassLoader());
207 }
208 classes.add(clazz);
209 } catch (ClassNotFoundException cnfe) {
210 throw new IllegalStateException("Error while loading detected class.", cnfe);
211 }
212 }
213 }
214 return classes;
215 }
216
217 private static boolean contains(Object[] list, Object t) {
218 for (Object o : list) {
219 if (o.equals(t)) {
220 return true;
221 }
222 }
223 return false;
224 }
225
226 private DiscoveryUtils() {
227 }
228
229 }