KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > vfs > impl > VFSClassLoader


1 /*
2  * Copyright 2002-2005 The Apache Software Foundation.
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.apache.commons.vfs.impl;
17
18 import org.apache.commons.vfs.FileObject;
19 import org.apache.commons.vfs.FileSystemException;
20 import org.apache.commons.vfs.FileSystemManager;
21 import org.apache.commons.vfs.FileType;
22 import org.apache.commons.vfs.NameScope;
23
24 import java.io.IOException JavaDoc;
25 import java.net.URL JavaDoc;
26 import java.security.CodeSource JavaDoc;
27 import java.security.Permission JavaDoc;
28 import java.security.PermissionCollection JavaDoc;
29 import java.security.Permissions JavaDoc;
30 import java.security.SecureClassLoader JavaDoc;
31 import java.security.cert.Certificate JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.jar.Attributes JavaDoc;
36 import java.util.jar.Attributes.Name;
37
38
39 /**
40  * A class loader that can load classes and resources from a search path
41  * VFS FileObjects refering both to folders and JAR files. Any FileObject
42  * of type {@link FileType#FILE} is asumed to be a JAR and is opened
43  * by creating a layered file system with the "jar" scheme.
44  * </p><p>
45  * TODO - Test this with signed Jars and a SecurityManager.
46  *
47  * @author <a HREF="mailto:brian@mmmanager.org">Brian Olsen</a>
48  * @see FileSystemManager#createFileSystem
49  */

50 public class VFSClassLoader
51     extends SecureClassLoader JavaDoc
52 {
53     private final ArrayList JavaDoc resources = new ArrayList JavaDoc();
54
55     /**
56      * Constructors a new VFSClassLoader for the given file.
57      *
58      * @param file the file to load the classes and resources from.
59      * @param manager the FileManager to use when trying create a layered Jar file
60      * system.
61      */

62     public VFSClassLoader(final FileObject file,
63                           final FileSystemManager manager)
64         throws FileSystemException
65     {
66         this(new FileObject[]{file}, manager, null);
67     }
68
69     /**
70      * Constructors a new VFSClassLoader for the given file.
71      *
72      * @param file the file to load the classes and resources from.
73      * @param manager the FileManager to use when trying create a layered Jar file
74      * system.
75      * @param parent the parent class loader for delegation.
76      */

77     public VFSClassLoader(final FileObject file,
78                           final FileSystemManager manager,
79                           final ClassLoader JavaDoc parent)
80         throws FileSystemException
81     {
82         this(new FileObject[]{file}, manager, parent);
83     }
84
85     /**
86      * Constructors a new VFSClassLoader for the given files. The files will
87      * be searched in the order specified.
88      *
89      * @param files the files to load the classes and resources from.
90      * @param manager the FileManager to use when trying create a layered Jar file
91      * system.
92      */

93     public VFSClassLoader(final FileObject[] files,
94                           final FileSystemManager manager)
95         throws FileSystemException
96     {
97         this(files, manager, null);
98     }
99
100     /**
101      * Constructors a new VFSClassLoader for the given FileObjects.
102      * The FileObjects will be searched in the order specified.
103      *
104      * @param files the FileObjects to load the classes and resources from.
105      * @param manager the FileManager to use when trying create a layered Jar file
106      * system.
107      * @param parent the parent class loader for delegation.
108      */

109     public VFSClassLoader(final FileObject[] files,
110                           final FileSystemManager manager,
111                           final ClassLoader JavaDoc parent) throws FileSystemException
112     {
113         super(parent);
114         addFileObjects(manager, files);
115     }
116
117     /**
118      * Appends the specified FileObjects to the list of FileObjects to search
119      * for classes and resources.
120      *
121      * @param files the FileObjects to append to the search path.
122      */

123     private void addFileObjects(final FileSystemManager manager,
124                                 final FileObject[] files) throws FileSystemException
125     {
126         for (int i = 0; i < files.length; i++)
127         {
128             FileObject file = files[i];
129             if (!file.exists())
130             {
131                 // Does not exist - skip
132
continue;
133             }
134
135             // TODO - use federation instead
136
if (manager.canCreateFileSystem(file))
137             {
138                 // Use contents of the file
139
file = manager.createFileSystem(file);
140             }
141
142             resources.add(file);
143         }
144     }
145
146     /**
147      * Finds and loads the class with the specified name from the search
148      * path.
149      *
150      * @throws ClassNotFoundException if the class is not found.
151      */

152     protected Class JavaDoc findClass(final String JavaDoc name) throws ClassNotFoundException JavaDoc
153     {
154         try
155         {
156             final String JavaDoc path = name.replace('.', '/').concat(".class");
157             final Resource res = loadResource(path);
158             if (res == null)
159             {
160                 throw new ClassNotFoundException JavaDoc(name);
161             }
162             return defineClass(name, res);
163         }
164         catch (final IOException JavaDoc ioe)
165         {
166             throw new ClassNotFoundException JavaDoc(name, ioe);
167         }
168     }
169
170     /**
171      * Loads and verifies the class with name and located with res.
172      */

173     private Class JavaDoc defineClass(final String JavaDoc name, final Resource res)
174         throws IOException JavaDoc
175     {
176         final URL JavaDoc url = res.getCodeSourceURL();
177         final String JavaDoc pkgName = res.getPackageName();
178         if (pkgName != null)
179         {
180             final Package JavaDoc pkg = getPackage(pkgName);
181             if (pkg != null)
182             {
183                 if (pkg.isSealed())
184                 {
185                     if (!pkg.isSealed(url))
186                     {
187                         throw new FileSystemException("vfs.impl/pkg-sealed-other-url", pkgName);
188                     }
189                 }
190                 else
191                 {
192                     if (isSealed(res))
193                     {
194                         throw new FileSystemException("vfs.impl/pkg-sealing-unsealed", pkgName);
195                     }
196                 }
197             }
198             else
199             {
200                 definePackage(pkgName, res);
201             }
202         }
203
204         final byte[] bytes = res.getBytes();
205         final Certificate JavaDoc[] certs =
206             res.getFileObject().getContent().getCertificates();
207         final CodeSource JavaDoc cs = new CodeSource JavaDoc(url, certs);
208         return defineClass(name, bytes, 0, bytes.length, cs);
209     }
210
211     /**
212      * Returns true if the we should seal the package where res resides.
213      */

214     private boolean isSealed(final Resource res)
215         throws FileSystemException
216     {
217         final String JavaDoc sealed = res.getPackageAttribute(Attributes.Name.SEALED);
218         return "true".equalsIgnoreCase(sealed);
219     }
220
221     /**
222      * Reads attributes for the package and defines it.
223      */

224     private Package JavaDoc definePackage(final String JavaDoc name,
225                                   final Resource res)
226         throws FileSystemException
227     {
228         // TODO - check for MANIFEST_ATTRIBUTES capability first
229
final String JavaDoc specTitle = res.getPackageAttribute(Name.SPECIFICATION_TITLE);
230         final String JavaDoc specVendor = res.getPackageAttribute(Attributes.Name.SPECIFICATION_VENDOR);
231         final String JavaDoc specVersion = res.getPackageAttribute(Name.SPECIFICATION_VERSION);
232         final String JavaDoc implTitle = res.getPackageAttribute(Name.IMPLEMENTATION_TITLE);
233         final String JavaDoc implVendor = res.getPackageAttribute(Name.IMPLEMENTATION_VENDOR);
234         final String JavaDoc implVersion = res.getPackageAttribute(Name.IMPLEMENTATION_VERSION);
235
236         final URL JavaDoc sealBase;
237         if (isSealed(res))
238         {
239             sealBase = res.getCodeSourceURL();
240         }
241         else
242         {
243             sealBase = null;
244         }
245
246         return definePackage(name, specTitle, specVersion, specVendor,
247             implTitle, implVersion, implVendor, sealBase);
248     }
249
250     /**
251      * Calls super.getPermissions both for the code source and also
252      * adds the permissions granted to the parent layers.
253      */

254     protected PermissionCollection JavaDoc getPermissions(final CodeSource JavaDoc cs)
255     {
256         try
257         {
258             final String JavaDoc url = cs.getLocation().toString();
259             FileObject file = lookupFileObject(url);
260             if (file == null)
261             {
262                 return super.getPermissions(cs);
263             }
264
265             FileObject parentLayer = file.getFileSystem().getParentLayer();
266             if (parentLayer == null)
267             {
268                 return super.getPermissions(cs);
269             }
270
271             Permissions JavaDoc combi = new Permissions JavaDoc();
272             PermissionCollection JavaDoc permCollect = super.getPermissions(cs);
273             copyPermissions(permCollect, combi);
274
275             for (FileObject parent = parentLayer;
276                  parent != null;
277                  parent = parent.getFileSystem().getParentLayer())
278             {
279                 final CodeSource JavaDoc parentcs =
280                     new CodeSource JavaDoc(parent.getURL(),
281                         parent.getContent().getCertificates());
282                 permCollect = super.getPermissions(parentcs);
283                 copyPermissions(permCollect, combi);
284             }
285
286             return combi;
287         }
288         catch (final FileSystemException fse)
289         {
290             throw new SecurityException JavaDoc(fse.getMessage());
291         }
292     }
293
294     /**
295      * Copies the permissions from src to dest.
296      */

297     protected void copyPermissions(final PermissionCollection JavaDoc src,
298                                    final PermissionCollection JavaDoc dest)
299     {
300         for (Enumeration JavaDoc elem = src.elements(); elem.hasMoreElements();)
301         {
302             final Permission JavaDoc permission = (Permission JavaDoc) elem.nextElement();
303             dest.add(permission);
304         }
305     }
306
307     /**
308      * Does a reverse lookup to find the FileObject when we only have the
309      * URL.
310      */

311     private FileObject lookupFileObject(final String JavaDoc name)
312     {
313         final Iterator JavaDoc it = resources.iterator();
314         while (it.hasNext())
315         {
316             final FileObject object = (FileObject) it.next();
317             if (name.equals(object.getName().getURI()))
318             {
319                 return object;
320             }
321         }
322         return null;
323     }
324
325     /**
326      * Finds the resource with the specified name from the search path.
327      * This returns null if the resource is not found.
328      */

329     protected URL JavaDoc findResource(final String JavaDoc name)
330     {
331         try
332         {
333             final Resource res = loadResource(name);
334             if (res != null)
335             {
336                 return res.getURL();
337             }
338         }
339         catch (final Exception JavaDoc mue)
340         {
341             // Ignore
342
// TODO - report?
343
}
344
345         return null;
346     }
347
348     /**
349      * Returns an Enumeration of all the resources in the search path
350      * with the specified name.
351      * TODO - Implement this.
352      */

353     protected Enumeration JavaDoc findResources(final String JavaDoc name)
354     {
355         return new Enumeration JavaDoc()
356         {
357             public boolean hasMoreElements()
358             {
359                 return false;
360             }
361
362             public Object JavaDoc nextElement()
363             {
364                 return null;
365             }
366         };
367     }
368
369     /**
370      * Searches through the search path of for the first class or resource
371      * with specified name.
372      */

373     private Resource loadResource(final String JavaDoc name) throws FileSystemException
374     {
375         final Iterator JavaDoc it = resources.iterator();
376         while (it.hasNext())
377         {
378             final FileObject baseFile = (FileObject) it.next();
379             final FileObject file =
380                 baseFile.resolveFile(name, NameScope.DESCENDENT_OR_SELF);
381             if (file.exists())
382             {
383                 return new Resource(name, baseFile, file);
384             }
385         }
386
387         return null;
388     }
389 }
390
Popular Tags