PR: 30161 Submitted by: Jesse Glick (jglick at netbeans dot org) git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276721 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -48,6 +48,10 @@ Fixed bugs: | |||
| * AbstractCvsTask prematurely closed its outputStream and errorStream. | |||
| Bugzilla 30097. | |||
| * Impossible to use implicit classpath for <taskdef> | |||
| when Ant core loader != Java application loader and Path.systemClassPath taken from ${java.class.path} | |||
| Bugzilla 30161. | |||
| Changes from Ant 1.6.1 to Ant 1.6.2 | |||
| =================================== | |||
| @@ -1456,7 +1456,7 @@ | |||
| <classpath refid="tests-classpath"/> | |||
| <sysproperty key="ant.home" value="${ant.home}"/> | |||
| <sysproperty key="build.tests" value="${build.tests}"/> | |||
| <sysproperty key="build.tests" file="${build.tests}"/> | |||
| <sysproperty key="build.tests.value" value="${build.tests.value}"/> | |||
| <sysproperty key="tests-classpath.value" | |||
| value="${tests-classpath.value}"/> | |||
| @@ -1606,7 +1606,7 @@ | |||
| filtertrace="${junit.filtertrace}"> | |||
| <!-- <jvmarg value="-classic"/> --> | |||
| <sysproperty key="ant.home" value="${ant.home}"/> | |||
| <sysproperty key="build.tests" value="${build.tests}"/> | |||
| <sysproperty key="build.tests" file="${build.tests}"/> | |||
| <sysproperty key="build.tests.value" value="${build.tests.value}"/> | |||
| <sysproperty key="tests-classpath.value" | |||
| value="${tests-classpath.value}"/> | |||
| @@ -32,6 +32,7 @@ import java.util.Vector; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipFile; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.util.CollectionUtils; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| import org.apache.tools.ant.util.JavaEnvUtils; | |||
| import org.apache.tools.ant.util.LoaderUtils; | |||
| @@ -864,8 +865,24 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||
| * @return an enumeration of URLs for the resources | |||
| * @exception IOException if I/O errors occurs (can't happen) | |||
| */ | |||
| protected Enumeration findResources(String name) throws IOException { | |||
| return new ResourceEnumeration(name); | |||
| protected Enumeration/*<URL>*/ findResources(String name) throws IOException { | |||
| Enumeration/*<URL>*/ mine = new ResourceEnumeration(name); | |||
| Enumeration/*<URL>*/ base; | |||
| if (parent != null && parent != getParent()) { | |||
| // Delegate to the parent: | |||
| base = parent.getResources(name); | |||
| // Note: could cause overlaps in case ClassLoader.this.parent has matches. | |||
| } else { | |||
| // ClassLoader.this.parent is already delegated to from ClassLoader.getResources, no need: | |||
| base = new CollectionUtils.EmptyEnumeration(); | |||
| } | |||
| if (isParentFirst(name)) { | |||
| // Normal case. | |||
| return CollectionUtils.append(base, mine); | |||
| } else { | |||
| // Inverted. | |||
| return CollectionUtils.append(mine, base); | |||
| } | |||
| } | |||
| /** | |||
| @@ -113,4 +113,39 @@ public class CollectionUtils { | |||
| } | |||
| } | |||
| /** | |||
| * Append one enumeration to another. | |||
| * Elements are evaluated lazily. | |||
| * @param e1 the first enumeration | |||
| * @param e2 the subsequent enumeration | |||
| * @return an enumeration representing e1 followed by e2 | |||
| * @since Ant 1.6.3 | |||
| */ | |||
| public static Enumeration append(Enumeration e1, Enumeration e2) { | |||
| return new CompoundEnumeration(e1, e2); | |||
| } | |||
| private static final class CompoundEnumeration implements Enumeration { | |||
| private final Enumeration e1, e2; | |||
| public CompoundEnumeration(Enumeration e1, Enumeration e2) { | |||
| this.e1 = e1; | |||
| this.e2 = e2; | |||
| } | |||
| public boolean hasMoreElements() { | |||
| return e1.hasMoreElements() || e2.hasMoreElements(); | |||
| } | |||
| public Object nextElement() throws NoSuchElementException { | |||
| if (e1.hasMoreElements()) { | |||
| return e1.nextElement(); | |||
| } else { | |||
| return e2.nextElement(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -16,8 +16,20 @@ | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import org.apache.tools.ant.types.Path; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.net.URL; | |||
| import java.util.ArrayList; | |||
| import java.util.Arrays; | |||
| import java.util.Collections; | |||
| import java.util.Enumeration; | |||
| import java.util.List; | |||
| import junit.framework.TestCase; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * Test case for ant class loader | |||
| @@ -70,5 +82,56 @@ public class AntClassLoaderTest extends TestCase { | |||
| fail("loader should not fail even if project finished"); | |||
| } | |||
| } | |||
| /** Sample resource present in build/testcases/ */ | |||
| private static final String TEST_RESOURCE = "org/apache/tools/ant/IncludeTest.class"; | |||
| public void testFindResources() throws Exception { | |||
| //System.err.println("loading from: " + AntClassLoader.class.getProtectionDomain().getCodeSource().getLocation()); | |||
| // See bug #30161. | |||
| // This path should contain the class files for these testcases: | |||
| String buildTestcases = System.getProperty("build.tests"); | |||
| assertNotNull("defined ${build.tests}", buildTestcases); | |||
| assertTrue("have a dir " + buildTestcases, new File(buildTestcases).isDirectory()); | |||
| Path path = new Path(p, buildTestcases); | |||
| // A special parent loader which is not the system class loader: | |||
| ClassLoader parent = new ParentLoader(); | |||
| // An AntClassLoader which is supposed to delegate to the parent and then to the disk path: | |||
| ClassLoader acl = new AntClassLoader(parent, p, path, true); | |||
| // The intended result URLs: | |||
| URL urlFromPath = new URL(FileUtils.newFileUtils().toURI(buildTestcases) + TEST_RESOURCE); | |||
| URL urlFromParent = new URL("http://ant.apache.org/" + TEST_RESOURCE); | |||
| assertEquals("correct resources (regular delegation order)", | |||
| Arrays.asList(new URL[] {urlFromParent, urlFromPath}), | |||
| enum2List(acl.getResources(TEST_RESOURCE))); | |||
| acl = new AntClassLoader(parent, p, path, false); | |||
| assertEquals("correct resources (reverse delegation order)", | |||
| Arrays.asList(new URL[] {urlFromPath, urlFromParent}), | |||
| enum2List(acl.getResources(TEST_RESOURCE))); | |||
| } | |||
| private static List enum2List(Enumeration e) { | |||
| // JDK 1.4: return Collections.list(e); | |||
| List l = new ArrayList(); | |||
| while (e.hasMoreElements()) { | |||
| l.add(e.nextElement()); | |||
| } | |||
| return l; | |||
| } | |||
| /** Special loader that just knows how to find TEST_RESOURCE. */ | |||
| private static final class ParentLoader extends ClassLoader { | |||
| public ParentLoader() {} | |||
| protected Enumeration findResources(String name) throws IOException { | |||
| if (name.equals(TEST_RESOURCE)) { | |||
| return Collections.enumeration(Collections.singleton(new URL("http://ant.apache.org/" + name))); | |||
| } else { | |||
| return Collections.enumeration(Collections.EMPTY_SET); | |||
| } | |||
| } | |||
| } | |||
| } | |||