1 /* gnu.classpath.tools.FileSystemClassLoader
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 package gnu
.classpath
.tools
;
24 import java
.io
.FileInputStream
;
25 import java
.io
.FileNotFoundException
;
26 import java
.io
.InputStream
;
27 import java
.io
.IOException
;
28 import java
.io
.StreamTokenizer
;
29 import java
.io
.StringReader
;
31 import java
.net
.MalformedURLException
;
34 import java
.util
.LinkedList
;
35 import java
.util
.List
;
36 import java
.util
.ArrayList
;
37 import java
.util
.StringTokenizer
;
39 import java
.util
.jar
.JarEntry
;
40 import java
.util
.jar
.JarFile
;
41 import java
.util
.jar
.Manifest
;
42 import java
.util
.jar
.Attributes
;
45 * A <code>ClassLoader</code> implementation which looks for classes
46 * on the local filesystem given a standard search path.
48 public class FileSystemClassLoader
extends ClassLoader
{
50 private File
[] pathComponents
;
53 * Initialize the class loader with a normal path string. The path
54 * string should contain path components separated by {@link
55 * File.pathSeparator}. Each path component should either denote a
56 * directory or a .jar or .zip file.
58 public FileSystemClassLoader(String path
)
60 List components
= new ArrayList();
61 for (StringTokenizer st
= new StringTokenizer(path
, File
.pathSeparator
); st
.hasMoreTokens(); ) {
62 File pathComponent
= new File(st
.nextToken());
63 components
.add(pathComponent
);
64 if (pathComponent
.exists() && !pathComponent
.isDirectory()) {
65 List subComponents
= tryGetJarFileClassPathComponents(pathComponent
);
66 if (null != subComponents
) {
67 components
.addAll(subComponents
);
71 File
[] componentArray
= new File
[components
.size()];
72 this.pathComponents
= (File
[])components
.toArray(componentArray
);
76 * Initialize the class loader with an array of path
77 * components. Each path component should either denote a
78 * directory or a .jar or .zip file.
80 public FileSystemClassLoader(File
[] pathComponents
)
82 this.pathComponents
= pathComponents
;
83 for (int i
= 0; i
< pathComponents
.length
; ++i
) {
84 if (!pathComponents
[i
].exists()) {
85 System
.err
.println("WARNING: Path component '" + pathComponents
[i
] + "' not found.");
90 public Class
loadClass(String name
)
91 throws ClassNotFoundException
{
93 return super.loadClass(name
);
96 public Class
findClass(String name
)
97 throws ClassNotFoundException
{
99 byte[] b
= loadClassData(name
);
100 return defineClass(name
, b
, 0, b
.length
);
103 public URL
findResource(String name
)
105 StreamInfo streamInfo
= getResourceStream(name
);
106 if (null == streamInfo
) {
107 return super.findResource(name
);
111 return streamInfo
.getURL();
113 catch (MalformedURLException e
) {
114 System
.err
.println("WARNING: In FileSystemClassLoader: could not derive URL from file or jar entry: " + e
.toString());
120 private byte[] readFromStream(InputStream in
, long size
)
123 byte[] result
= new byte[(int)size
];
126 while (offset
< size
&& (nread
= in
.read(result
, offset
, (int)(size
- offset
))) >= 0) {
133 private byte[] readFromStream(StreamInfo streamInfo
)
136 InputStream in
= streamInfo
.openStream();
137 long size
= streamInfo
.getSize();
139 byte[] result
= new byte[(int)size
];
142 while (offset
< size
&& (nread
= in
.read(result
, offset
, (int)(size
- offset
))) >= 0) {
149 private static interface StreamInfo
151 public InputStream
openStream()
153 public long getSize();
155 throws MalformedURLException
;
158 private static class FileStreamInfo
159 implements StreamInfo
163 FileStreamInfo(File file
)
168 public InputStream
openStream()
171 return new FileInputStream(file
);
174 public long getSize()
176 return file
.length();
180 throws MalformedURLException
186 private static class JarStreamInfo
187 implements StreamInfo
190 private JarFile jarFile
;
191 private JarEntry jarEntry
;
193 JarStreamInfo(File file
, JarFile jarFile
, JarEntry jarEntry
)
196 this.jarFile
= jarFile
;
197 this.jarEntry
= jarEntry
;
200 public InputStream
openStream()
203 return jarFile
.getInputStream(jarEntry
);
206 public long getSize()
208 return jarEntry
.getSize();
212 throws MalformedURLException
214 String urlString
= "jar:" + file
.toURL() + "!/" + jarEntry
.getName();
215 return new URL(urlString
);
219 private StreamInfo
getResourceStream(String path
)
221 for (int i
= 0; i
< pathComponents
.length
; ++i
) {
223 File parent
= pathComponents
[i
];
224 if (parent
.isDirectory()) {
225 File file
= new File(parent
, path
);
227 return new FileStreamInfo(file
);
231 JarFile jarFile
= new JarFile(parent
, false, JarFile
.OPEN_READ
);
232 JarEntry jarEntry
= jarFile
.getJarEntry(path
);
233 if (null != jarEntry
) {
234 return new JarStreamInfo(parent
, jarFile
, jarEntry
);
238 catch (IOException ignore
) {
244 private byte[] loadClassData(String className
)
245 throws ClassNotFoundException
247 String classFileName
= className
.replace('.', File
.separatorChar
) + ".class";
248 StreamInfo streamInfo
= getResourceStream(classFileName
);
251 if (null != streamInfo
) {
252 return readFromStream(streamInfo
);
255 catch (IOException ignore
) {
258 throw new ClassNotFoundException(className
);
261 private static List
tryGetJarFileClassPathComponents(File file
)
264 JarFile jarFile
= new JarFile(file
, false, JarFile
.OPEN_READ
);
265 Manifest manifest
= jarFile
.getManifest();
266 if (null != manifest
) {
267 Attributes mainAttributes
= manifest
.getMainAttributes();
268 if (null != mainAttributes
) {
269 String classPath
= mainAttributes
.getValue(Attributes
.Name
.CLASS_PATH
);
270 if (null != classPath
) {
271 List result
= new LinkedList();
272 StreamTokenizer tokenizer
= new StreamTokenizer(new StringReader(classPath
));
273 tokenizer
.resetSyntax();
274 tokenizer
.wordChars(0, Integer
.MAX_VALUE
);
275 tokenizer
.whitespaceChars(9, 9); // tab
276 tokenizer
.whitespaceChars(10, 10); // lf
277 tokenizer
.whitespaceChars(13, 13); // cr
278 tokenizer
.whitespaceChars(32, 32); // space
279 tokenizer
.quoteChar('"');
281 while ((token
= tokenizer
.nextToken()) != StreamTokenizer
.TT_EOF
) {
282 if (StreamTokenizer
.TT_WORD
== token
) {
283 result
.add(new File(file
.getParentFile(), tokenizer
.sval
));
291 catch (IOException ignore
) {