Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: edu/emory/mathcs/util/classloader/GenericClassLoader.java


1   /* ***** BEGIN LICENSE BLOCK *****
2    * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3    *
4    * The contents of this file are subject to the Mozilla Public License Version
5    * 1.1 (the "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis,
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11   * for the specific language governing rights and limitations under the
12   * License.
13   *
14   * The Original Code is the Emory Utilities.
15   *
16   * The Initial Developer of the Original Code is
17   * The Distributed Computing Laboratory, Emory University.
18   * Portions created by the Initial Developer are Copyright (C) 2002
19   * the Initial Developer. All Rights Reserved.
20   *
21   * Alternatively, the contents of this file may be used under the terms of
22   * either the GNU General Public License Version 2 or later (the "GPL"), or
23   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24   * in which case the provisions of the GPL or the LGPL are applicable instead
25   * of those above. If you wish to allow use of your version of this file only
26   * under the terms of either the GPL or the LGPL, and not to allow others to
27   * use your version of this file under the terms of the MPL, indicate your
28   * decision by deleting the provisions above and replace them with the notice
29   * and other provisions required by the GPL or the LGPL. If you do not delete
30   * the provisions above, a recipient may use your version of this file under
31   * the terms of any one of the MPL, the GPL or the LGPL.
32   *
33   * ***** END LICENSE BLOCK ***** */
34  
35  package edu.emory.mathcs.util.classloader;
36  
37  import java.io.*;
38  import java.net.*;
39  import java.security.*;
40  import java.util.*;
41  import java.util.jar.*;
42  import java.util.jar.Attributes.Name;
43  import edu.emory.mathcs.util.security.action.*;
44  
45  /**
46   * This class loader can be used to find class, resource and library
47   * {@link ResourceHandle handles}
48   * as well as load classes, resources and libraries using abstract
49   * {@link ResourceFinder} entity encapsulating the searching approach.
50   * Resource handles allow accessing meta-information (like Attributes,
51   * Certificates etc.) related to classes, resources and libraries prior to
52   * loading them.
53   * <p>
54   * GenericClassLoader is intended to be used as a base for custom class
55   * loaders. In most applications, GenericClassLoader can be used directly --
56   * the application-specific functionality of resource searching can often be
57   * completely delegated to the resource finder. See {@link URIClassLoader}
58   * for a concrete implementation using a simple resource finder.
59   *
60   * @see        ResourceFinder
61   * @see        ResourceLoader
62   * @see        ResourceHandle
63   *
64   * @author Dawid Kurzyniec
65   * @version 1.0
66   */
67  public class GenericClassLoader extends SecureClassLoader {
68  
69      protected ResourceFinder finder;
70      private AccessControlContext acc;
71  
72      /**
73       * Creates new GenericClassLoader instance using specified
74       * {@link ResourceFinder} to find resources and having specified
75       * parent class loader.
76       */
77      public GenericClassLoader(ResourceFinder finder, ClassLoader parent) {
78          super(parent);
79          SecurityManager security = System.getSecurityManager();
80          if (security != null) {
81              security.checkCreateClassLoader();
82          }
83          this.finder = finder;
84          acc = AccessController.getContext();
85      }
86  
87      /**
88       * Creates new GenericClassLoader instance using specified
89       * {@link ResourceFinder} to find resources and with default
90       * parent class loader.
91       */
92      public GenericClassLoader(ResourceFinder finder) {
93          super();
94          // this is to make the stack depth consistent with 1.1
95          SecurityManager security = System.getSecurityManager();
96          if (security != null) {
97              security.checkCreateClassLoader();
98          }
99          this.finder = finder;
100         //acc = AccessController.getContext();
101     }
102 
103     /**
104      * Finds and loads the class with the specified name.
105      *
106      * @param name the name of the class
107      * @return the resulting class
108      * @exception ClassNotFoundException if the class could not be found
109      */
110     protected Class findClass(final String name)
111         throws ClassNotFoundException
112     {
113         try {
114             return (Class)
115                 AccessController.doPrivileged(new PrivilegedExceptionAction() {
116                     public Object run() throws ClassNotFoundException {
117                         String path = name.replace('.', '/').concat(".class");
118                         ResourceHandle h = finder.getResource(path);
119                         if (h != null) {
120                             try {
121                                 return defineClass(name, h);
122                             } catch (IOException e) {
123                                 throw new ClassNotFoundException(name, e);
124                             }
125                         } else {
126                             throw new ClassNotFoundException(name);
127                         }
128                     }
129                 }, acc);
130         } catch (java.security.PrivilegedActionException pae) {
131             throw (ClassNotFoundException)pae.getException();
132         }
133     }
134 
135     protected Class defineClass(String name, ResourceHandle h) throws IOException {
136         int i = name.lastIndexOf('.');
137         URL url = h.getCodeSourceURL();
138         if (i != -1) { // check package
139             String pkgname = name.substring(0, i);
140             // check if package already loaded
141             Package pkg = getPackage(pkgname);
142             Manifest man = h.getManifest();
143             if (pkg != null) {
144                 // package found, so check package sealing
145                 boolean ok;
146                 if (pkg.isSealed()) {
147                     // verify that code source URLs are the same
148                     ok = pkg.isSealed(url);
149                 } else {
150                     // make sure we are not attempting to seal the package
151                     // at this code source URL
152                     ok = (man == null) || !isSealed(pkgname, man);
153                 }
154                 if (!ok) {
155                     throw new SecurityException("sealing violation: " + name);
156                 }
157             } else { // package not yet defined
158                 if (man != null) {
159                     definePackage(pkgname, man, url);
160                 } else {
161                     definePackage(pkgname, null, null, null, null, null, null, null);
162                 }
163             }
164         }
165 
166         // now read the class bytes and define the class
167         byte[] b = h.getBytes();
168         java.security.cert.Certificate[] certs = h.getCertificates();
169         CodeSource cs = new CodeSource(url, certs);
170         return defineClass(name, b, 0, b.length, cs);
171     }
172 
173     /**
174      * returns true if the specified package name is sealed according to the
175      * given manifest.
176      */
177     private boolean isSealed(String name, Manifest man) {
178         String path = name.replace('.', '/').concat("/");
179         Attributes attr = man.getAttributes(path);
180         String sealed = null;
181         if (attr != null) {
182             sealed = attr.getValue(Name.SEALED);
183         }
184         if (sealed == null) {
185             if ((attr = man.getMainAttributes()) != null) {
186                 sealed = attr.getValue(Name.SEALED);
187             }
188         }
189         return "true".equalsIgnoreCase(sealed);
190     }
191 
192     /**
193      * Finds the resource with the specified name.
194      *
195      * @param name the name of the resource
196      * @return a <code>URL</code> for the resource, or <code>null</code>
197      *         if the resource could not be found.
198      */
199     protected URL findResource(final String name) {
200         return
201             (URL) AccessController.doPrivileged(new PrivilegedAction() {
202                 public Object run() {
203                     return finder.findResource(name);
204                 }
205             }, acc);
206     }
207 
208     /**
209      * Returns an Enumeration of URLs representing all of the resources
210      * having the specified name.
211      *
212      * @param name the resource name
213      * @exception IOException if an I/O exception occurs
214      * @return an <code>Enumeration</code> of <code>URL</code>s
215      */
216     protected Enumeration findResources(final String name) throws IOException {
217         return
218             (Enumeration) AccessController.doPrivileged(new PrivilegedAction() {
219                 public Object run() {
220                     return finder.findResources(name);
221                 }
222             }, acc);
223     }
224 
225     /**
226      * Returns the absolute path name of a native library. The VM
227      * invokes this method to locate the native libraries that belong
228      * to classes loaded with this class loader. If this method returns
229      * <code>null</code>, the VM searches the library along the path
230      * specified as the <code>java.library.path</code> property.
231      * This method invoke {@link #getLibraryHandle} method to find handle
232      * of this library. If the handle is found and its URL protocol is "file",
233      * the system-dependent absolute library file path is returned.
234      * Otherwise this method returns null. <p>
235      *
236      * Subclasses can override this method to provide specific approaches
237      * in library searching.
238      *
239      * @param      libname   the library name
240      * @return     the absolute path of the native library
241      * @see        java.lang.System#loadLibrary(java.lang.String)
242      * @see        java.lang.System#mapLibraryName(java.lang.String)
243      */
244     protected String findLibrary(String libname) {
245         ResourceHandle md = getLibraryHandle(libname);
246         if (md == null) return null;
247         URL url = md.getURL();
248         if (!"file".equals(url.getProtocol())) return null;
249         return new File(URI.create(url.toString())).getPath();
250     }
251 //
252 //    /**
253 //     * Gets the ResourceHandle object for the specified loaded class.
254 //     *
255 //     * @param clazz the Class
256 //     * @return the ResourceHandle of the Class
257 //     */
258 //    protected ResourceHandle getClassHandle(Class clazz)
259 //    {
260 //        return null;
261 //    }
262 
263     /**
264      * Finds the ResourceHandle object for the class with the specified name.
265      * Unlike <code>findClass()</code>, this method does not load the class.
266      *
267      * @param name the name of the class
268      * @return the ResourceHandle of the class
269      */
270     protected ResourceHandle getClassHandle(final String name) {
271         String path = name.replace('.', '/').concat(".class");
272         return getResourceHandle(path);
273     }
274 
275     /**
276      * Finds the ResourceHandle object for the resource with the specified name.
277      *
278      * @param name the name of the resource
279      * @return the ResourceHandle of the resource
280      */
281     protected ResourceHandle getResourceHandle(final String name)
282     {
283         return
284             (ResourceHandle) AccessController.doPrivileged(new PrivilegedAction() {
285                 public Object run() {
286                     return finder.getResource(name);
287                 }
288             }, acc);
289     }
290 
291     /**
292      * Finds the ResourceHandle object for the native library with the specified
293      * name.
294      * The library name must be '/'-separated path. The last part of this
295      * path is substituted by its system-dependent mapping (using
296      * {@link System#mapLibraryName(String)} method). Next, the
297      * <code>ResourceFinder</code> is used to look for the library as it
298      * was ordinary resource. <p>
299      *
300      * Subclasses can override this method to provide specific approaches
301      * in library searching.
302      *
303      * @param name the name of the library
304      * @return the ResourceHandle of the library
305      */
306     protected ResourceHandle getLibraryHandle(final String name) {
307         int idx = name.lastIndexOf('/');
308         String path;
309         String simplename;
310         if (idx == -1) {
311             path = "";
312             simplename = name;
313         } else if (idx == name.length()-1) { // name.endsWith('/')
314             throw new IllegalArgumentException(name);
315         } else {
316             path = name.substring(0, idx+1); // including '/'
317             simplename = name.substring(idx+1);
318         }
319         return getResourceHandle(path + System.mapLibraryName(simplename));
320     }
321 
322     /**
323      * Returns an Enumeration of ResourceHandle objects representing all of the
324      * resources having the specified name.
325      *
326      * @param name the name of the resource
327      * @return the ResourceHandle of the resource
328      */
329     protected Enumeration getResourceHandles(final String name)
330     {
331         return
332             (Enumeration) AccessController.doPrivileged(new PrivilegedAction() {
333                 public Object run() {
334                     return finder.getResources(name);
335                 }
336             }, acc);
337     }
338 
339     /**
340      * Defines a new package by name in this ClassLoader. The attributes
341      * contained in the specified Manifest will be used to obtain package
342      * version and sealing information. For sealed packages, the additional
343      * URL specifies the code source URL from which the package was loaded.
344      *
345      * @param name  the package name
346      * @param man   the Manifest containing package version and sealing
347      *              information
348      * @param url   the code source url for the package, or null if none
349      * @exception   IllegalArgumentException if the package name duplicates
350      *              an existing package either in this class loader or one
351      *              of its ancestors
352      * @return the newly defined Package object
353      */
354     protected Package definePackage(String name, Manifest man, URL url)
355         throws IllegalArgumentException
356     {
357         String path = name.replace('.', '/').concat("/");
358         URL sealBase = null;
359 
360         Attributes entryAttr = man.getAttributes(path);
361         Attributes mainAttr = man.getMainAttributes();
362 
363         String specTitle   = getManifestVal(entryAttr, mainAttr, Name.SPECIFICATION_TITLE);
364         String specVersion = getManifestVal(entryAttr, mainAttr, Name.SPECIFICATION_VERSION);
365         String specVendor  = getManifestVal(entryAttr, mainAttr, Name.SPECIFICATION_VENDOR);
366         String implTitle   = getManifestVal(entryAttr, mainAttr, Name.IMPLEMENTATION_TITLE);
367         String implVersion = getManifestVal(entryAttr, mainAttr, Name.IMPLEMENTATION_VERSION);
368         String implVendor  = getManifestVal(entryAttr, mainAttr, Name.IMPLEMENTATION_VENDOR);
369         String sealed      = getManifestVal(entryAttr, mainAttr, Name.SEALED);
370 
371         if ("true".equalsIgnoreCase(sealed)) sealBase = url;
372 
373         return definePackage(name, specTitle, specVersion, specVendor,
374                              implTitle, implVersion, implVendor, sealBase);
375     }
376 
377     private static String getManifestVal(Attributes entryAttr, Attributes mainAttr, Name key) {
378         String val = null;
379         if (entryAttr != null) {
380             val = entryAttr.getValue(key);
381         }
382         if (val == null && mainAttr != null) {
383             val = mainAttr.getValue(key);
384         }
385         return val;
386     }
387 
388 
389     public static URLStreamHandler getDefaultURLStreamHandler(String protocol) {
390 
391         String pkgList = (String)java.security.AccessController.doPrivileged(
392             new GetPropertyAction("java.protocol.handler.pkgs", ""));
393 
394         if (pkgList.length() > 0) pkgList += "|";
395         pkgList += "sun.net.www.protocol";
396 
397         StringTokenizer tokenizer = new StringTokenizer(pkgList, "|");
398 
399         while (tokenizer.hasMoreTokens()) {
400             String pkg = tokenizer.nextToken().trim();
401             try {
402                 String clname = pkg + "." + protocol + ".Handler";
403                 Class cls;
404                 try {
405                     cls = Class.forName(clname);
406                 } catch (ClassNotFoundException e) {
407                     cls = Class.forName(clname, false, null);
408                 }
409                 return (URLStreamHandler)cls.newInstance();
410             } catch (Exception e) {
411                 // ignore and try next one
412             }
413         }
414         return null;
415     }
416 
417 }