OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [net/] [URLClassLoader.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* URLClassLoader.java --  ClassLoader that loads classes from one or more URLs
2
   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GNU Classpath.
6
 
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING.  If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301 USA.
21
 
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library.  Thus, the terms and
24
conditions of the GNU General Public License cover the whole
25
combination.
26
 
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module.  An independent module is a module which is not derived from
34
or based on this library.  If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so.  If you do not wish to do so, delete this
37
exception statement from your version. */
38
 
39
 
40
package java.net;
41
 
42
import java.io.ByteArrayOutputStream;
43
import java.io.EOFException;
44
import java.io.File;
45
import java.io.FileInputStream;
46
import java.io.FilePermission;
47
import java.io.IOException;
48
import java.io.InputStream;
49
import java.security.AccessControlContext;
50
import java.security.AccessController;
51
import java.security.CodeSource;
52
import java.security.PermissionCollection;
53
import java.security.PrivilegedAction;
54
import java.security.SecureClassLoader;
55
import java.security.cert.Certificate;
56
import java.util.Enumeration;
57
import java.util.HashMap;
58
import java.util.Iterator;
59
import java.util.StringTokenizer;
60
import java.util.Vector;
61
import java.util.jar.Attributes;
62
import java.util.jar.JarEntry;
63
import java.util.jar.JarFile;
64
import java.util.jar.Manifest;
65
 
66
 
67
/**
68
 * A secure class loader that can load classes and resources from
69
 * multiple locations.  Given an array of <code>URL</code>s this class
70
 * loader will retrieve classes and resources by fetching them from
71
 * possible remote locations.  Each <code>URL</code> is searched in
72
 * order in which it was added.  If the file portion of the
73
 * <code>URL</code> ends with a '/' character then it is interpreted
74
 * as a base directory, otherwise it is interpreted as a jar file from
75
 * which the classes/resources are resolved.
76
 *
77
 * <p>New instances can be created by two static
78
 * <code>newInstance()</code> methods or by three public
79
 * contructors. Both ways give the option to supply an initial array
80
 * of <code>URL</code>s and (optionally) a parent classloader (that is
81
 * different from the standard system class loader).</p>
82
 *
83
 * <p>Normally creating a <code>URLClassLoader</code> throws a
84
 * <code>SecurityException</code> if a <code>SecurityManager</code> is
85
 * installed and the <code>checkCreateClassLoader()</code> method does
86
 * not return true.  But the <code>newInstance()</code> methods may be
87
 * used by any code as long as it has permission to acces the given
88
 * <code>URL</code>s.  <code>URLClassLoaders</code> created by the
89
 * <code>newInstance()</code> methods also explicitly call the
90
 * <code>checkPackageAccess()</code> method of
91
 * <code>SecurityManager</code> if one is installed before trying to
92
 * load a class.  Note that only subclasses of
93
 * <code>URLClassLoader</code> can add new URLs after the
94
 * URLClassLoader had been created. But it is always possible to get
95
 * an array of all URLs that the class loader uses to resolve classes
96
 * and resources by way of the <code>getURLs()</code> method.</p>
97
 *
98
 * <p>Open issues:
99
 * <ul>
100
 *
101
 * <li>Should the URLClassLoader actually add the locations found in
102
 * the manifest or is this the responsibility of some other
103
 * loader/(sub)class?  (see <a
104
 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
105
 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
106
 *
107
 * <li>How does <code>definePackage()</code> and sealing work
108
 * precisely?</li>
109
 *
110
 * <li>We save and use the security context (when a created by
111
 * <code>newInstance()</code> but do we have to use it in more
112
 * places?</li>
113
 *
114
 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
115
 *
116
 * </ul>
117
 * </p>
118
 *
119
 * @since 1.2
120
 *
121
 * @author Mark Wielaard (mark@klomp.org)
122
 * @author Wu Gansha (gansha.wu@intel.com)
123
 */
124
public class URLClassLoader extends SecureClassLoader
125
{
126
  // Class Variables
127
 
128
  /**
129
   * A global cache to store mappings between URLLoader and URL,
130
   * so we can avoid do all the homework each time the same URL
131
   * comes.
132
   * XXX - Keeps these loaders forever which prevents garbage collection.
133
   */
134
  private static HashMap urlloaders = new HashMap();
135
 
136
  /**
137
   * A cache to store mappings between handler factory and its
138
   * private protocol handler cache (also a HashMap), so we can avoid
139
   * create handlers each time the same protocol comes.
140
   */
141
  private static HashMap factoryCache = new HashMap(5);
142
 
143
  // Instance variables
144
 
145
  /** Locations to load classes from */
146
  private final Vector urls = new Vector();
147
 
148
  /**
149
   * Store pre-parsed information for each url into this vector: each
150
   * element is a URL loader.  A jar file has its own class-path
151
   * attribute which adds to the URLs that will be searched, but this
152
   * does not add to the list of urls.
153
   */
154
  private final Vector urlinfos = new Vector();
155
 
156
  /** Factory used to get the protocol handlers of the URLs */
157
  private final URLStreamHandlerFactory factory;
158
 
159
  /**
160
   * The security context when created from <code>newInstance()</code>
161
   * or null when created through a normal constructor or when no
162
   * <code>SecurityManager</code> was installed.
163
   */
164
  private final AccessControlContext securityContext;
165
 
166
  // Helper classes
167
 
168
  /**
169
   * A <code>URLLoader</code> contains all logic to load resources from a
170
   * given base <code>URL</code>.
171
   */
172
  abstract static class URLLoader
173
  {
174
    /**
175
     * Our classloader to get info from if needed.
176
     */
177
    final URLClassLoader classloader;
178
 
179
    /**
180
     * The base URL from which all resources are loaded.
181
     */
182
    final URL baseURL;
183
 
184
    /**
185
     * A <code>CodeSource</code> without any associated certificates.
186
     * It is common for classes to not have certificates associated
187
     * with them.  If they come from the same <code>URLLoader</code>
188
     * then it is safe to share the associated <code>CodeSource</code>
189
     * between them since <code>CodeSource</code> is immutable.
190
     */
191
    final CodeSource noCertCodeSource;
192
 
193
    URLLoader(URLClassLoader classloader, URL baseURL)
194
    {
195
      this(classloader, baseURL, baseURL);
196
    }
197
 
198
    URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL)
199
    {
200
      this.classloader = classloader;
201
      this.baseURL = baseURL;
202
      this.noCertCodeSource = new CodeSource(overrideURL, null);
203
    }
204
 
205
    /**
206
     * Returns a <code>Resource</code> loaded by this
207
     * <code>URLLoader</code>, or <code>null</code> when no
208
     * <code>Resource</code> with the given name exists.
209
     */
210
    abstract Resource getResource(String s);
211
 
212
    /**
213
     * Returns the <code>Manifest</code> associated with the
214
     * <code>Resource</code>s loaded by this <code>URLLoader</code> or
215
     * <code>null</code> there is no such <code>Manifest</code>.
216
     */
217
    Manifest getManifest()
218
    {
219
      return null;
220
    }
221
 
222
    Vector getClassPath()
223
    {
224
      return null;
225
    }
226
  }
227
 
228
  /**
229
   * A <code>Resource</code> represents a resource in some
230
   * <code>URLLoader</code>. It also contains all information (e.g.,
231
   * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
232
   * <code>InputStream</code>) that is necessary for loading resources
233
   * and creating classes from a <code>URL</code>.
234
   */
235
  abstract static class Resource
236
  {
237
    final URLLoader loader;
238
 
239
    Resource(URLLoader loader)
240
    {
241
      this.loader = loader;
242
    }
243
 
244
    /**
245
     * Returns the non-null <code>CodeSource</code> associated with
246
     * this resource.
247
     */
248
    CodeSource getCodeSource()
249
    {
250
      Certificate[] certs = getCertificates();
251
      if (certs == null)
252
        return loader.noCertCodeSource;
253
      else
254
        return new CodeSource(loader.baseURL, certs);
255
    }
256
 
257
    /**
258
     * Returns <code>Certificates</code> associated with this
259
     * resource, or null when there are none.
260
     */
261
    Certificate[] getCertificates()
262
    {
263
      return null;
264
    }
265
 
266
    /**
267
     * Return a <code>URL</code> that can be used to access this resource.
268
     */
269
    abstract URL getURL();
270
 
271
    /**
272
     * Returns the size of this <code>Resource</code> in bytes or
273
     * <code>-1</code> when unknown.
274
     */
275
    abstract int getLength();
276
 
277
    /**
278
     * Returns the non-null <code>InputStream</code> through which
279
     * this resource can be loaded.
280
     */
281
    abstract InputStream getInputStream() throws IOException;
282
  }
283
 
284
  /**
285
   * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
286
   * only loading from jar url.
287
   */
288
  static final class JarURLLoader extends URLLoader
289
  {
290
    final JarFile jarfile; // The jar file for this url
291
    final URL baseJarURL; // Base jar: url for all resources loaded from jar
292
 
293
    Vector classPath;   // The "Class-Path" attribute of this Jar's manifest
294
 
295
    public JarURLLoader(URLClassLoader classloader, URL baseURL)
296
    {
297
      super(classloader, baseURL);
298
 
299
      // Cache url prefix for all resources in this jar url.
300
      String external = baseURL.toExternalForm();
301
      StringBuffer sb = new StringBuffer(external.length() + 6);
302
      sb.append("jar:");
303
      sb.append(external);
304
      sb.append("!/");
305
      String jarURL = sb.toString();
306
 
307
      this.classPath = null;
308
      URL baseJarURL = null;
309
      JarFile jarfile = null;
310
      try
311
        {
312
          baseJarURL =
313
            new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
314
 
315
          jarfile =
316
            ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
317
 
318
          Manifest manifest;
319
          Attributes attributes;
320
          String classPathString;
321
 
322
          if ((manifest = jarfile.getManifest()) != null
323
              && (attributes = manifest.getMainAttributes()) != null
324
              && ((classPathString
325
                   = attributes.getValue(Attributes.Name.CLASS_PATH))
326
                  != null))
327
            {
328
              this.classPath = new Vector();
329
 
330
              StringTokenizer st = new StringTokenizer(classPathString, " ");
331
              while (st.hasMoreElements ())
332
                {
333
                  String e = st.nextToken ();
334
                  try
335
                    {
336
                      URL url = new URL(baseURL, e);
337
                      this.classPath.add(url);
338
                    }
339
                  catch (java.net.MalformedURLException xx)
340
                    {
341
                      // Give up
342
                    }
343
                }
344
            }
345
        }
346
      catch (IOException ioe)
347
        {
348
          /* ignored */
349
        }
350
 
351
      this.baseJarURL = baseJarURL;
352
      this.jarfile = jarfile;
353
    }
354
 
355
    /** get resource with the name "name" in the jar url */
356
    Resource getResource(String name)
357
    {
358
      if (jarfile == null)
359
        return null;
360
 
361
      if (name.startsWith("/"))
362
        name = name.substring(1);
363
 
364
      JarEntry je = jarfile.getJarEntry(name);
365
      if (je != null)
366
        return new JarURLResource(this, name, je);
367
      else
368
        return null;
369
    }
370
 
371
    Manifest getManifest()
372
    {
373
      try
374
        {
375
          return (jarfile == null) ? null : jarfile.getManifest();
376
        }
377
      catch (IOException ioe)
378
        {
379
          return null;
380
        }
381
    }
382
 
383
    Vector getClassPath()
384
    {
385
      return classPath;
386
    }
387
  }
388
 
389
  static final class JarURLResource extends Resource
390
  {
391
    private final JarEntry entry;
392
    private final String name;
393
 
394
    JarURLResource(JarURLLoader loader, String name, JarEntry entry)
395
    {
396
      super(loader);
397
      this.entry = entry;
398
      this.name = name;
399
    }
400
 
401
    InputStream getInputStream() throws IOException
402
    {
403
      return ((JarURLLoader) loader).jarfile.getInputStream(entry);
404
    }
405
 
406
    int getLength()
407
    {
408
      return (int) entry.getSize();
409
    }
410
 
411
    Certificate[] getCertificates()
412
    {
413
      // We have to get the entry from the jar file again, because the
414
      // certificates will not be available until the entire entry has
415
      // been read.
416
      return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name))
417
        .getCertificates();
418
    }
419
 
420
    URL getURL()
421
    {
422
      try
423
        {
424
          return new URL(((JarURLLoader) loader).baseJarURL, name,
425
                         loader.classloader.getURLStreamHandler("jar"));
426
        }
427
      catch (MalformedURLException e)
428
        {
429
          InternalError ie = new InternalError();
430
          ie.initCause(e);
431
          throw ie;
432
        }
433
    }
434
  }
435
 
436
  /**
437
   * Loader for remote directories.
438
   */
439
  static final class RemoteURLLoader extends URLLoader
440
  {
441
    private final String protocol;
442
 
443
    RemoteURLLoader(URLClassLoader classloader, URL url)
444
    {
445
      super(classloader, url);
446
      protocol = url.getProtocol();
447
    }
448
 
449
    /**
450
     * Get a remote resource.
451
     * Returns null if no such resource exists.
452
     */
453
    Resource getResource(String name)
454
    {
455
      try
456
        {
457
          URL url =
458
            new URL(baseURL, name, classloader.getURLStreamHandler(protocol));
459
          URLConnection connection = url.openConnection();
460
 
461
          // Open the connection and check the stream
462
          // just to be sure it exists.
463
          int length = connection.getContentLength();
464
          InputStream stream = connection.getInputStream();
465
 
466
          // We can do some extra checking if it is a http request
467
          if (connection instanceof HttpURLConnection)
468
            {
469
              int response =
470
                ((HttpURLConnection) connection).getResponseCode();
471
              if (response / 100 != 2)
472
                return null;
473
            }
474
 
475
          if (stream != null)
476
            return new RemoteResource(this, name, url, stream, length);
477
          else
478
            return null;
479
        }
480
      catch (IOException ioe)
481
        {
482
          return null;
483
        }
484
    }
485
  }
486
 
487
  /**
488
   * A resource from some remote location.
489
   */
490
  static final class RemoteResource extends Resource
491
  {
492
    private final URL url;
493
    private final InputStream stream;
494
    private final int length;
495
 
496
    RemoteResource(RemoteURLLoader loader, String name, URL url,
497
                   InputStream stream, int length)
498
    {
499
      super(loader);
500
      this.url = url;
501
      this.stream = stream;
502
      this.length = length;
503
    }
504
 
505
    InputStream getInputStream() throws IOException
506
    {
507
      return stream;
508
    }
509
 
510
    public int getLength()
511
    {
512
      return length;
513
    }
514
 
515
    public URL getURL()
516
    {
517
      return url;
518
    }
519
  }
520
 
521
  /**
522
   * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
523
   * only loading from file url.
524
   */
525
  static final class FileURLLoader extends URLLoader
526
  {
527
    File dir; //the file for this file url
528
 
529
    FileURLLoader(URLClassLoader classloader, URL url)
530
    {
531
      super(classloader, url);
532
      dir = new File(baseURL.getFile());
533
    }
534
 
535
    /** get resource with the name "name" in the file url */
536
    Resource getResource(String name)
537
    {
538
      try
539
        {
540
          File file = new File(dir, name).getCanonicalFile();
541
          if (file.exists() && !file.isDirectory())
542
            return new FileResource(this, file);
543
        }
544
      catch (IOException e)
545
        {
546
          // Fall through...
547
        }
548
      return null;
549
    }
550
  }
551
 
552
  static final class FileResource extends Resource
553
  {
554
    final File file;
555
 
556
    FileResource(FileURLLoader loader, File file)
557
    {
558
      super(loader);
559
      this.file = file;
560
    }
561
 
562
    InputStream getInputStream() throws IOException
563
    {
564
      return new FileInputStream(file);
565
    }
566
 
567
    public int getLength()
568
    {
569
      return (int) file.length();
570
    }
571
 
572
    public URL getURL()
573
    {
574
      try
575
        {
576
          return file.toURL();
577
        }
578
      catch (MalformedURLException e)
579
        {
580
          InternalError ie = new InternalError();
581
          ie.initCause(e);
582
          throw ie;
583
        }
584
    }
585
  }
586
 
587
  // Constructors
588
 
589
  /**
590
   * Creates a URLClassLoader that gets classes from the supplied URLs.
591
   * To determine if this classloader may be created the constructor of
592
   * the super class (<code>SecureClassLoader</code>) is called first, which
593
   * can throw a SecurityException. Then the supplied URLs are added
594
   * in the order given to the URLClassLoader which uses these URLs to
595
   * load classes and resources (after using the default parent ClassLoader).
596
   *
597
   * @param urls Locations that should be searched by this ClassLoader when
598
   * resolving Classes or Resources.
599
   * @exception SecurityException if the SecurityManager disallows the
600
   * creation of a ClassLoader.
601
   * @see SecureClassLoader
602
   */
603
  public URLClassLoader(URL[] urls) throws SecurityException
604
  {
605
    super();
606
    this.factory = null;
607
    this.securityContext = null;
608
    addURLs(urls);
609
  }
610
 
611
  /**
612
   * Creates a <code>URLClassLoader</code> that gets classes from the supplied
613
   * <code>URL</code>s.
614
   * To determine if this classloader may be created the constructor of
615
   * the super class (<code>SecureClassLoader</code>) is called first, which
616
   * can throw a SecurityException. Then the supplied URLs are added
617
   * in the order given to the URLClassLoader which uses these URLs to
618
   * load classes and resources (after using the supplied parent ClassLoader).
619
   * @param urls Locations that should be searched by this ClassLoader when
620
   * resolving Classes or Resources.
621
   * @param parent The parent class loader used before trying this class
622
   * loader.
623
   * @exception SecurityException if the SecurityManager disallows the
624
   * creation of a ClassLoader.
625
   * @exception SecurityException
626
   * @see SecureClassLoader
627
   */
628
  public URLClassLoader(URL[] urls, ClassLoader parent)
629
    throws SecurityException
630
  {
631
    super(parent);
632
    this.factory = null;
633
    this.securityContext = null;
634
    addURLs(urls);
635
  }
636
 
637
  // Package-private to avoid a trampoline constructor.
638
  /**
639
   * Package-private constructor used by the static
640
   * <code>newInstance(URL[])</code> method.  Creates an
641
   * <code>URLClassLoader</code> with the given parent but without any
642
   * <code>URL</code>s yet. This is used to bypass the normal security
643
   * check for creating classloaders, but remembers the security
644
   * context which will be used when defining classes.  The
645
   * <code>URL</code>s to load from must be added by the
646
   * <code>newInstance()</code> method in the security context of the
647
   * caller.
648
   *
649
   * @param securityContext the security context of the unprivileged code.
650
   */
651
  URLClassLoader(ClassLoader parent, AccessControlContext securityContext)
652
  {
653
    super(parent);
654
    this.factory = null;
655
    this.securityContext = securityContext;
656
  }
657
 
658
  /**
659
   * Creates a URLClassLoader that gets classes from the supplied URLs.
660
   * To determine if this classloader may be created the constructor of
661
   * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
662
   * can throw a SecurityException. Then the supplied URLs are added
663
   * in the order given to the URLClassLoader which uses these URLs to
664
   * load classes and resources (after using the supplied parent ClassLoader).
665
   * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
666
   * protocol handlers of the supplied URLs.
667
   * @param urls Locations that should be searched by this ClassLoader when
668
   * resolving Classes or Resources.
669
   * @param parent The parent class loader used before trying this class
670
   * loader.
671
   * @param factory Used to get the protocol handler for the URLs.
672
   * @exception SecurityException if the SecurityManager disallows the
673
   * creation of a ClassLoader.
674
   * @exception SecurityException
675
   * @see SecureClassLoader
676
   */
677
  public URLClassLoader(URL[] urls, ClassLoader parent,
678
                        URLStreamHandlerFactory factory)
679
    throws SecurityException
680
  {
681
    super(parent);
682
    this.securityContext = null;
683
    this.factory = factory;
684
    addURLs(urls);
685
 
686
    // If this factory is still not in factoryCache, add it,
687
    //   since we only support three protocols so far, 5 is enough
688
    //   for cache initial size
689
    synchronized (factoryCache)
690
      {
691
        if (factory != null && factoryCache.get(factory) == null)
692
          factoryCache.put(factory, new HashMap(5));
693
      }
694
  }
695
 
696
  // Methods
697
 
698
  /**
699
   * Adds a new location to the end of the internal URL store.
700
   * @param newUrl the location to add
701
   */
702
  protected void addURL(URL newUrl)
703
  {
704
    urls.add(newUrl);
705
    addURLImpl(newUrl);
706
  }
707
 
708
  private void addURLImpl(URL newUrl)
709
  {
710
    synchronized (this)
711
      {
712
        if (newUrl == null)
713
          return; // Silently ignore...
714
 
715
        // Reset the toString() value.
716
        thisString = null;
717
 
718
        // Check global cache to see if there're already url loader
719
        // for this url.
720
        URLLoader loader = (URLLoader) urlloaders.get(newUrl);
721
        if (loader == null)
722
          {
723
            String file = newUrl.getFile();
724
            String protocol = newUrl.getProtocol();
725
 
726
            // Check that it is not a directory
727
            if (! (file.endsWith("/") || file.endsWith(File.separator)))
728
              loader = new JarURLLoader(this, newUrl);
729
            else if ("file".equals(protocol))
730
              loader = new FileURLLoader(this, newUrl);
731
            else
732
              loader = new RemoteURLLoader(this, newUrl);
733
 
734
            // Cache it.
735
            urlloaders.put(newUrl, loader);
736
          }
737
 
738
        urlinfos.add(loader);
739
 
740
        Vector extraUrls = loader.getClassPath();
741
        if (extraUrls != null)
742
          {
743
            Iterator it = extraUrls.iterator();
744
            while (it.hasNext())
745
              {
746
                URL url = (URL)it.next();
747
                URLLoader extraLoader = (URLLoader) urlloaders.get(url);
748
                if (! urlinfos.contains (extraLoader))
749
                  addURLImpl(url);
750
              }
751
          }
752
 
753
      }
754
  }
755
 
756
  /**
757
   * Adds an array of new locations to the end of the internal URL
758
   * store.  Called from the the constructors. Should not call to the
759
   * protected addURL() method since that can be overridden and
760
   * subclasses are not yet in a good state at this point.
761
   * jboss 4.0.3 for example depends on this.
762
   *
763
   * @param newUrls the locations to add
764
   */
765
  private void addURLs(URL[] newUrls)
766
  {
767
    for (int i = 0; i < newUrls.length; i++)
768
      {
769
        urls.add(newUrls[i]);
770
        addURLImpl(newUrls[i]);
771
      }
772
  }
773
 
774
  /**
775
   * Look in both Attributes for a given value.  The first Attributes
776
   * object, if not null, has precedence.
777
   */
778
  private String getAttributeValue(Attributes.Name name, Attributes first,
779
                                   Attributes second)
780
  {
781
    String result = null;
782
    if (first != null)
783
      result = first.getValue(name);
784
    if (result == null)
785
      result = second.getValue(name);
786
    return result;
787
  }
788
 
789
  /**
790
   * Defines a Package based on the given name and the supplied manifest
791
   * information. The manifest indicates the title, version and
792
   * vendor information of the specification and implementation and whether the
793
   * package is sealed. If the Manifest indicates that the package is sealed
794
   * then the Package will be sealed with respect to the supplied URL.
795
   *
796
   * @param name The name of the package
797
   * @param manifest The manifest describing the specification,
798
   * implementation and sealing details of the package
799
   * @param url the code source url to seal the package
800
   * @return the defined Package
801
   * @throws IllegalArgumentException If this package name already exists
802
   * in this class loader
803
   */
804
  protected Package definePackage(String name, Manifest manifest, URL url)
805
    throws IllegalArgumentException
806
  {
807
    // Compute the name of the package as it may appear in the
808
    // Manifest.
809
    StringBuffer xform = new StringBuffer(name);
810
    for (int i = xform.length () - 1; i >= 0; --i)
811
      if (xform.charAt(i) == '.')
812
        xform.setCharAt(i, '/');
813
    xform.append('/');
814
    String xformName = xform.toString();
815
 
816
    Attributes entryAttr = manifest.getAttributes(xformName);
817
    Attributes attr = manifest.getMainAttributes();
818
 
819
    String specTitle
820
      = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE,
821
                          entryAttr, attr);
822
    String specVersion
823
      = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION,
824
                          entryAttr, attr);
825
    String specVendor
826
      = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR,
827
                          entryAttr, attr);
828
    String implTitle
829
      = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE,
830
                          entryAttr, attr);
831
    String implVersion
832
      = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION,
833
                          entryAttr, attr);
834
    String implVendor
835
      = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR,
836
                          entryAttr, attr);
837
 
838
    // Look if the Manifest indicates that this package is sealed
839
    // XXX - most likely not completely correct!
840
    // Shouldn't we also check the sealed attribute of the complete jar?
841
    // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
842
    // But how do we get that jar manifest here?
843
    String sealed = attr.getValue(Attributes.Name.SEALED);
844
    if ("false".equals(sealed))
845
      // make sure that the URL is null so the package is not sealed
846
      url = null;
847
 
848
    return definePackage(name,
849
                         specTitle, specVendor, specVersion,
850
                         implTitle, implVendor, implVersion,
851
                         url);
852
  }
853
 
854
  /**
855
   * Finds (the first) class by name from one of the locations. The locations
856
   * are searched in the order they were added to the URLClassLoader.
857
   *
858
   * @param className the classname to find
859
   * @exception ClassNotFoundException when the class could not be found or
860
   * loaded
861
   * @return a Class object representing the found class
862
   */
863
  protected Class findClass(final String className)
864
    throws ClassNotFoundException
865
  {
866
    // Just try to find the resource by the (almost) same name
867
    String resourceName = className.replace('.', '/') + ".class";
868
    Resource resource = findURLResource(resourceName);
869
    if (resource == null)
870
      throw new ClassNotFoundException(className + " not found in " + this);
871
 
872
    // Try to read the class data, create the CodeSource, Package and
873
    // construct the class (and watch out for those nasty IOExceptions)
874
    try
875
      {
876
        byte[] data;
877
        InputStream in = resource.getInputStream();
878
        try
879
          {
880
            int length = resource.getLength();
881
            if (length != -1)
882
              {
883
                // We know the length of the data.
884
                // Just try to read it in all at once
885
                data = new byte[length];
886
                int pos = 0;
887
                while (length - pos > 0)
888
                  {
889
                    int len = in.read(data, pos, length - pos);
890
                    if (len == -1)
891
                      throw new EOFException("Not enough data reading from: "
892
                                             + in);
893
                    pos += len;
894
                  }
895
              }
896
            else
897
              {
898
                // We don't know the data length.
899
                // Have to read it in chunks.
900
                ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
901
                byte[] b = new byte[4096];
902
                int l = 0;
903
                while (l != -1)
904
                  {
905
                    l = in.read(b);
906
                    if (l != -1)
907
                      out.write(b, 0, l);
908
                  }
909
                data = out.toByteArray();
910
              }
911
          }
912
        finally
913
          {
914
            in.close();
915
          }
916
        final byte[] classData = data;
917
 
918
        // Now get the CodeSource
919
        final CodeSource source = resource.getCodeSource();
920
 
921
        // Find out package name
922
        String packageName = null;
923
        int lastDot = className.lastIndexOf('.');
924
        if (lastDot != -1)
925
          packageName = className.substring(0, lastDot);
926
 
927
        if (packageName != null && getPackage(packageName) == null)
928
          {
929
            // define the package
930
            Manifest manifest = resource.loader.getManifest();
931
            if (manifest == null)
932
              definePackage(packageName, null, null, null, null, null, null,
933
                            null);
934
            else
935
              definePackage(packageName, manifest, resource.loader.baseURL);
936
          }
937
 
938
        // And finally construct the class!
939
        SecurityManager sm = System.getSecurityManager();
940
        Class result = null;
941
        if (sm != null && securityContext != null)
942
          {
943
            result = (Class)AccessController.doPrivileged
944
              (new PrivilegedAction()
945
                {
946
                  public Object run()
947
                  {
948
                    return defineClass(className, classData,
949
                                       0, classData.length,
950
                                       source);
951
                  }
952
                }, securityContext);
953
          }
954
        else
955
          result = defineClass(className, classData, 0, classData.length, source);
956
 
957
        // Avoid NullPointerExceptions.
958
        Certificate[] resourceCertificates = resource.getCertificates();
959
        if(resourceCertificates != null)
960
          super.setSigners(result, resourceCertificates);
961
 
962
        return result;
963
      }
964
    catch (IOException ioe)
965
      {
966
        ClassNotFoundException cnfe;
967
        cnfe = new ClassNotFoundException(className + " not found in " + this);
968
        cnfe.initCause(ioe);
969
        throw cnfe;
970
      }
971
  }
972
 
973
  // Cached String representation of this URLClassLoader
974
  private String thisString;
975
 
976
  /**
977
   * Returns a String representation of this URLClassLoader giving the
978
   * actual Class name, the URLs that are searched and the parent
979
   * ClassLoader.
980
   */
981
  public String toString()
982
  {
983
    synchronized (this)
984
      {
985
        if (thisString == null)
986
          {
987
            StringBuffer sb = new StringBuffer();
988
            sb.append(this.getClass().getName());
989
            sb.append("{urls=[" );
990
            URL[] thisURLs = getURLs();
991
            for (int i = 0; i < thisURLs.length; i++)
992
              {
993
                sb.append(thisURLs[i]);
994
                if (i < thisURLs.length - 1)
995
                  sb.append(',');
996
              }
997
            sb.append(']');
998
            sb.append(", parent=");
999
            sb.append(getParent());
1000
            sb.append('}');
1001
            thisString = sb.toString();
1002
          }
1003
        return thisString;
1004
      }
1005
  }
1006
 
1007
  /**
1008
   * Finds the first occurrence of a resource that can be found. The locations
1009
   * are searched in the order they were added to the URLClassLoader.
1010
   *
1011
   * @param resourceName the resource name to look for
1012
   * @return the URLResource for the resource if found, null otherwise
1013
   */
1014
  private Resource findURLResource(String resourceName)
1015
  {
1016
    int max = urlinfos.size();
1017
    for (int i = 0; i < max; i++)
1018
      {
1019
        URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1020
        if (loader == null)
1021
          continue;
1022
 
1023
        Resource resource = loader.getResource(resourceName);
1024
        if (resource != null)
1025
          return resource;
1026
      }
1027
    return null;
1028
  }
1029
 
1030
  /**
1031
   * Finds the first occurrence of a resource that can be found.
1032
   *
1033
   * @param resourceName the resource name to look for
1034
   * @return the URL if found, null otherwise
1035
   */
1036
  public URL findResource(String resourceName)
1037
  {
1038
    Resource resource = findURLResource(resourceName);
1039
    if (resource != null)
1040
      return resource.getURL();
1041
 
1042
    // Resource not found
1043
    return null;
1044
  }
1045
 
1046
  /**
1047
   * If the URLStreamHandlerFactory has been set this return the appropriate
1048
   * URLStreamHandler for the given protocol, if not set returns null.
1049
   *
1050
   * @param protocol the protocol for which we need a URLStreamHandler
1051
   * @return the appropriate URLStreamHandler or null
1052
   */
1053
  URLStreamHandler getURLStreamHandler(String protocol)
1054
  {
1055
    if (factory == null)
1056
      return null;
1057
 
1058
    URLStreamHandler handler;
1059
    synchronized (factoryCache)
1060
      {
1061
        // Check if there're handler for the same protocol in cache.
1062
        HashMap cache = (HashMap) factoryCache.get(factory);
1063
        handler = (URLStreamHandler) cache.get(protocol);
1064
        if (handler == null)
1065
          {
1066
            // Add it to cache.
1067
            handler = factory.createURLStreamHandler(protocol);
1068
            cache.put(protocol, handler);
1069
          }
1070
      }
1071
    return handler;
1072
  }
1073
 
1074
  /**
1075
   * Finds all the resources with a particular name from all the locations.
1076
   *
1077
   * @param resourceName the name of the resource to lookup
1078
   * @return a (possible empty) enumeration of URLs where the resource can be
1079
   * found
1080
   * @exception IOException when an error occurs accessing one of the
1081
   * locations
1082
   */
1083
  public Enumeration findResources(String resourceName)
1084
    throws IOException
1085
  {
1086
    Vector resources = new Vector();
1087
    int max = urlinfos.size();
1088
    for (int i = 0; i < max; i++)
1089
      {
1090
        URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1091
        Resource resource = loader.getResource(resourceName);
1092
        if (resource != null)
1093
          resources.add(resource.getURL());
1094
      }
1095
    return resources.elements();
1096
  }
1097
 
1098
  /**
1099
   * Returns the permissions needed to access a particular code
1100
   * source.  These permissions includes those returned by
1101
   * <code>SecureClassLoader.getPermissions()</code> and the actual
1102
   * permissions to access the objects referenced by the URL of the
1103
   * code source.  The extra permissions added depend on the protocol
1104
   * and file portion of the URL in the code source. If the URL has
1105
   * the "file" protocol ends with a '/' character then it must be a
1106
   * directory and a file Permission to read everything in that
1107
   * directory and all subdirectories is added. If the URL had the
1108
   * "file" protocol and doesn't end with a '/' character then it must
1109
   * be a normal file and a file permission to read that file is
1110
   * added. If the <code>URL</code> has any other protocol then a
1111
   * socket permission to connect and accept connections from the host
1112
   * portion of the URL is added.
1113
   *
1114
   * @param source The codesource that needs the permissions to be accessed
1115
   * @return the collection of permissions needed to access the code resource
1116
   * @see java.security.SecureClassLoader#getPermissions(CodeSource)
1117
   */
1118
  protected PermissionCollection getPermissions(CodeSource source)
1119
  {
1120
    // XXX - This implementation does exactly as the Javadoc describes.
1121
    // But maybe we should/could use URLConnection.getPermissions()?
1122
    // First get the permissions that would normally be granted
1123
    PermissionCollection permissions = super.getPermissions(source);
1124
 
1125
    // Now add any extra permissions depending on the URL location.
1126
    URL url = source.getLocation();
1127
    String protocol = url.getProtocol();
1128
    if (protocol.equals("file"))
1129
      {
1130
        String file = url.getFile();
1131
 
1132
        // If the file end in / it must be an directory.
1133
        if (file.endsWith("/") || file.endsWith(File.separator))
1134
          {
1135
            // Grant permission to read everything in that directory and
1136
            // all subdirectories.
1137
            permissions.add(new FilePermission(file + "-", "read"));
1138
          }
1139
        else
1140
          {
1141
            // It is a 'normal' file.
1142
            // Grant permission to access that file.
1143
            permissions.add(new FilePermission(file, "read"));
1144
          }
1145
      }
1146
    else
1147
      {
1148
        // Grant permission to connect to and accept connections from host
1149
        String host = url.getHost();
1150
        if (host != null)
1151
          permissions.add(new SocketPermission(host, "connect,accept"));
1152
      }
1153
 
1154
    return permissions;
1155
  }
1156
 
1157
  /**
1158
   * Returns all the locations that this class loader currently uses the
1159
   * resolve classes and resource. This includes both the initially supplied
1160
   * URLs as any URLs added later by the loader.
1161
   * @return All the currently used URLs
1162
   */
1163
  public URL[] getURLs()
1164
  {
1165
    return (URL[]) urls.toArray(new URL[urls.size()]);
1166
  }
1167
 
1168
  /**
1169
   * Creates a new instance of a <code>URLClassLoader</code> that gets
1170
   * classes from the supplied <code>URL</code>s. This class loader
1171
   * will have as parent the standard system class loader.
1172
   *
1173
   * @param urls the initial URLs used to resolve classes and
1174
   * resources
1175
   *
1176
   * @return the class loader
1177
   *
1178
   * @exception SecurityException when the calling code does not have
1179
   * permission to access the given <code>URL</code>s
1180
   */
1181
  public static URLClassLoader newInstance(URL[] urls)
1182
    throws SecurityException
1183
  {
1184
    return newInstance(urls, null);
1185
  }
1186
 
1187
  /**
1188
   * Creates a new instance of a <code>URLClassLoader</code> that gets
1189
   * classes from the supplied <code>URL</code>s and with the supplied
1190
   * loader as parent class loader.
1191
   *
1192
   * @param urls the initial URLs used to resolve classes and
1193
   * resources
1194
   * @param parent the parent class loader
1195
   *
1196
   * @return the class loader
1197
   *
1198
   * @exception SecurityException when the calling code does not have
1199
   * permission to access the given <code>URL</code>s
1200
   */
1201
  public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent)
1202
    throws SecurityException
1203
  {
1204
    SecurityManager sm = System.getSecurityManager();
1205
    if (sm == null)
1206
      return new URLClassLoader(urls, parent);
1207
    else
1208
      {
1209
        final Object securityContext = sm.getSecurityContext();
1210
 
1211
        // XXX - What to do with anything else then an AccessControlContext?
1212
        if (! (securityContext instanceof AccessControlContext))
1213
          throw new SecurityException("securityContext must be AccessControlContext: "
1214
                                      + securityContext);
1215
 
1216
        URLClassLoader loader =
1217
          (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
1218
              {
1219
                public Object run()
1220
                {
1221
                  return new URLClassLoader(parent,
1222
                                            (AccessControlContext) securityContext);
1223
                }
1224
              });
1225
        loader.addURLs(urls);
1226
        return loader;
1227
      }
1228
  }
1229
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.