BaseResourceCollectionWrapper. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@278491 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -222,6 +222,8 @@ Ant's "legacy" datatypes have been modified to behave as Resource Collections: | |||
| <li><a href="#restrict">restrict</a> - restrict a resource collection | |||
| to include only resources meeting specified criteria</li> | |||
| <li><a href="#sort">sort</a> - sorted resource collection</li> | |||
| <li><a href="#first">first</a> - first <i>n</i> resources from a | |||
| nested collection</li> | |||
| <li><a href="#union">union</a> - set union of nested resource collections</li> | |||
| <li><a href="#intersect">intersect</a> - set intersection | |||
| of nested resource collections</li> | |||
| @@ -514,6 +516,19 @@ platforms. | |||
| <p>Sorts another nested resource collection according to the resources' | |||
| natural order, or by one or more nested resource comparators:</p> | |||
| <blockquote> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| <tr> | |||
| <td valign="top"><b>Attribute</b></td> | |||
| <td valign="top"><b>Description</b></td> | |||
| <td align="center" valign="top"><b>Required</b></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">cache</td> | |||
| <td valign="top">Whether to cache results; disabling | |||
| may seriously impact performance</td> | |||
| <td valign="top" align="center">No, default <i>true</i></td> | |||
| </tr> | |||
| </table> | |||
| <h4>Parameters specified as nested elements</h4> | |||
| <p>A single resource collection is required.</p> | |||
| <p>The sort can be controlled and customized by specifying one or more | |||
| @@ -532,7 +547,7 @@ natural order, or by one or more nested resource comparators:</p> | |||
| <li><a href="#rcmp.size">size</a> - sort resources by size</li> | |||
| <li><a href="#rcmp.content">content</a> - sort resources by content</li> | |||
| <li><a href="#rcmp.reverse">reverse</a> - reverse the natural sort order, | |||
| or a single nested resource comparator</li> | |||
| or that of a single nested resource comparator</li> | |||
| </ul> | |||
| <h4><a name="rcmp.name">name</a></h4> | |||
| @@ -570,10 +585,38 @@ natural order, or by one or more nested resource comparators:</p> | |||
| </table> | |||
| <h4><a name="rcmp.reverse">reverse</a></h4> | |||
| <p>Reverse the natural sort order, or a single nested comparator.</p> | |||
| <p>Reverse the natural sort order, or that of a single nested comparator.</p> | |||
| </blockquote> | |||
| <h4><a name="first">first</a></h4> | |||
| <p>Includes the first <i>count</i> resources from a nested resource collection. | |||
| This can be used in conjunction with the <a href="#sort">sort</a> collection, | |||
| for example, to select the first few oldest, largest, etc. resources from a | |||
| larger collection.</p> | |||
| <blockquote> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| <tr> | |||
| <td valign="top"><b>Attribute</b></td> | |||
| <td valign="top"><b>Description</b></td> | |||
| <td align="center" valign="top"><b>Required</b></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">count</td> | |||
| <td valign="top">The number of resources to include</td> | |||
| <td valign="top" align="center">No, default 1</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">cache</td> | |||
| <td valign="top">Whether to cache results; disabling | |||
| may seriously impact performance</td> | |||
| <td valign="top" align="center">No, default <i>true</i></td> | |||
| </tr> | |||
| </table> | |||
| <h4>Parameters specified as nested elements</h4> | |||
| <p>A single resource collection is required.</p> | |||
| </blockquote> | |||
| <h4><a name="setlogic">Set operations</a></h4> | |||
| <blockquote> | |||
| <p>The following resource collections implement set operations:</p> | |||
| @@ -592,6 +635,21 @@ natural order, or by one or more nested resource comparators:</p> | |||
| <h4><a name="difference">difference</a></h4> | |||
| <p>Difference of nested resource collections.</p> | |||
| <p>The following attributes apply to all set-operation resource collections: | |||
| </p> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| <tr> | |||
| <td valign="top"><b>Attribute</b></td> | |||
| <td valign="top"><b>Description</b></td> | |||
| <td align="center" valign="top"><b>Required</b></td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">cache</td> | |||
| <td valign="top">Whether to cache results; disabling | |||
| may seriously impact performance</td> | |||
| <td valign="top" align="center">No, default <i>true</i></td> | |||
| </tr> | |||
| </table> | |||
| </blockquote> | |||
| <hr> | |||
| @@ -599,4 +657,4 @@ natural order, or by one or more nested resource comparators:</p> | |||
| Reserved.</p> | |||
| </body> | |||
| </html> | |||
| </html> | |||
| @@ -445,6 +445,50 @@ depends="testfileurl,testfileurlref,testhttpurl1,testhttpurl2,testjarurl,testres | |||
| <target name="single" | |||
| depends="testresource,url,testfile,string,testzipentry,testproperty" /> | |||
| <target name="all" depends="legacy,files,resources,setlogic,single" /> | |||
| <target name="testfirst0"> | |||
| <fail> | |||
| <condition> | |||
| <not> | |||
| <resourcecount count="0"> | |||
| <first count="0"> | |||
| <filelist dir="${dir}" files="1,2,3,4,5" /> | |||
| </first> | |||
| </resourcecount> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| </target> | |||
| <target name="testfirst1"> | |||
| <fail> | |||
| <condition> | |||
| <not> | |||
| <resourcecount count="1"> | |||
| <first> | |||
| <filelist dir="${dir}" files="1,2,3,4,5" /> | |||
| </first> | |||
| </resourcecount> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| </target> | |||
| <target name="testfirst2"> | |||
| <fail> | |||
| <condition> | |||
| <not> | |||
| <resourcecount count="2"> | |||
| <first count="2"> | |||
| <filelist dir="${dir}" files="1,2,3,4,5" /> | |||
| </first> | |||
| </resourcecount> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| </target> | |||
| <target name="first" depends="testfirst0,testfirst1,testfirst2" /> | |||
| <target name="all" depends="legacy,files,resources,setlogic,single,first" /> | |||
| </project> | |||
| @@ -54,6 +54,7 @@ difference=org.apache.tools.ant.types.resources.Difference | |||
| intersect=org.apache.tools.ant.types.resources.Intersect | |||
| sort=org.apache.tools.ant.types.resources.Sort | |||
| resources=org.apache.tools.ant.types.resources.Resources | |||
| first=org.apache.tools.ant.types.resources.First | |||
| #Resources (single-element ResourceCollections): | |||
| resource=org.apache.tools.ant.types.Resource | |||
| @@ -0,0 +1,203 @@ | |||
| /* | |||
| * Copyright 2005 The Apache Software Foundation | |||
| * | |||
| * Licensed 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 java.io.File; | |||
| import java.util.List; | |||
| import java.util.Stack; | |||
| import java.util.Iterator; | |||
| import java.util.ArrayList; | |||
| import java.util.Collection; | |||
| import java.util.Collections; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.types.DataType; | |||
| import org.apache.tools.ant.types.ResourceCollection; | |||
| /** | |||
| * Base class for a ResourceCollection that wraps a single nested | |||
| * ResourceCollection. | |||
| * @since Ant 1.7 | |||
| */ | |||
| public abstract class BaseResourceCollectionWrapper | |||
| extends DataType implements ResourceCollection, Cloneable { | |||
| private static final String ONE_NESTED_MESSAGE | |||
| = " expects exactly one nested resource collection."; | |||
| private ResourceCollection rc; | |||
| private Collection coll = null; | |||
| private boolean cache = true; | |||
| /** | |||
| * Set whether to cache collections. | |||
| * @param b boolean cache flag. | |||
| */ | |||
| public synchronized void setCache(boolean b) { | |||
| cache = b; | |||
| } | |||
| /** | |||
| * Learn whether to cache collections. Default is <code>true</code>. | |||
| * @return boolean cache flag. | |||
| */ | |||
| public synchronized boolean isCache() { | |||
| return cache; | |||
| } | |||
| /** | |||
| * Add a ResourceCollection to the container. | |||
| * @param c the ResourceCollection to add. | |||
| * @throws BuildException on error. | |||
| */ | |||
| public synchronized void add(ResourceCollection c) throws BuildException { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| if (c == null) { | |||
| return; | |||
| } | |||
| if (rc != null) { | |||
| throwOneNested(); | |||
| } | |||
| rc = c; | |||
| setChecked(false); | |||
| } | |||
| /** | |||
| * Fulfill the ResourceCollection contract. | |||
| * @return an Iterator of Resources. | |||
| */ | |||
| public synchronized final Iterator iterator() { | |||
| if (isReference()) { | |||
| return ((BaseResourceCollectionWrapper) getCheckedRef()).iterator(); | |||
| } | |||
| dieOnCircularReference(); | |||
| return cacheCollection().iterator(); | |||
| } | |||
| /** | |||
| * Fulfill the ResourceCollection contract. | |||
| * @return number of elements as int. | |||
| */ | |||
| public synchronized int size() { | |||
| if (isReference()) { | |||
| return ((BaseResourceCollectionWrapper) getCheckedRef()).size(); | |||
| } | |||
| dieOnCircularReference(); | |||
| return cacheCollection().size(); | |||
| } | |||
| /** | |||
| * Fulfill the ResourceCollection contract. | |||
| * @return whether this is a filesystem-only resource collection. | |||
| */ | |||
| public synchronized boolean isFilesystemOnly() { | |||
| if (isReference()) { | |||
| return ((BaseResourceCollectionContainer) getCheckedRef()).isFilesystemOnly(); | |||
| } | |||
| dieOnCircularReference(); | |||
| if (rc == null || rc.isFilesystemOnly()) { | |||
| return true; | |||
| } | |||
| /* now check each Resource in case the child only | |||
| lets through files from any children IT may have: */ | |||
| for (Iterator i = cacheCollection().iterator(); i.hasNext();) { | |||
| if (!(i.next() instanceof FileResource)) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Overrides the version of DataType to recurse on all DataType | |||
| * child elements that may have been added. | |||
| * @param stk the stack of data types to use (recursively). | |||
| * @param p the project to use to dereference the references. | |||
| * @throws BuildException on error. | |||
| */ | |||
| protected synchronized void dieOnCircularReference(Stack stk, Project p) | |||
| throws BuildException { | |||
| if (isChecked()) { | |||
| return; | |||
| } | |||
| if (isReference()) { | |||
| super.dieOnCircularReference(stk, p); | |||
| } else { | |||
| if (rc instanceof DataType) { | |||
| stk.push(rc); | |||
| invokeCircularReferenceCheck((DataType) rc, stk, p); | |||
| stk.pop(); | |||
| } | |||
| setChecked(true); | |||
| } | |||
| } | |||
| /** | |||
| * Get the nested ResourceCollection. | |||
| * @return a ResourceCollection. | |||
| * @throws BuildException if no nested ResourceCollection has been provided. | |||
| */ | |||
| protected synchronized final ResourceCollection getResourceCollection() { | |||
| dieOnCircularReference(); | |||
| if (rc == null) { | |||
| throwOneNested(); | |||
| } | |||
| return rc; | |||
| } | |||
| /** | |||
| * Template method for subclasses to return a Collection of Resources. | |||
| * @return Collection. | |||
| */ | |||
| protected abstract Collection getCollection(); | |||
| /** | |||
| * Format this BaseResourceCollectionWrapper as a String. | |||
| * @return a descriptive <code>String</code>. | |||
| */ | |||
| public synchronized String toString() { | |||
| if (isReference()) { | |||
| return getCheckedRef().toString(); | |||
| } | |||
| if (cacheCollection().size() == 0) { | |||
| return ""; | |||
| } | |||
| StringBuffer sb = new StringBuffer(); | |||
| for (Iterator i = coll.iterator(); i.hasNext();) { | |||
| if (sb.length() > 0) { | |||
| sb.append(File.pathSeparatorChar); | |||
| } | |||
| sb.append(i.next()); | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| private synchronized Collection cacheCollection() { | |||
| if (coll == null || !isCache()) { | |||
| coll = getCollection(); | |||
| } | |||
| return coll; | |||
| } | |||
| private void throwOneNested() throws BuildException { | |||
| throw new BuildException(super.toString() + ONE_NESTED_MESSAGE); | |||
| } | |||
| } | |||
| @@ -0,0 +1,72 @@ | |||
| /* | |||
| * Copyright 2005 The Apache Software Foundation | |||
| * | |||
| * Licensed 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 java.util.List; | |||
| import java.util.Iterator; | |||
| import java.util.ArrayList; | |||
| import java.util.Collection; | |||
| import java.util.Collections; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.types.ResourceCollection; | |||
| /** | |||
| * ResourceCollection that contains the first <code>count</code> elements of | |||
| * another ResourceCollection. | |||
| * @since Ant 1.7 | |||
| */ | |||
| public class First extends BaseResourceCollectionWrapper { | |||
| private static final String BAD_COUNT | |||
| = "count of first resources should be set to an int >= 0"; | |||
| private int count = 1; | |||
| /** | |||
| * Set the number of resources to be included. | |||
| * @param i the count as <code>int</count>. | |||
| */ | |||
| public synchronized void setCount(int i) { | |||
| count = i; | |||
| } | |||
| /** | |||
| * Get the number of resources to be included. Default is 1. | |||
| * @return the count as <code>int</count>. | |||
| */ | |||
| public synchronized int getCount() { | |||
| return count; | |||
| } | |||
| /** | |||
| * Take the first <code>count</code> elements. | |||
| * @return a Collection of Resources. | |||
| */ | |||
| protected Collection getCollection() { | |||
| int ct = getCount(); | |||
| if (ct < 0) { | |||
| throw new BuildException(BAD_COUNT); | |||
| } | |||
| Iterator iter = getResourceCollection().iterator(); | |||
| ArrayList al = new ArrayList(ct); | |||
| for (int i = 0; i < ct && iter.hasNext(); i++) { | |||
| al.add(iter.next()); | |||
| } | |||
| return al; | |||
| } | |||
| } | |||
| @@ -73,6 +73,14 @@ public class ResourceCollectionsTest extends BuildFileTest { | |||
| executeTarget("testfileurlref"); | |||
| } | |||
| public void testfirst1() { | |||
| executeTarget("testfirst1"); | |||
| } | |||
| public void testfirst2() { | |||
| executeTarget("testfirst2"); | |||
| } | |||
| public void testhttpurl1() { | |||
| executeTarget("testhttpurl1"); | |||
| } | |||