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

Subversion Repositories scarts

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

powered by: WebSVN 2.1.0

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