1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.nnsoft.commons.meiyo.classpath;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Enumeration;
23 import java.util.jar.JarEntry;
24 import java.util.jar.JarFile;
25 import java.util.regex.Pattern;
26
27
28
29
30 public final class MeiyoScanner {
31
32 private static final String JAVA_CLASS_PATH = "java.class.path";
33
34 private static final Pattern JAR_FILE = Pattern.compile(".+\\.(jar|zip)", Pattern.CASE_INSENSITIVE);
35
36 private static final String CLASS_EXTENSION = ".class";
37
38 private MeiyoScanner() {
39
40 }
41
42 public static HandlerConfigurationsBuilder createClassPathFromJVM() {
43 return createClassPathFromPath(System.getProperty(JAVA_CLASS_PATH));
44 }
45
46 public static HandlerConfigurationsBuilder createClassPathFromPath(final String classpath) {
47 if (classpath == null || classpath.length() == 0) {
48 throw new IllegalArgumentException("Parameter 'classpath' must not be empty");
49 }
50
51 return createClassPathFromPath(classpath.split(File.pathSeparator));
52 }
53
54 public static HandlerConfigurationsBuilder createClassPathFromPath(final String...paths) {
55 if (paths == null || paths.length == 0) {
56 throw new IllegalArgumentException("At least one path has to be specified");
57 }
58
59 return new HandlerConfigurationsBuilder() {
60
61 @Override
62 public ClassLoaderBuilder withConfiguration(final HandlerConfiguration...configurations) {
63 if (configurations == null || configurations.length == 0) {
64 throw new IllegalArgumentException("At least one HandlerConfiguration has to be specified");
65 }
66 return withConfiguration(Arrays.asList(configurations));
67 }
68
69 @Override
70 public ClassLoaderBuilder withConfiguration(final Collection<HandlerConfiguration> configurations) {
71 if (configurations == null || configurations.isEmpty()) {
72 throw new IllegalArgumentException("Parameter 'configurations' must not be null or empty");
73 }
74
75 MatcherImpl matcher = new MatcherImpl();
76 for (HandlerConfiguration configuration : configurations) {
77 configuration.configure(matcher);
78 }
79
80 final Collection<ClassPathHandler> handlers = matcher.getHandlers();
81
82 return new ClassLoaderBuilder() {
83
84 @Override
85 public ErrorHandlerBuilder usingDefaultClassLoader() {
86 return this.usingClassLoader(Thread.currentThread().getContextClassLoader());
87 }
88
89 @Override
90 public ErrorHandlerBuilder usingClassLoader(final ClassLoader classLoader) {
91 if (classLoader == null) {
92 throw new IllegalArgumentException("Parameter 'classLoader' must not be null");
93 }
94
95 return new ErrorHandlerBuilder() {
96
97 @Override
98 public void scan() {
99 scan(new ErrorHandler() {
100
101 @Override
102 public void onJARReadingError(File file, IOException e) {
103 throw new RuntimeException("An error occurred while loading '"
104 + file
105 + "' jar entry", e);
106 }
107
108 @Override
109 public void onClassNotFound(String className) {
110
111 }
112
113 });
114 }
115
116 @Override
117 public void scan(final ErrorHandler errorHandler) {
118 if (errorHandler == null) {
119 throw new IllegalArgumentException("Parameter 'errorHandler' must not be null");
120 }
121
122 for (String path: paths) {
123 File file = new File(path);
124 if (JAR_FILE.matcher(path).matches()) {
125 try {
126 JarFile jarFile = new JarFile(path);
127 Enumeration<JarEntry> enumeration = jarFile.entries();
128 while (enumeration.hasMoreElements()) {
129 JarEntry entry = enumeration.nextElement();
130 if (!entry.isDirectory()) {
131 handleEntry(entry.getName(), path, handlers, classLoader, errorHandler);
132 }
133 }
134 } catch (IOException e) {
135 errorHandler.onJARReadingError(file, e);
136 }
137 } else {
138 traverse(file, path, handlers, classLoader, errorHandler);
139 }
140
141 }
142 }
143 };
144 }
145
146 };
147 }
148 };
149 }
150
151 private static final void traverse(final File file,
152 final String path,
153 final Collection<ClassPathHandler> handlers,
154 final ClassLoader classLoader,
155 final ErrorHandler errorHandler) {
156 if (file.isDirectory()) {
157
158 for (File child : file.listFiles()) {
159 traverse(child, path, handlers, classLoader, errorHandler);
160 }
161
162 return;
163 }
164
165 handleEntry(file.getAbsolutePath().substring(path.length() + 1), path, handlers, classLoader, errorHandler);
166 }
167
168 private static final void handleEntry(String entry,
169 final String path,
170 final Collection<ClassPathHandler> handlers,
171 final ClassLoader classLoader,
172 final ErrorHandler errorHandler) {
173 if (!entry.endsWith(CLASS_EXTENSION)) {
174 return;
175 }
176
177 entry = entry.substring(0, entry.lastIndexOf('.')).replace('/', '.');
178 try {
179 Class<?> clazz = classLoader.loadClass(entry);
180
181 for (ClassPathHandler classPathHandler : handlers) {
182 classPathHandler.doHandle(path, clazz);
183 }
184 } catch (Throwable t) {
185 errorHandler.onClassNotFound(entry);
186 }
187 }
188
189 }