View Javadoc

1   /*
2    *    Copyright 2010-2011 The Meiyo Team
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
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   * FILL ME
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          // do nothing
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                                         // do nothing, just ignore it
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                                     // else ignore it
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 }