You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

AntClassLoader.java 59 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant;
  19. import java.io.ByteArrayOutputStream;
  20. import java.io.File;
  21. import java.io.FileInputStream;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.InputStreamReader;
  25. import java.io.Reader;
  26. import java.lang.reflect.Constructor;
  27. import java.net.MalformedURLException;
  28. import java.net.URL;
  29. import java.security.CodeSource;
  30. import java.security.ProtectionDomain;
  31. import java.security.cert.Certificate;
  32. import java.util.Collections;
  33. import java.util.Enumeration;
  34. import java.util.HashMap;
  35. import java.util.Hashtable;
  36. import java.util.Map;
  37. import java.util.StringTokenizer;
  38. import java.util.Vector;
  39. import java.util.Locale;
  40. import java.util.jar.Attributes;
  41. import java.util.jar.Attributes.Name;
  42. import java.util.jar.JarEntry;
  43. import java.util.jar.JarFile;
  44. import java.util.jar.Manifest;
  45. import java.util.zip.ZipEntry;
  46. import java.util.zip.ZipFile;
  47. import org.apache.tools.ant.types.Path;
  48. import org.apache.tools.ant.util.CollectionUtils;
  49. import org.apache.tools.ant.util.FileUtils;
  50. import org.apache.tools.ant.util.JavaEnvUtils;
  51. import org.apache.tools.ant.util.LoaderUtils;
  52. import org.apache.tools.ant.util.ReflectUtil;
  53. import org.apache.tools.ant.util.VectorSet;
  54. import org.apache.tools.ant.launch.Locator;
  55. /**
  56. * Used to load classes within ant with a different classpath from
  57. * that used to start ant. Note that it is possible to force a class
  58. * into this loader even when that class is on the system classpath by
  59. * using the forceLoadClass method. Any subsequent classes loaded by that
  60. * class will then use this loader rather than the system class loader.
  61. *
  62. * <p>
  63. * Note that this classloader has a feature to allow loading
  64. * in reverse order and for "isolation".
  65. * Due to the fact that a number of
  66. * methods in java.lang.ClassLoader are final (at least
  67. * in java 1.4 getResources) this means that the
  68. * class has to fake the given parent.
  69. * </p>
  70. *
  71. */
  72. public class AntClassLoader extends ClassLoader implements SubBuildListener {
  73. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  74. /**
  75. * An enumeration of all resources of a given name found within the
  76. * classpath of this class loader. This enumeration is used by the
  77. * ClassLoader.findResources method, which is in
  78. * turn used by the ClassLoader.getResources method.
  79. *
  80. * @see AntClassLoader#findResources(String)
  81. * @see java.lang.ClassLoader#getResources(String)
  82. */
  83. private class ResourceEnumeration implements Enumeration {
  84. /**
  85. * The name of the resource being searched for.
  86. */
  87. private String resourceName;
  88. /**
  89. * The index of the next classpath element to search.
  90. */
  91. private int pathElementsIndex;
  92. /**
  93. * The URL of the next resource to return in the enumeration. If this
  94. * field is <code>null</code> then the enumeration has been completed,
  95. * i.e., there are no more elements to return.
  96. */
  97. private URL nextResource;
  98. /**
  99. * Constructs a new enumeration of resources of the given name found
  100. * within this class loader's classpath.
  101. *
  102. * @param name the name of the resource to search for.
  103. */
  104. ResourceEnumeration(String name) {
  105. this.resourceName = name;
  106. this.pathElementsIndex = 0;
  107. findNextResource();
  108. }
  109. /**
  110. * Indicates whether there are more elements in the enumeration to
  111. * return.
  112. *
  113. * @return <code>true</code> if there are more elements in the
  114. * enumeration; <code>false</code> otherwise.
  115. */
  116. public boolean hasMoreElements() {
  117. return (this.nextResource != null);
  118. }
  119. /**
  120. * Returns the next resource in the enumeration.
  121. *
  122. * @return the next resource in the enumeration
  123. */
  124. public Object nextElement() {
  125. URL ret = this.nextResource;
  126. findNextResource();
  127. return ret;
  128. }
  129. /**
  130. * Locates the next resource of the correct name in the classpath and
  131. * sets <code>nextResource</code> to the URL of that resource. If no
  132. * more resources can be found, <code>nextResource</code> is set to
  133. * <code>null</code>.
  134. */
  135. private void findNextResource() {
  136. URL url = null;
  137. while ((pathElementsIndex < pathComponents.size()) && (url == null)) {
  138. try {
  139. File pathComponent = (File) pathComponents.elementAt(pathElementsIndex);
  140. url = getResourceURL(pathComponent, this.resourceName);
  141. pathElementsIndex++;
  142. } catch (BuildException e) {
  143. // ignore path elements which are not valid relative to the
  144. // project
  145. }
  146. }
  147. this.nextResource = url;
  148. }
  149. }
  150. /**
  151. * The size of buffers to be used in this classloader.
  152. */
  153. private static final int BUFFER_SIZE = 8192;
  154. /**
  155. * Number of array elements in a test array of strings
  156. */
  157. private static final int NUMBER_OF_STRINGS = 256;
  158. /**
  159. * The components of the classpath that the classloader searches
  160. * for classes.
  161. */
  162. private Vector pathComponents = new VectorSet();
  163. /**
  164. * The project to which this class loader belongs.
  165. */
  166. private Project project;
  167. /**
  168. * Indicates whether the parent class loader should be
  169. * consulted before trying to load with this class loader.
  170. */
  171. private boolean parentFirst = true;
  172. /**
  173. * These are the package roots that are to be loaded by the parent class
  174. * loader regardless of whether the parent class loader is being searched
  175. * first or not.
  176. */
  177. private Vector systemPackages = new Vector();
  178. /**
  179. * These are the package roots that are to be loaded by this class loader
  180. * regardless of whether the parent class loader is being searched first
  181. * or not.
  182. */
  183. private Vector loaderPackages = new Vector();
  184. /**
  185. * Whether or not this classloader will ignore the base
  186. * classloader if it can't find a class.
  187. *
  188. * @see #setIsolated(boolean)
  189. */
  190. private boolean ignoreBase = false;
  191. /**
  192. * The parent class loader, if one is given or can be determined.
  193. */
  194. private ClassLoader parent = null;
  195. /**
  196. * A hashtable of zip files opened by the classloader (File to ZipFile).
  197. */
  198. private Hashtable zipFiles = new Hashtable();
  199. /** Static map of jar file/time to manifest class-path entries */
  200. private static Map/*<String,String>*/ pathMap = Collections.synchronizedMap(new HashMap());
  201. /**
  202. * The context loader saved when setting the thread's current
  203. * context loader.
  204. */
  205. private ClassLoader savedContextLoader = null;
  206. /**
  207. * Whether or not the context loader is currently saved.
  208. */
  209. private boolean isContextLoaderSaved = false;
  210. /**
  211. * Create an Ant ClassLoader for a given project, with
  212. * a parent classloader and an initial classpath.
  213. * @since Ant 1.7.
  214. * @param parent the parent for this classloader.
  215. * @param project The project to which this classloader is to
  216. * belong.
  217. * @param classpath The classpath to use to load classes.
  218. */
  219. public AntClassLoader(ClassLoader parent, Project project, Path classpath) {
  220. setParent(parent);
  221. setClassPath(classpath);
  222. setProject(project);
  223. }
  224. /**
  225. * Create an Ant Class Loader
  226. */
  227. public AntClassLoader() {
  228. setParent(null);
  229. }
  230. /**
  231. * Creates a classloader for the given project using the classpath given.
  232. *
  233. * @param project The project to which this classloader is to belong.
  234. * Must not be <code>null</code>.
  235. * @param classpath The classpath to use to load the classes. This
  236. * is combined with the system classpath in a manner
  237. * determined by the value of ${build.sysclasspath}.
  238. * May be <code>null</code>, in which case no path
  239. * elements are set up to start with.
  240. */
  241. public AntClassLoader(Project project, Path classpath) {
  242. setParent(null);
  243. setProject(project);
  244. setClassPath(classpath);
  245. }
  246. /**
  247. * Creates a classloader for the given project using the classpath given.
  248. *
  249. * @param parent The parent classloader to which unsatisfied loading
  250. * attempts are delegated. May be <code>null</code>,
  251. * in which case the classloader which loaded this
  252. * class is used as the parent.
  253. * @param project The project to which this classloader is to belong.
  254. * Must not be <code>null</code>.
  255. * @param classpath the classpath to use to load the classes.
  256. * May be <code>null</code>, in which case no path
  257. * elements are set up to start with.
  258. * @param parentFirst If <code>true</code>, indicates that the parent
  259. * classloader should be consulted before trying to
  260. * load the a class through this loader.
  261. */
  262. public AntClassLoader(
  263. ClassLoader parent, Project project, Path classpath, boolean parentFirst) {
  264. this(project, classpath);
  265. if (parent != null) {
  266. setParent(parent);
  267. }
  268. setParentFirst(parentFirst);
  269. addJavaLibraries();
  270. }
  271. /**
  272. * Creates a classloader for the given project using the classpath given.
  273. *
  274. * @param project The project to which this classloader is to belong.
  275. * Must not be <code>null</code>.
  276. * @param classpath The classpath to use to load the classes. May be
  277. * <code>null</code>, in which case no path
  278. * elements are set up to start with.
  279. * @param parentFirst If <code>true</code>, indicates that the parent
  280. * classloader should be consulted before trying to
  281. * load the a class through this loader.
  282. */
  283. public AntClassLoader(Project project, Path classpath, boolean parentFirst) {
  284. this(null, project, classpath, parentFirst);
  285. }
  286. /**
  287. * Creates an empty class loader. The classloader should be configured
  288. * with path elements to specify where the loader is to look for
  289. * classes.
  290. *
  291. * @param parent The parent classloader to which unsatisfied loading
  292. * attempts are delegated. May be <code>null</code>,
  293. * in which case the classloader which loaded this
  294. * class is used as the parent.
  295. * @param parentFirst If <code>true</code>, indicates that the parent
  296. * classloader should be consulted before trying to
  297. * load the a class through this loader.
  298. */
  299. public AntClassLoader(ClassLoader parent, boolean parentFirst) {
  300. setParent(parent);
  301. project = null;
  302. this.parentFirst = parentFirst;
  303. }
  304. /**
  305. * Set the project associated with this class loader
  306. *
  307. * @param project the project instance
  308. */
  309. public void setProject(Project project) {
  310. this.project = project;
  311. if (project != null) {
  312. project.addBuildListener(this);
  313. }
  314. }
  315. /**
  316. * Set the classpath to search for classes to load. This should not be
  317. * changed once the classloader starts to server classes
  318. *
  319. * @param classpath the search classpath consisting of directories and
  320. * jar/zip files.
  321. */
  322. public void setClassPath(Path classpath) {
  323. pathComponents.removeAllElements();
  324. if (classpath != null) {
  325. Path actualClasspath = classpath.concatSystemClasspath("ignore");
  326. String[] pathElements = actualClasspath.list();
  327. for (int i = 0; i < pathElements.length; ++i) {
  328. try {
  329. addPathElement(pathElements[i]);
  330. } catch (BuildException e) {
  331. // ignore path elements which are invalid
  332. // relative to the project
  333. }
  334. }
  335. }
  336. }
  337. /**
  338. * Set the parent for this class loader. This is the class loader to which
  339. * this class loader will delegate to load classes
  340. *
  341. * @param parent the parent class loader.
  342. */
  343. public void setParent(ClassLoader parent) {
  344. this.parent = parent == null ? AntClassLoader.class.getClassLoader() : parent;
  345. }
  346. /**
  347. * Control whether class lookup is delegated to the parent loader first
  348. * or after this loader. Use with extreme caution. Setting this to
  349. * false violates the class loader hierarchy and can lead to Linkage errors
  350. *
  351. * @param parentFirst if true, delegate initial class search to the parent
  352. * classloader.
  353. */
  354. public void setParentFirst(boolean parentFirst) {
  355. this.parentFirst = parentFirst;
  356. }
  357. /**
  358. * Logs a message through the project object if one has been provided.
  359. *
  360. * @param message The message to log.
  361. * Should not be <code>null</code>.
  362. *
  363. * @param priority The logging priority of the message.
  364. */
  365. protected void log(String message, int priority) {
  366. if (project != null) {
  367. project.log(message, priority);
  368. }
  369. }
  370. /**
  371. * Sets the current thread's context loader to this classloader, storing
  372. * the current loader value for later resetting.
  373. */
  374. public void setThreadContextLoader() {
  375. if (isContextLoaderSaved) {
  376. throw new BuildException("Context loader has not been reset");
  377. }
  378. if (LoaderUtils.isContextLoaderAvailable()) {
  379. savedContextLoader = LoaderUtils.getContextClassLoader();
  380. ClassLoader loader = this;
  381. if (project != null && "only".equals(project.getProperty("build.sysclasspath"))) {
  382. loader = this.getClass().getClassLoader();
  383. }
  384. LoaderUtils.setContextClassLoader(loader);
  385. isContextLoaderSaved = true;
  386. }
  387. }
  388. /**
  389. * Resets the current thread's context loader to its original value.
  390. */
  391. public void resetThreadContextLoader() {
  392. if (LoaderUtils.isContextLoaderAvailable() && isContextLoaderSaved) {
  393. LoaderUtils.setContextClassLoader(savedContextLoader);
  394. savedContextLoader = null;
  395. isContextLoaderSaved = false;
  396. }
  397. }
  398. /**
  399. * Adds an element to the classpath to be searched.
  400. *
  401. * @param pathElement The path element to add. Must not be
  402. * <code>null</code>.
  403. *
  404. * @exception BuildException if the given path element cannot be resolved
  405. * against the project.
  406. */
  407. public void addPathElement(String pathElement) throws BuildException {
  408. File pathComponent = project != null ? project.resolveFile(pathElement) : new File(
  409. pathElement);
  410. try {
  411. addPathFile(pathComponent);
  412. } catch (IOException e) {
  413. throw new BuildException(e);
  414. }
  415. }
  416. /**
  417. * Add a path component.
  418. * This simply adds the file, unlike addPathElement
  419. * it does not open jar files and load files from
  420. * their CLASSPATH entry in the manifest file.
  421. * @param file the jar file or directory to add.
  422. */
  423. public void addPathComponent(File file) {
  424. if (pathComponents.contains(file)) {
  425. return;
  426. }
  427. pathComponents.addElement(file);
  428. }
  429. /**
  430. * Add a file to the path.
  431. * Reads the manifest, if available, and adds any additional class path jars
  432. * specified in the manifest.
  433. *
  434. * @param pathComponent the file which is to be added to the path for
  435. * this class loader
  436. *
  437. * @throws IOException if data needed from the file cannot be read.
  438. */
  439. protected void addPathFile(File pathComponent) throws IOException {
  440. if (!pathComponents.contains(pathComponent)) {
  441. pathComponents.addElement(pathComponent);
  442. }
  443. if (pathComponent.isDirectory()) {
  444. return;
  445. }
  446. String absPathPlusTimeAndLength = pathComponent.getAbsolutePath()
  447. + pathComponent.lastModified() + "-" + pathComponent.length();
  448. String classpath = (String) pathMap.get(absPathPlusTimeAndLength);
  449. if (classpath == null) {
  450. ZipFile jarFile = null;
  451. InputStream manifestStream = null;
  452. try {
  453. jarFile = new ZipFile(pathComponent);
  454. manifestStream = jarFile.getInputStream(new ZipEntry("META-INF/MANIFEST.MF"));
  455. if (manifestStream == null) {
  456. return;
  457. }
  458. Reader manifestReader = new InputStreamReader(manifestStream, "UTF-8");
  459. org.apache.tools.ant.taskdefs.Manifest manifest
  460. = new org.apache.tools.ant.taskdefs.Manifest(manifestReader);
  461. classpath = manifest.getMainSection().getAttributeValue("Class-Path");
  462. } catch (org.apache.tools.ant.taskdefs.ManifestException e) {
  463. // ignore
  464. } finally {
  465. FileUtils.close(manifestStream);
  466. if (jarFile != null) {
  467. jarFile.close();
  468. }
  469. }
  470. if (classpath == null) {
  471. classpath = "";
  472. }
  473. pathMap.put(absPathPlusTimeAndLength, classpath);
  474. }
  475. if (!"".equals(classpath)) {
  476. URL baseURL = FILE_UTILS.getFileURL(pathComponent);
  477. StringTokenizer st = new StringTokenizer(classpath);
  478. while (st.hasMoreTokens()) {
  479. String classpathElement = st.nextToken();
  480. URL libraryURL = new URL(baseURL, classpathElement);
  481. if (!libraryURL.getProtocol().equals("file")) {
  482. log("Skipping jar library " + classpathElement
  483. + " since only relative URLs are supported by this" + " loader",
  484. Project.MSG_VERBOSE);
  485. continue;
  486. }
  487. String decodedPath = Locator.decodeUri(libraryURL.getFile());
  488. File libraryFile = new File(decodedPath);
  489. if (libraryFile.exists() && !isInPath(libraryFile)) {
  490. addPathFile(libraryFile);
  491. }
  492. }
  493. }
  494. }
  495. /**
  496. * Returns the classpath this classloader will consult.
  497. *
  498. * @return the classpath used for this classloader, with elements
  499. * separated by the path separator for the system.
  500. */
  501. public String getClasspath() {
  502. StringBuffer sb = new StringBuffer();
  503. boolean firstPass = true;
  504. Enumeration componentEnum = pathComponents.elements();
  505. while (componentEnum.hasMoreElements()) {
  506. if (!firstPass) {
  507. sb.append(System.getProperty("path.separator"));
  508. } else {
  509. firstPass = false;
  510. }
  511. sb.append(((File) componentEnum.nextElement()).getAbsolutePath());
  512. }
  513. return sb.toString();
  514. }
  515. /**
  516. * Sets whether this classloader should run in isolated mode. In
  517. * isolated mode, classes not found on the given classpath will
  518. * not be referred to the parent class loader but will cause a
  519. * ClassNotFoundException.
  520. *
  521. * @param isolated Whether or not this classloader should run in
  522. * isolated mode.
  523. */
  524. public synchronized void setIsolated(boolean isolated) {
  525. ignoreBase = isolated;
  526. }
  527. /**
  528. * Forces initialization of a class in a JDK 1.1 compatible, albeit hacky
  529. * way.
  530. *
  531. * @param theClass The class to initialize.
  532. * Must not be <code>null</code>.
  533. *
  534. * @deprecated since 1.6.x.
  535. * Use Class.forName with initialize=true instead.
  536. */
  537. public static void initializeClass(Class theClass) {
  538. // ***HACK*** We ask the VM to create an instance
  539. // by voluntarily providing illegal arguments to force
  540. // the VM to run the class' static initializer, while
  541. // at the same time not running a valid constructor.
  542. final Constructor[] cons = theClass.getDeclaredConstructors();
  543. //At least one constructor is guaranteed to be there, but check anyway.
  544. if (cons != null) {
  545. if (cons.length > 0 && cons[0] != null) {
  546. final String[] strs = new String[NUMBER_OF_STRINGS];
  547. try {
  548. cons[0].newInstance((Object[]) strs);
  549. // Expecting an exception to be thrown by this call:
  550. // IllegalArgumentException: wrong number of Arguments
  551. } catch (Exception e) {
  552. // Ignore - we are interested only in the side
  553. // effect - that of getting the static initializers
  554. // invoked. As we do not want to call a valid
  555. // constructor to get this side effect, an
  556. // attempt is made to call a hopefully
  557. // invalid constructor - come on, nobody
  558. // would have a constructor that takes in
  559. // 256 String arguments ;-)
  560. // (In fact, they can't - according to JVM spec
  561. // section 4.10, the number of method parameters is limited
  562. // to 255 by the definition of a method descriptor.
  563. // Constructors count as methods here.)
  564. }
  565. }
  566. }
  567. }
  568. /**
  569. * Adds a package root to the list of packages which must be loaded on the
  570. * parent loader.
  571. *
  572. * All subpackages are also included.
  573. *
  574. * @param packageRoot The root of all packages to be included.
  575. * Should not be <code>null</code>.
  576. */
  577. public void addSystemPackageRoot(String packageRoot) {
  578. systemPackages.addElement(packageRoot + (packageRoot.endsWith(".") ? "" : "."));
  579. }
  580. /**
  581. * Adds a package root to the list of packages which must be loaded using
  582. * this loader.
  583. *
  584. * All subpackages are also included.
  585. *
  586. * @param packageRoot The root of all packages to be included.
  587. * Should not be <code>null</code>.
  588. */
  589. public void addLoaderPackageRoot(String packageRoot) {
  590. loaderPackages.addElement(packageRoot + (packageRoot.endsWith(".") ? "" : "."));
  591. }
  592. /**
  593. * Loads a class through this class loader even if that class is available
  594. * on the parent classpath.
  595. *
  596. * This ensures that any classes which are loaded by the returned class
  597. * will use this classloader.
  598. *
  599. * @param classname The name of the class to be loaded.
  600. * Must not be <code>null</code>.
  601. *
  602. * @return the required Class object
  603. *
  604. * @exception ClassNotFoundException if the requested class does not exist
  605. * on this loader's classpath.
  606. */
  607. public Class forceLoadClass(String classname) throws ClassNotFoundException {
  608. log("force loading " + classname, Project.MSG_DEBUG);
  609. Class theClass = findLoadedClass(classname);
  610. if (theClass == null) {
  611. theClass = findClass(classname);
  612. }
  613. return theClass;
  614. }
  615. /**
  616. * Loads a class through this class loader but defer to the parent class
  617. * loader.
  618. *
  619. * This ensures that instances of the returned class will be compatible
  620. * with instances which have already been loaded on the parent
  621. * loader.
  622. *
  623. * @param classname The name of the class to be loaded.
  624. * Must not be <code>null</code>.
  625. *
  626. * @return the required Class object
  627. *
  628. * @exception ClassNotFoundException if the requested class does not exist
  629. * on this loader's classpath.
  630. */
  631. public Class forceLoadSystemClass(String classname) throws ClassNotFoundException {
  632. log("force system loading " + classname, Project.MSG_DEBUG);
  633. Class theClass = findLoadedClass(classname);
  634. if (theClass == null) {
  635. theClass = findBaseClass(classname);
  636. }
  637. return theClass;
  638. }
  639. /**
  640. * Returns a stream to read the requested resource name.
  641. *
  642. * @param name The name of the resource for which a stream is required.
  643. * Must not be <code>null</code>.
  644. *
  645. * @return a stream to the required resource or <code>null</code> if the
  646. * resource cannot be found on the loader's classpath.
  647. */
  648. public InputStream getResourceAsStream(String name) {
  649. InputStream resourceStream = null;
  650. if (isParentFirst(name)) {
  651. resourceStream = loadBaseResource(name);
  652. }
  653. if (resourceStream != null) {
  654. log("ResourceStream for " + name
  655. + " loaded from parent loader", Project.MSG_DEBUG);
  656. } else {
  657. resourceStream = loadResource(name);
  658. if (resourceStream != null) {
  659. log("ResourceStream for " + name
  660. + " loaded from ant loader", Project.MSG_DEBUG);
  661. }
  662. }
  663. if (resourceStream == null && !isParentFirst(name)) {
  664. if (ignoreBase) {
  665. resourceStream = getRootLoader() == null ? null : getRootLoader().getResourceAsStream(name);
  666. } else {
  667. resourceStream = loadBaseResource(name);
  668. }
  669. if (resourceStream != null) {
  670. log("ResourceStream for " + name + " loaded from parent loader",
  671. Project.MSG_DEBUG);
  672. }
  673. }
  674. if (resourceStream == null) {
  675. log("Couldn't load ResourceStream for " + name, Project.MSG_DEBUG);
  676. }
  677. return resourceStream;
  678. }
  679. /**
  680. * Returns a stream to read the requested resource name from this loader.
  681. *
  682. * @param name The name of the resource for which a stream is required.
  683. * Must not be <code>null</code>.
  684. *
  685. * @return a stream to the required resource or <code>null</code> if
  686. * the resource cannot be found on the loader's classpath.
  687. */
  688. private InputStream loadResource(String name) {
  689. // we need to search the components of the path to see if we can
  690. // find the class we want.
  691. InputStream stream = null;
  692. Enumeration e = pathComponents.elements();
  693. while (e.hasMoreElements() && stream == null) {
  694. File pathComponent = (File) e.nextElement();
  695. stream = getResourceStream(pathComponent, name);
  696. }
  697. return stream;
  698. }
  699. /**
  700. * Finds a system resource (which should be loaded from the parent
  701. * classloader).
  702. *
  703. * @param name The name of the system resource to load.
  704. * Must not be <code>null</code>.
  705. *
  706. * @return a stream to the named resource, or <code>null</code> if
  707. * the resource cannot be found.
  708. */
  709. private InputStream loadBaseResource(String name) {
  710. return parent == null ? super.getResourceAsStream(name) : parent.getResourceAsStream(name);
  711. }
  712. /**
  713. * Returns an inputstream to a given resource in the given file which may
  714. * either be a directory or a zip file.
  715. *
  716. * @param file the file (directory or jar) in which to search for the
  717. * resource. Must not be <code>null</code>.
  718. * @param resourceName The name of the resource for which a stream is
  719. * required. Must not be <code>null</code>.
  720. *
  721. * @return a stream to the required resource or <code>null</code> if
  722. * the resource cannot be found in the given file.
  723. */
  724. private InputStream getResourceStream(File file, String resourceName) {
  725. try {
  726. ZipFile zipFile = (ZipFile) zipFiles.get(file);
  727. if (zipFile == null && file.isDirectory()) {
  728. File resource = new File(file, resourceName);
  729. if (resource.exists()) {
  730. return new FileInputStream(resource);
  731. }
  732. } else {
  733. if (zipFile == null) {
  734. if (file.exists()) {
  735. zipFile = new ZipFile(file);
  736. zipFiles.put(file, zipFile);
  737. } else {
  738. return null;
  739. }
  740. //to eliminate a race condition, retrieve the entry
  741. //that is in the hash table under that filename
  742. zipFile = (ZipFile) zipFiles.get(file);
  743. }
  744. ZipEntry entry = zipFile.getEntry(resourceName);
  745. if (entry != null) {
  746. return zipFile.getInputStream(entry);
  747. }
  748. }
  749. } catch (Exception e) {
  750. log("Ignoring Exception " + e.getClass().getName() + ": " + e.getMessage()
  751. + " reading resource " + resourceName + " from " + file, Project.MSG_VERBOSE);
  752. }
  753. return null;
  754. }
  755. /**
  756. * Tests whether or not the parent classloader should be checked for a
  757. * resource before this one. If the resource matches both the "use parent
  758. * classloader first" and the "use this classloader first" lists, the latter
  759. * takes priority.
  760. *
  761. * @param resourceName
  762. * The name of the resource to check. Must not be
  763. * <code>null</code>.
  764. *
  765. * @return whether or not the parent classloader should be checked for a
  766. * resource before this one is.
  767. */
  768. private boolean isParentFirst(String resourceName) {
  769. // default to the global setting and then see
  770. // if this class belongs to a package which has been
  771. // designated to use a specific loader first
  772. // (this one or the parent one)
  773. // XXX - shouldn't this always return false in isolated mode?
  774. boolean useParentFirst = parentFirst;
  775. for (Enumeration e = systemPackages.elements(); e.hasMoreElements();) {
  776. String packageName = (String) e.nextElement();
  777. if (resourceName.startsWith(packageName)) {
  778. useParentFirst = true;
  779. break;
  780. }
  781. }
  782. for (Enumeration e = loaderPackages.elements(); e.hasMoreElements();) {
  783. String packageName = (String) e.nextElement();
  784. if (resourceName.startsWith(packageName)) {
  785. useParentFirst = false;
  786. break;
  787. }
  788. }
  789. return useParentFirst;
  790. }
  791. /**
  792. * Used for isolated resource seaching.
  793. * @return the root classloader of AntClassLoader.
  794. */
  795. private ClassLoader getRootLoader() {
  796. ClassLoader ret = getClass().getClassLoader();
  797. while (ret != null && ret.getParent() != null) {
  798. ret = ret.getParent();
  799. }
  800. return ret;
  801. }
  802. /**
  803. * Finds the resource with the given name. A resource is
  804. * some data (images, audio, text, etc) that can be accessed by class
  805. * code in a way that is independent of the location of the code.
  806. *
  807. * @param name The name of the resource for which a stream is required.
  808. * Must not be <code>null</code>.
  809. *
  810. * @return a URL for reading the resource, or <code>null</code> if the
  811. * resource could not be found or the caller doesn't have
  812. * adequate privileges to get the resource.
  813. */
  814. public URL getResource(String name) {
  815. // we need to search the components of the path to see if
  816. // we can find the class we want.
  817. URL url = null;
  818. if (isParentFirst(name)) {
  819. url = parent == null ? super.getResource(name) : parent.getResource(name);
  820. }
  821. if (url != null) {
  822. log("Resource " + name + " loaded from parent loader", Project.MSG_DEBUG);
  823. } else {
  824. // try and load from this loader if the parent either didn't find
  825. // it or wasn't consulted.
  826. Enumeration e = pathComponents.elements();
  827. while (e.hasMoreElements() && url == null) {
  828. File pathComponent = (File) e.nextElement();
  829. url = getResourceURL(pathComponent, name);
  830. if (url != null) {
  831. log("Resource " + name + " loaded from ant loader", Project.MSG_DEBUG);
  832. }
  833. }
  834. }
  835. if (url == null && !isParentFirst(name)) {
  836. // this loader was first but it didn't find it - try the parent
  837. if (ignoreBase) {
  838. url = getRootLoader() == null ? null : getRootLoader().getResource(name);
  839. } else {
  840. url = parent == null ? super.getResource(name) : parent.getResource(name);
  841. }
  842. if (url != null) {
  843. log("Resource " + name + " loaded from parent loader", Project.MSG_DEBUG);
  844. }
  845. }
  846. if (url == null) {
  847. log("Couldn't load Resource " + name, Project.MSG_DEBUG);
  848. }
  849. return url;
  850. }
  851. /**
  852. * Finds all the resources with the given name. A resource is some
  853. * data (images, audio, text, etc) that can be accessed by class
  854. * code in a way that is independent of the location of the code.
  855. *
  856. * <p>Would override getResources if that wasn't final in Java
  857. * 1.4.</p>
  858. *
  859. * @since Ant 1.8.0
  860. */
  861. public Enumeration/*<URL>*/ getNamedResources(String name)
  862. throws IOException {
  863. return findResources(name, false);
  864. }
  865. /**
  866. * Returns an enumeration of URLs representing all the resources with the
  867. * given name by searching the class loader's classpath.
  868. *
  869. * @param name The resource name to search for.
  870. * Must not be <code>null</code>.
  871. * @return an enumeration of URLs for the resources
  872. * @exception IOException if I/O errors occurs (can't happen)
  873. */
  874. protected Enumeration/*<URL>*/ findResources(String name) throws IOException {
  875. return findResources(name, true);
  876. }
  877. /**
  878. * Returns an enumeration of URLs representing all the resources with the
  879. * given name by searching the class loader's classpath.
  880. *
  881. * @param name The resource name to search for.
  882. * Must not be <code>null</code>.
  883. * @param parentHasBeenSearched whether ClassLoader.this.parent
  884. * has been searched - will be true if the method is (indirectly)
  885. * called from ClassLoader.getResources
  886. * @return an enumeration of URLs for the resources
  887. * @exception IOException if I/O errors occurs (can't happen)
  888. */
  889. protected Enumeration/*<URL>*/ findResources(String name,
  890. boolean parentHasBeenSearched)
  891. throws IOException {
  892. Enumeration/*<URL>*/ mine = new ResourceEnumeration(name);
  893. Enumeration/*<URL>*/ base;
  894. if (parent != null && (!parentHasBeenSearched || parent != getParent())) {
  895. // Delegate to the parent:
  896. base = parent.getResources(name);
  897. // Note: could cause overlaps in case
  898. // ClassLoader.this.parent has matches and
  899. // parentHasBeenSearched is true
  900. } else {
  901. // ClassLoader.this.parent is already delegated to for example from
  902. // ClassLoader.getResources, no need:
  903. base = new CollectionUtils.EmptyEnumeration();
  904. }
  905. if (isParentFirst(name)) {
  906. // Normal case.
  907. return CollectionUtils.append(base, mine);
  908. }
  909. if (ignoreBase) {
  910. return getRootLoader() == null ? mine : CollectionUtils.append(mine, getRootLoader()
  911. .getResources(name));
  912. }
  913. // parent last:
  914. return CollectionUtils.append(mine, base);
  915. }
  916. /**
  917. * Returns the URL of a given resource in the given file which may
  918. * either be a directory or a zip file.
  919. *
  920. * @param file The file (directory or jar) in which to search for
  921. * the resource. Must not be <code>null</code>.
  922. * @param resourceName The name of the resource for which a stream
  923. * is required. Must not be <code>null</code>.
  924. *
  925. * @return a stream to the required resource or <code>null</code> if the
  926. * resource cannot be found in the given file object.
  927. */
  928. protected URL getResourceURL(File file, String resourceName) {
  929. try {
  930. ZipFile zipFile = (ZipFile) zipFiles.get(file);
  931. if (zipFile == null && file.isDirectory()) {
  932. File resource = new File(file, resourceName);
  933. if (resource.exists()) {
  934. try {
  935. return FILE_UTILS.getFileURL(resource);
  936. } catch (MalformedURLException ex) {
  937. return null;
  938. }
  939. }
  940. } else {
  941. if (zipFile == null) {
  942. if (file.exists()) {
  943. zipFile = new ZipFile(file);
  944. zipFiles.put(file, zipFile);
  945. } else {
  946. return null;
  947. }
  948. }
  949. ZipEntry entry = zipFile.getEntry(resourceName);
  950. if (entry != null) {
  951. try {
  952. return new URL("jar:" + FILE_UTILS.getFileURL(file) + "!/" + entry);
  953. } catch (MalformedURLException ex) {
  954. return null;
  955. }
  956. }
  957. }
  958. } catch (Exception e) {
  959. String msg = "Unable to obtain resource from " + file + ": ";
  960. log(msg + e, Project.MSG_WARN);
  961. System.err.println(msg);
  962. e.printStackTrace();
  963. }
  964. return null;
  965. }
  966. /**
  967. * Loads a class with this class loader.
  968. *
  969. * This class attempts to load the class in an order determined by whether
  970. * or not the class matches the system/loader package lists, with the
  971. * loader package list taking priority. If the classloader is in isolated
  972. * mode, failure to load the class in this loader will result in a
  973. * ClassNotFoundException.
  974. *
  975. * @param classname The name of the class to be loaded.
  976. * Must not be <code>null</code>.
  977. * @param resolve <code>true</code> if all classes upon which this class
  978. * depends are to be loaded.
  979. *
  980. * @return the required Class object
  981. *
  982. * @exception ClassNotFoundException if the requested class does not exist
  983. * on the system classpath (when not in isolated mode) or this loader's
  984. * classpath.
  985. */
  986. protected synchronized Class loadClass(String classname, boolean resolve)
  987. throws ClassNotFoundException {
  988. // 'sync' is needed - otherwise 2 threads can load the same class
  989. // twice, resulting in LinkageError: duplicated class definition.
  990. // findLoadedClass avoids that, but without sync it won't work.
  991. Class theClass = findLoadedClass(classname);
  992. if (theClass != null) {
  993. return theClass;
  994. }
  995. if (isParentFirst(classname)) {
  996. try {
  997. theClass = findBaseClass(classname);
  998. log("Class " + classname + " loaded from parent loader " + "(parentFirst)",
  999. Project.MSG_DEBUG);
  1000. } catch (ClassNotFoundException cnfe) {
  1001. theClass = findClass(classname);
  1002. log("Class " + classname + " loaded from ant loader " + "(parentFirst)",
  1003. Project.MSG_DEBUG);
  1004. }
  1005. } else {
  1006. try {
  1007. theClass = findClass(classname);
  1008. log("Class " + classname + " loaded from ant loader", Project.MSG_DEBUG);
  1009. } catch (ClassNotFoundException cnfe) {
  1010. if (ignoreBase) {
  1011. throw cnfe;
  1012. }
  1013. theClass = findBaseClass(classname);
  1014. log("Class " + classname + " loaded from parent loader", Project.MSG_DEBUG);
  1015. }
  1016. }
  1017. if (resolve) {
  1018. resolveClass(theClass);
  1019. }
  1020. return theClass;
  1021. }
  1022. /**
  1023. * Converts the class dot notation to a filesystem equivalent for
  1024. * searching purposes.
  1025. *
  1026. * @param classname The class name in dot format (eg java.lang.Integer).
  1027. * Must not be <code>null</code>.
  1028. *
  1029. * @return the classname in filesystem format (eg java/lang/Integer.class)
  1030. */
  1031. private String getClassFilename(String classname) {
  1032. return classname.replace('.', '/') + ".class";
  1033. }
  1034. /**
  1035. * Define a class given its bytes
  1036. *
  1037. * @param container the container from which the class data has been read
  1038. * may be a directory or a jar/zip file.
  1039. *
  1040. * @param classData the bytecode data for the class
  1041. * @param classname the name of the class
  1042. *
  1043. * @return the Class instance created from the given data
  1044. *
  1045. * @throws IOException if the class data cannot be read.
  1046. */
  1047. protected Class defineClassFromData(File container, byte[] classData, String classname)
  1048. throws IOException {
  1049. definePackage(container, classname);
  1050. ProtectionDomain currentPd = Project.class.getProtectionDomain();
  1051. String classResource = getClassFilename(classname);
  1052. CodeSource src = new CodeSource(FILE_UTILS.getFileURL(container),
  1053. getCertificates(container,
  1054. classResource));
  1055. ProtectionDomain classesPd =
  1056. new ProtectionDomain(src, currentPd.getPermissions(),
  1057. this,
  1058. currentPd.getPrincipals());
  1059. return defineClass(classname, classData, 0, classData.length,
  1060. classesPd);
  1061. }
  1062. /**
  1063. * Define the package information associated with a class.
  1064. *
  1065. * @param container the file containing the class definition.
  1066. * @param className the class name of for which the package information
  1067. * is to be determined.
  1068. *
  1069. * @exception IOException if the package information cannot be read from the
  1070. * container.
  1071. */
  1072. protected void definePackage(File container, String className) throws IOException {
  1073. int classIndex = className.lastIndexOf('.');
  1074. if (classIndex == -1) {
  1075. return;
  1076. }
  1077. String packageName = className.substring(0, classIndex);
  1078. if (getPackage(packageName) != null) {
  1079. // already defined
  1080. return;
  1081. }
  1082. // define the package now
  1083. Manifest manifest = getJarManifest(container);
  1084. if (manifest == null) {
  1085. definePackage(packageName, null, null, null, null, null, null, null);
  1086. } else {
  1087. definePackage(container, packageName, manifest);
  1088. }
  1089. }
  1090. /**
  1091. * Get the manifest from the given jar, if it is indeed a jar and it has a
  1092. * manifest
  1093. *
  1094. * @param container the File from which a manifest is required.
  1095. *
  1096. * @return the jar's manifest or null is the container is not a jar or it
  1097. * has no manifest.
  1098. *
  1099. * @exception IOException if the manifest cannot be read.
  1100. */
  1101. private Manifest getJarManifest(File container) throws IOException {
  1102. if (container.isDirectory()) {
  1103. return null;
  1104. }
  1105. JarFile jarFile = null;
  1106. try {
  1107. jarFile = new JarFile(container);
  1108. return jarFile.getManifest();
  1109. } finally {
  1110. if (jarFile != null) {
  1111. jarFile.close();
  1112. }
  1113. }
  1114. }
  1115. /**
  1116. * Get the certificates for a given jar entry, if it is indeed a jar.
  1117. *
  1118. * @param container the File from which to read the entry
  1119. * @param entry the entry of which the certificates are requested
  1120. *
  1121. * @return the entry's certificates or null is the container is
  1122. * not a jar or it has no certificates.
  1123. *
  1124. * @exception IOException if the manifest cannot be read.
  1125. */
  1126. private Certificate[] getCertificates(File container, String entry)
  1127. throws IOException {
  1128. if (container.isDirectory()) {
  1129. return null;
  1130. }
  1131. JarFile jarFile = null;
  1132. InputStream is = null;
  1133. try {
  1134. jarFile = new JarFile(container);
  1135. JarEntry ent = jarFile.getJarEntry(entry);
  1136. if (ent != null) {
  1137. // must read the input in order to obtain certificates
  1138. is = jarFile.getInputStream(ent);
  1139. while (is.read() >= 0);
  1140. }
  1141. return ent == null ? null : ent.getCertificates();
  1142. } finally {
  1143. FileUtils.close(is);
  1144. if (jarFile != null) {
  1145. jarFile.close();
  1146. }
  1147. }
  1148. }
  1149. /**
  1150. * Define the package information when the class comes from a
  1151. * jar with a manifest
  1152. *
  1153. * @param container the jar file containing the manifest
  1154. * @param packageName the name of the package being defined.
  1155. * @param manifest the jar's manifest
  1156. */
  1157. protected void definePackage(File container, String packageName, Manifest manifest) {
  1158. String sectionName = packageName.replace('.', '/') + "/";
  1159. String specificationTitle = null;
  1160. String specificationVendor = null;
  1161. String specificationVersion = null;
  1162. String implementationTitle = null;
  1163. String implementationVendor = null;
  1164. String implementationVersion = null;
  1165. String sealedString = null;
  1166. URL sealBase = null;
  1167. Attributes sectionAttributes = manifest.getAttributes(sectionName);
  1168. if (sectionAttributes != null) {
  1169. specificationTitle = sectionAttributes.getValue(Name.SPECIFICATION_TITLE);
  1170. specificationVendor = sectionAttributes.getValue(Name.SPECIFICATION_VENDOR);
  1171. specificationVersion = sectionAttributes.getValue(Name.SPECIFICATION_VERSION);
  1172. implementationTitle = sectionAttributes.getValue(Name.IMPLEMENTATION_TITLE);
  1173. implementationVendor = sectionAttributes.getValue(Name.IMPLEMENTATION_VENDOR);
  1174. implementationVersion = sectionAttributes.getValue(Name.IMPLEMENTATION_VERSION);
  1175. sealedString = sectionAttributes.getValue(Name.SEALED);
  1176. }
  1177. Attributes mainAttributes = manifest.getMainAttributes();
  1178. if (mainAttributes != null) {
  1179. if (specificationTitle == null) {
  1180. specificationTitle = mainAttributes.getValue(Name.SPECIFICATION_TITLE);
  1181. }
  1182. if (specificationVendor == null) {
  1183. specificationVendor = mainAttributes.getValue(Name.SPECIFICATION_VENDOR);
  1184. }
  1185. if (specificationVersion == null) {
  1186. specificationVersion = mainAttributes.getValue(Name.SPECIFICATION_VERSION);
  1187. }
  1188. if (implementationTitle == null) {
  1189. implementationTitle = mainAttributes.getValue(Name.IMPLEMENTATION_TITLE);
  1190. }
  1191. if (implementationVendor == null) {
  1192. implementationVendor = mainAttributes.getValue(Name.IMPLEMENTATION_VENDOR);
  1193. }
  1194. if (implementationVersion == null) {
  1195. implementationVersion = mainAttributes.getValue(Name.IMPLEMENTATION_VERSION);
  1196. }
  1197. if (sealedString == null) {
  1198. sealedString = mainAttributes.getValue(Name.SEALED);
  1199. }
  1200. }
  1201. if (sealedString != null && sealedString.toLowerCase(Locale.ENGLISH).equals("true")) {
  1202. try {
  1203. sealBase = new URL(FileUtils.getFileUtils().toURI(container.getAbsolutePath()));
  1204. } catch (MalformedURLException e) {
  1205. // ignore
  1206. }
  1207. }
  1208. definePackage(packageName, specificationTitle, specificationVersion, specificationVendor,
  1209. implementationTitle, implementationVersion, implementationVendor, sealBase);
  1210. }
  1211. /**
  1212. * Reads a class definition from a stream.
  1213. *
  1214. * @param stream The stream from which the class is to be read.
  1215. * Must not be <code>null</code>.
  1216. * @param classname The name of the class in the stream.
  1217. * Must not be <code>null</code>.
  1218. * @param container the file or directory containing the class.
  1219. *
  1220. * @return the Class object read from the stream.
  1221. *
  1222. * @exception IOException if there is a problem reading the class from the
  1223. * stream.
  1224. * @exception SecurityException if there is a security problem while
  1225. * reading the class from the stream.
  1226. */
  1227. private Class getClassFromStream(InputStream stream, String classname, File container)
  1228. throws IOException, SecurityException {
  1229. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  1230. int bytesRead = -1;
  1231. byte[] buffer = new byte[BUFFER_SIZE];
  1232. while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
  1233. baos.write(buffer, 0, bytesRead);
  1234. }
  1235. byte[] classData = baos.toByteArray();
  1236. return defineClassFromData(container, classData, classname);
  1237. }
  1238. /**
  1239. * Searches for and load a class on the classpath of this class loader.
  1240. *
  1241. * @param name The name of the class to be loaded. Must not be
  1242. * <code>null</code>.
  1243. *
  1244. * @return the required Class object
  1245. *
  1246. * @exception ClassNotFoundException if the requested class does not exist
  1247. * on this loader's classpath.
  1248. */
  1249. public Class findClass(String name) throws ClassNotFoundException {
  1250. log("Finding class " + name, Project.MSG_DEBUG);
  1251. return findClassInComponents(name);
  1252. }
  1253. /**
  1254. * Indicate if the given file is in this loader's path
  1255. *
  1256. * @param component the file which is to be checked
  1257. *
  1258. * @return true if the file is in the class path
  1259. */
  1260. protected boolean isInPath(File component) {
  1261. return pathComponents.contains(component);
  1262. }
  1263. /**
  1264. * Finds a class on the given classpath.
  1265. *
  1266. * @param name The name of the class to be loaded. Must not be
  1267. * <code>null</code>.
  1268. *
  1269. * @return the required Class object
  1270. *
  1271. * @exception ClassNotFoundException if the requested class does not exist
  1272. * on this loader's classpath.
  1273. */
  1274. private Class findClassInComponents(String name)
  1275. throws ClassNotFoundException {
  1276. // we need to search the components of the path to see if
  1277. // we can find the class we want.
  1278. InputStream stream = null;
  1279. String classFilename = getClassFilename(name);
  1280. try {
  1281. Enumeration e = pathComponents.elements();
  1282. while (e.hasMoreElements()) {
  1283. File pathComponent = (File) e.nextElement();
  1284. try {
  1285. stream = getResourceStream(pathComponent, classFilename);
  1286. if (stream != null) {
  1287. log("Loaded from " + pathComponent + " "
  1288. + classFilename, Project.MSG_DEBUG);
  1289. return getClassFromStream(stream, name, pathComponent);
  1290. }
  1291. } catch (SecurityException se) {
  1292. throw se;
  1293. } catch (IOException ioe) {
  1294. // ioe.printStackTrace();
  1295. log("Exception reading component " + pathComponent + " (reason: "
  1296. + ioe.getMessage() + ")", Project.MSG_VERBOSE);
  1297. }
  1298. }
  1299. throw new ClassNotFoundException(name);
  1300. } finally {
  1301. FileUtils.close(stream);
  1302. }
  1303. }
  1304. /**
  1305. * Finds a system class (which should be loaded from the same classloader
  1306. * as the Ant core).
  1307. *
  1308. * For JDK 1.1 compatibility, this uses the findSystemClass method if
  1309. * no parent classloader has been specified.
  1310. *
  1311. * @param name The name of the class to be loaded.
  1312. * Must not be <code>null</code>.
  1313. *
  1314. * @return the required Class object
  1315. *
  1316. * @exception ClassNotFoundException if the requested class does not exist
  1317. * on this loader's classpath.
  1318. */
  1319. private Class findBaseClass(String name) throws ClassNotFoundException {
  1320. return parent == null ? findSystemClass(name) : parent.loadClass(name);
  1321. }
  1322. /**
  1323. * Cleans up any resources held by this classloader. Any open archive
  1324. * files are closed.
  1325. */
  1326. public synchronized void cleanup() {
  1327. for (Enumeration e = zipFiles.elements(); e.hasMoreElements();) {
  1328. ZipFile zipFile = (ZipFile) e.nextElement();
  1329. try {
  1330. zipFile.close();
  1331. } catch (IOException ioe) {
  1332. // ignore
  1333. }
  1334. }
  1335. zipFiles = new Hashtable();
  1336. if (project != null) {
  1337. project.removeBuildListener(this);
  1338. }
  1339. project = null;
  1340. }
  1341. /**
  1342. * Gets the parent as has been specified in the constructor or via
  1343. * setParent.
  1344. *
  1345. * @since Ant 1.8.0
  1346. */
  1347. public ClassLoader getConfiguredParent() {
  1348. return parent;
  1349. }
  1350. /**
  1351. * Empty implementation to satisfy the BuildListener interface.
  1352. *
  1353. * @param event the buildStarted event
  1354. */
  1355. public void buildStarted(BuildEvent event) {
  1356. // Not significant for the class loader.
  1357. }
  1358. /**
  1359. * Cleans up any resources held by this classloader at the end
  1360. * of a build.
  1361. *
  1362. * @param event the buildFinished event
  1363. */
  1364. public void buildFinished(BuildEvent event) {
  1365. cleanup();
  1366. }
  1367. /**
  1368. * Cleans up any resources held by this classloader at the end of
  1369. * a subbuild if it has been created for the subbuild's project
  1370. * instance.
  1371. *
  1372. * @param event the buildFinished event
  1373. *
  1374. * @since Ant 1.6.2
  1375. */
  1376. public void subBuildFinished(BuildEvent event) {
  1377. if (event.getProject() == project) {
  1378. cleanup();
  1379. }
  1380. }
  1381. /**
  1382. * Empty implementation to satisfy the BuildListener interface.
  1383. *
  1384. * @param event the buildStarted event
  1385. *
  1386. * @since Ant 1.6.2
  1387. */
  1388. public void subBuildStarted(BuildEvent event) {
  1389. // Not significant for the class loader.
  1390. }
  1391. /**
  1392. * Empty implementation to satisfy the BuildListener interface.
  1393. *
  1394. * @param event the targetStarted event
  1395. */
  1396. public void targetStarted(BuildEvent event) {
  1397. // Not significant for the class loader.
  1398. }
  1399. /**
  1400. * Empty implementation to satisfy the BuildListener interface.
  1401. *
  1402. * @param event the targetFinished event
  1403. */
  1404. public void targetFinished(BuildEvent event) {
  1405. // Not significant for the class loader.
  1406. }
  1407. /**
  1408. * Empty implementation to satisfy the BuildListener interface.
  1409. *
  1410. * @param event the taskStarted event
  1411. */
  1412. public void taskStarted(BuildEvent event) {
  1413. // Not significant for the class loader.
  1414. }
  1415. /**
  1416. * Empty implementation to satisfy the BuildListener interface.
  1417. *
  1418. * @param event the taskFinished event
  1419. */
  1420. public void taskFinished(BuildEvent event) {
  1421. // Not significant for the class loader.
  1422. }
  1423. /**
  1424. * Empty implementation to satisfy the BuildListener interface.
  1425. *
  1426. * @param event the messageLogged event
  1427. */
  1428. public void messageLogged(BuildEvent event) {
  1429. // Not significant for the class loader.
  1430. }
  1431. /**
  1432. * add any libraries that come with different java versions
  1433. * here
  1434. */
  1435. public void addJavaLibraries() {
  1436. Vector packages = JavaEnvUtils.getJrePackages();
  1437. Enumeration e = packages.elements();
  1438. while (e.hasMoreElements()) {
  1439. String packageName = (String) e.nextElement();
  1440. addSystemPackageRoot(packageName);
  1441. }
  1442. }
  1443. /**
  1444. * Returns a <code>String</code> representing this loader.
  1445. * @return the path that this classloader has.
  1446. */
  1447. public String toString() {
  1448. return "AntClassLoader[" + getClasspath() + "]";
  1449. }
  1450. private static Class subClassToLoad = null;
  1451. private static final Class[] CONSTRUCTOR_ARGS = new Class[] {
  1452. ClassLoader.class, Project.class, Path.class, Boolean.TYPE
  1453. };
  1454. static {
  1455. if (JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_5)) {
  1456. try {
  1457. subClassToLoad =
  1458. Class.forName("org.apache.tools.ant.loader.AntClassLoader5");
  1459. } catch (ClassNotFoundException e) {
  1460. // this is Java5 but the installation is lacking our subclass
  1461. }
  1462. }
  1463. }
  1464. /**
  1465. * Factory method
  1466. */
  1467. public static AntClassLoader newAntClassLoader(ClassLoader parent,
  1468. Project project,
  1469. Path path,
  1470. boolean parentFirst) {
  1471. if (subClassToLoad != null) {
  1472. return (AntClassLoader)
  1473. ReflectUtil.newInstance(subClassToLoad,
  1474. CONSTRUCTOR_ARGS,
  1475. new Object[] {
  1476. parent, project, path,
  1477. Boolean.valueOf(parentFirst)
  1478. });
  1479. }
  1480. return new AntClassLoader(parent, project, path, parentFirst);
  1481. }
  1482. }