diff --git a/src/etc/testcases/types/resources/resourcelist.xml b/src/etc/testcases/types/resources/resourcelist.xml new file mode 100644 index 000000000..6b5951914 --- /dev/null +++ b/src/etc/testcases/types/resources/resourcelist.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/types/resources/ResourceList.java b/src/main/org/apache/tools/ant/types/resources/ResourceList.java index 2d4ebf4f5..75da21896 100644 --- a/src/main/org/apache/tools/ant/types/resources/ResourceList.java +++ b/src/main/org/apache/tools/ant/types/resources/ResourceList.java @@ -22,6 +22,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.util.ArrayList; import java.util.Iterator; import java.util.Stack; import java.util.Vector; @@ -32,6 +33,7 @@ import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.filters.util.ChainReaderHelper; import org.apache.tools.ant.types.DataType; import org.apache.tools.ant.types.FilterChain; +import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.util.FileUtils; @@ -43,13 +45,12 @@ import org.apache.tools.ant.util.FileUtils; */ public class ResourceList extends DataType implements ResourceCollection { private final Vector filterChains = new Vector(); - private final Union textDocuments = new Union(); + private final ArrayList textDocuments = new ArrayList(); private final Union cachedResources = new Union(); private volatile boolean cached = false; private String encoding = null; public ResourceList() { - textDocuments.setCache(true); cachedResources.setCache(true); } @@ -61,6 +62,7 @@ public class ResourceList extends DataType implements ResourceCollection { throw noChildrenAllowed(); } textDocuments.add(rc); + setChecked(false); } /** @@ -71,6 +73,7 @@ public class ResourceList extends DataType implements ResourceCollection { throw noChildrenAllowed(); } filterChains.add(filter); + setChecked(false); } /** @@ -89,6 +92,20 @@ public class ResourceList extends DataType implements ResourceCollection { this.encoding = encoding; } + /** + * Makes this instance in effect a reference to another ResourceList + * instance. + */ + public void setRefid(Reference r) throws BuildException { + if (encoding != null) { + throw tooManyAttributes(); + } + if (filterChains.size() > 0 || textDocuments.size() > 0) { + throw noChildrenAllowed(); + } + super.setRefid(r); + } + /** * Fulfill the ResourceCollection contract. The Iterator returned * will throw ConcurrentModificationExceptions if ResourceCollections @@ -99,7 +116,6 @@ public class ResourceList extends DataType implements ResourceCollection { if (isReference()) { return ((ResourceList) getCheckedRef()).iterator(); } - dieOnCircularReference(); return cache().iterator(); } @@ -111,7 +127,6 @@ public class ResourceList extends DataType implements ResourceCollection { if (isReference()) { return ((ResourceList) getCheckedRef()).size(); } - dieOnCircularReference(); return cache().size(); } @@ -123,7 +138,6 @@ public class ResourceList extends DataType implements ResourceCollection { if (isReference()) { return ((ResourceList) getCheckedRef()).isFilesystemOnly(); } - dieOnCircularReference(); return cache().isFilesystemOnly(); } @@ -142,7 +156,12 @@ public class ResourceList extends DataType implements ResourceCollection { if (isReference()) { super.dieOnCircularReference(stk, p); } else { - pushAndInvokeCircularReferenceCheck(textDocuments, stk, p); + for (Iterator iter = textDocuments.iterator(); iter.hasNext(); ) { + Object o = (Object) iter.next(); + if (o instanceof DataType) { + pushAndInvokeCircularReferenceCheck((DataType) o, stk, p); + } + } for (Iterator iter = filterChains.iterator(); iter.hasNext(); ) { FilterChain fc = (FilterChain) iter.next(); pushAndInvokeCircularReferenceCheck(fc, stk, p); @@ -153,8 +172,12 @@ public class ResourceList extends DataType implements ResourceCollection { private synchronized ResourceCollection cache() { if (!cached) { + dieOnCircularReference(); for (Iterator iter = textDocuments.iterator(); iter.hasNext(); ) { - cachedResources.add(read((Resource) iter.next())); + ResourceCollection rc = (ResourceCollection) iter.next(); + for (Iterator r = rc.iterator(); r.hasNext(); ) { + cachedResources.add(read((Resource) r.next())); + } } cached = true; } diff --git a/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java b/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java new file mode 100644 index 000000000..bd34fbbed --- /dev/null +++ b/src/tests/junit/org/apache/tools/ant/types/resources/ResourceListTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tools.ant.types.resources; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.BuildFileTest; +import org.apache.tools.ant.types.FilterChain; +import org.apache.tools.ant.types.Reference; + +public class ResourceListTest extends BuildFileTest { + + protected void setUp() throws Exception { + configureProject("src/etc/testcases/types/resources/resourcelist.xml"); + } + + protected void tearDown() throws Exception { + executeTarget("tearDown"); + } + + public void testEmptyElementWithReference() { + ResourceList rl = new ResourceList(); + rl.setEncoding("foo"); + try { + rl.setRefid(new Reference(getProject(), "dummyref")); + fail("Can add reference to ResourceList with encoding attribute set."); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute when using refid", + be.getMessage()); + } + + rl = new ResourceList(); + rl.setRefid(new Reference(getProject(), "dummyref")); + try { + rl.setEncoding("foo"); + fail("Can set encoding in ResourceList that is a reference"); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute when using refid", + be.getMessage()); + } + + rl = new ResourceList(); + rl.add(new FileResource(getProject(), ".")); + try { + rl.setRefid(new Reference(getProject(), "dummyref")); + fail("Can add reference to ResourceList with nested resource collection."); + } catch (BuildException be) { + assertEquals("You must not specify nested elements when using refid", + be.getMessage()); + } + + rl = new ResourceList(); + rl.setRefid(new Reference(getProject(), "dummyref")); + try { + rl.add(new FileResource(getProject(), ".")); + fail("Can add reference to ResourceList with nested resource collection."); + } catch (BuildException be) { + assertEquals("You must not specify nested elements when using refid", + be.getMessage()); + } + + rl = new ResourceList(); + rl.addFilterChain(new FilterChain()); + try { + rl.setRefid(new Reference(getProject(), "dummyref")); + fail("Can add reference to ResourceList with nested filter chain."); + } catch (BuildException be) { + assertEquals("You must not specify nested elements when using refid", + be.getMessage()); + } + + rl = new ResourceList(); + rl.setRefid(new Reference(getProject(), "dummyref")); + try { + rl.addFilterChain(new FilterChain()); + fail("Can add reference to ResourceList with nested filter chain."); + } catch (BuildException be) { + assertEquals("You must not specify nested elements when using refid", + be.getMessage()); + } + } + + public void testCircularReference() throws Exception { + ResourceList rl1 = new ResourceList(); + rl1.setProject(getProject()); + rl1.setRefid(new Reference(getProject(), "foo")); + + ResourceList rl2 = new ResourceList(); + rl2.setProject(getProject()); + getProject().addReference("foo", rl2); + + Union u = new Union(); + u.add(rl1); + u.setProject(getProject()); + + rl2.add(u); + + try { + rl2.size(); + fail("Can make ResourceList a Reference to itself."); + } catch (BuildException be) { + assertEquals("This data type contains a circular reference.", + be.getMessage()); + } + } +}