1 /*
2 * Copyright (c) 2001, 2002 The XDoclet team
3 * All rights reserved.
4 */
5 package xdoclet.util;
6
7 import org.apache.commons.collections.CollectionUtils;
8 import org.apache.commons.collections.Predicate;
9 import org.apache.commons.logging.LogFactory;
10
11 import java.io.File;
12 import java.io.FileFilter;
13 import java.io.IOException;
14 import java.io.FileInputStream;
15
16 import java.net.MalformedURLException;
17 import java.net.URL;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.StringTokenizer;
23 import java.util.List;
24 import java.util.jar.Manifest;
25 import java.util.jar.JarFile;
26 import java.util.jar.Attributes;
27
28 import xdoclet.PluginFactory;
29
30 /***
31 * Finds directories and jars on the classpath.
32 *
33 * @author <a href="mailto:aslak.hellesoy at netcom.no">Aslak Hellesøy</a>
34 * @version $Revision: 1.13 $
35 */
36 public class ClasspathManager {
37 public static final JarFilter JAR_FILTER = new JarFilter();
38 public static final DirFilter DIR_FILTER = new DirFilter();
39 public static final String PATH_DELIM = System.getProperty("path.separator");
40 private final String _classpath;
41
42 /***
43 * Contains directories and jars on the classpath that exist,
44 * regardless of whether they have a descriptor.
45 */
46 private final Collection _files = new ArrayList();
47
48 /***
49 * Constructs a new ClasspathManager.
50 *
51 * @param classpath where plugin jars and directories will be searched for
52 */
53 public ClasspathManager(String classpath) {
54 if (classpath == null) {
55 throw new IllegalArgumentException("classpath cannot be null");
56 }
57
58 _classpath = classpath;
59 findExistingClasspathFiles();
60 }
61
62 public static String getNiceClasspath( String classpath ) {
63 StringBuffer sb = new StringBuffer("\n");
64
65 for (StringTokenizer st = new StringTokenizer( classpath, System.getProperty("path.separator") ); st.hasMoreTokens(); ) {
66 sb.append(" ").append(st.nextToken()).append("\n");
67 }
68
69 return sb.toString();
70 }
71
72 /***
73 * Gets all the files on the classpath that exist, both directories and files.
74 *
75 * @return Collection of File
76 */
77 public Collection getFiles() {
78 return _files;
79 }
80
81 /***
82 * Returns the existing zip/jar files on the classpath.
83 *
84 * @return a Collection of File
85 */
86 public final Collection getJars() {
87 return CollectionUtils.select(getFiles(), JAR_FILTER);
88 }
89
90 /***
91 * Returns the existing directories on the classpath.
92 *
93 * @return a Collection of File
94 */
95 public final Collection getDirectories() {
96 return CollectionUtils.select(getFiles(), DIR_FILTER);
97 }
98
99 /***
100 * Returns a resource from the classpath, taking the first it finds.
101 *
102 * @param relativePath
103 * @return an URL to the resource or null if not found.
104 */
105 public URL getResource(String relativePath) {
106 if (relativePath == null) {
107 throw new IllegalArgumentException("relativePath can't be null");
108 }
109
110 for (Iterator files = getFiles().iterator(); files.hasNext();) {
111 File file = (File) files.next();
112
113 try {
114 URL fileUrl = file.toURL();
115
116 if (FileUtils.isJar(file)) {
117 try {
118 URL resourceURL = new URL("jar:" + fileUrl.toExternalForm() + "!/" + relativePath);
119
120 try {
121 resourceURL.openStream(); // if we don't get an exception here, the entry exists.
122
123 return resourceURL;
124 } catch (IOException e) {
125 }
126 } catch (IOException ignore) {
127 }
128 } else if (file.isDirectory()) {
129 File resourceFile = new File(fileUrl.getFile(), relativePath);
130
131 if (resourceFile.exists()) {
132 return resourceFile.toURL();
133 }
134 }
135 } catch (MalformedURLException ignore) {
136 }
137 }
138
139 return null;
140 }
141
142 /***
143 * Finds existing files and directories on the classpath.
144 */
145 private void findExistingClasspathFiles() {
146 StringTokenizer pathTokenizer = new StringTokenizer(_classpath, PATH_DELIM);
147
148 while (pathTokenizer.hasMoreTokens()) {
149 File file = new File(pathTokenizer.nextToken()).getAbsoluteFile();
150
151 if (file.exists()) {
152 _files.add(file);
153 } else {
154 LogFactory.getLog(ClasspathManager.class).warn("The file " + file.getAbsolutePath()
155 + " was on the classpath, but doesn't exist.");
156 }
157 }
158 }
159
160 /***
161 * Gets the classpath where plugins are looked for.
162 * @return the classpath where plugins are looked for.
163 */
164 public String getClasspath() {
165 return _classpath;
166 }
167
168 /***
169 * Returns all Java Bean classes on the classpath.
170 * @return a List of {@link Class}.
171 */
172 public List findJavaBeans() {
173 List result = new ArrayList();
174 for( Iterator files = getFiles().iterator(); files.hasNext(); ) {
175 File dirOrJar = (File) files.next();
176 result.addAll( findJavaBeans( getClass().getClassLoader(), dirOrJar ));
177 }
178 return result;
179 }
180
181 /***
182 * Returns a collection of classes that are Java Beans. The Java Bean
183 * classes are found by looking at the MANIFEST.MF file.
184 *
185 * @param beanClassLoader the ClassLoader used to load the bean classes.
186 * @param dirOrJar the directory of jar file containing the classes.
187 * @return a Collection of {@link Class}.
188 */
189 public static List findJavaBeans( ClassLoader beanClassLoader, File dirOrJar ) {
190 List result = new ArrayList();
191
192 try {
193 Manifest manifest = null;
194 if (dirOrJar.isDirectory()) {
195 try {
196 manifest = new Manifest(new FileInputStream(new File(dirOrJar, "META-INF/MANIFEST.MF")));
197 } catch (IOException e) {
198 // Ignore. There was no Manifest here.
199 }
200 } else {
201 try {
202 JarFile jarFile = new JarFile(dirOrJar);
203
204 manifest = jarFile.getManifest();
205 } catch (IOException e) {
206 // Ignore. Wasn't a jar file.
207 }
208 }
209
210 if (manifest != null) {
211 // Now loop over all entries in the Manifest.
212 for (Iterator entryNames = manifest.getEntries().keySet().iterator(); entryNames.hasNext();) {
213 String entryName = (String) entryNames.next();
214 // Is it a class?
215 if (entryName.endsWith(".class")) {
216 Attributes attributes = manifest.getAttributes(entryName);
217 LogFactory.getLog(PluginFactory.class).debug("ENTRY:" + entryName);
218 // See if it's a java bean.
219 String javaBean = attributes.getValue("Java-Bean");
220
221 if ("true".equalsIgnoreCase(javaBean)) {
222 // OK. Get the BeanInfo.
223 String className = entryName.substring(0, entryName.length() - 6);
224
225 className = className.replace('/', '.');
226
227 // Load the class
228 try {
229 Class beanClass = beanClassLoader.loadClass(className);
230 result.add( beanClass );
231 } catch (ClassNotFoundException e) {
232 // diagnoseClassLoader( beanClassLoader );
233 String errorMessage = className
234 + " was declared as a Java-Bean in the manifest, but the class was not found.";
235
236 LogFactory.getLog(PluginFactory.class).error(errorMessage, e);
237 throw new IllegalStateException(errorMessage);
238 } catch (NoClassDefFoundError e) {
239 // diagnoseClassLoader( beanClassLoader );
240 if( e.getCause() != null ) {
241 e.getCause().printStackTrace();
242 }
243 String errorMessage = className
244 + " was declared as a Java-Bean in the manifest, but the class was not found.";
245
246 LogFactory.getLog(PluginFactory.class).error(errorMessage, e);
247 throw new IllegalStateException(errorMessage);
248 }
249 }
250 }
251 }
252 }
253 return result;
254 } catch( Exception e ) {
255 throw new IllegalStateException(e.getMessage());
256 }
257 }
258
259 public static String getPackage( Class clazz ) {
260 return clazz.getName().substring( 0, clazz.getName().lastIndexOf('.'));
261 }
262
263 /***
264 * Adapter class that makes it possible to use a class as both a
265 * Commons Collections Predicate and FileFilter.
266 */
267 public abstract static class FileFilterPredicate implements Predicate, FileFilter {
268 public abstract boolean accept(File file);
269
270 public final boolean evaluate(Object o) {
271 return accept((File) o);
272 }
273 }
274
275 public static class JarFilter extends FileFilterPredicate {
276 public boolean accept(File file) {
277 return FileUtils.isJar(file);
278 }
279 }
280
281 public static class DirFilter extends FileFilterPredicate {
282 public boolean accept(File file) {
283 return file.isDirectory();
284 }
285 }
286 }
This page was automatically generated by Maven