URLClassLoader.java 32 KB

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