libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / FileSystemClassLoader.java
blob0ec243d56392c3d4d6ab1ed058e8f5fe97b29fc4
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)
9 any later version.
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
19 02111-1307 USA. */
21 package gnu.classpath.tools;
23 import java.io.File;
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;
32 import java.net.URL;
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;
44 /**
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;
52 /**
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);
75 /**
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);
109 else {
110 try {
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());
115 return null;
120 private byte[] readFromStream(InputStream in, long size)
121 throws IOException
123 byte[] result = new byte[(int)size];
124 int nread = 0;
125 int offset = 0;
126 while (offset < size && (nread = in.read(result, offset, (int)(size - offset))) >= 0) {
127 offset += nread;
129 in.close();
130 return result;
133 private byte[] readFromStream(StreamInfo streamInfo)
134 throws IOException
136 InputStream in = streamInfo.openStream();
137 long size = streamInfo.getSize();
139 byte[] result = new byte[(int)size];
140 int nread = 0;
141 int offset = 0;
142 while (offset < size && (nread = in.read(result, offset, (int)(size - offset))) >= 0) {
143 offset += nread;
145 in.close();
146 return result;
149 private static interface StreamInfo
151 public InputStream openStream()
152 throws IOException;
153 public long getSize();
154 public URL getURL()
155 throws MalformedURLException;
158 private static class FileStreamInfo
159 implements StreamInfo
161 File file;
163 FileStreamInfo(File file)
165 this.file = file;
168 public InputStream openStream()
169 throws IOException
171 return new FileInputStream(file);
174 public long getSize()
176 return file.length();
179 public URL getURL()
180 throws MalformedURLException
182 return file.toURL();
186 private static class JarStreamInfo
187 implements StreamInfo
189 private File file;
190 private JarFile jarFile;
191 private JarEntry jarEntry;
193 JarStreamInfo(File file, JarFile jarFile, JarEntry jarEntry)
195 this.file = file;
196 this.jarFile = jarFile;
197 this.jarEntry = jarEntry;
200 public InputStream openStream()
201 throws IOException
203 return jarFile.getInputStream(jarEntry);
206 public long getSize()
208 return jarEntry.getSize();
211 public URL getURL()
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) {
222 try {
223 File parent = pathComponents[i];
224 if (parent.isDirectory()) {
225 File file = new File(parent, path);
226 if (file.exists()) {
227 return new FileStreamInfo(file);
230 else {
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) {
241 return null;
244 private byte[] loadClassData(String className)
245 throws ClassNotFoundException
247 String classFileName = className.replace('.', File.separatorChar) + ".class";
248 StreamInfo streamInfo = getResourceStream(classFileName);
250 try {
251 if (null != streamInfo) {
252 return readFromStream(streamInfo);
255 catch (IOException ignore) {
258 throw new ClassNotFoundException(className);
261 private static List tryGetJarFileClassPathComponents(File file)
263 try {
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('"');
280 int token;
281 while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
282 if (StreamTokenizer.TT_WORD == token) {
283 result.add(new File(file.getParentFile(), tokenizer.sval));
286 return result;
291 catch (IOException ignore) {
293 return null;