diff --git a/docs/manual/CoreTypes/resources.html b/docs/manual/CoreTypes/resources.html new file mode 100644 index 000000000..29e832b41 --- /dev/null +++ b/docs/manual/CoreTypes/resources.html @@ -0,0 +1,600 @@ + + + + + +Resources and Resource Collections + + + + +

Resources

+

+A file-like entity can be abstracted to the concept of a resource. +In addition to providing access to file-like attributes, a resource +implementation should, when possible, provide the means to read content +from and/or write content to the underlying entity. Although the resource +concept was introduced in Ant 1.5.2, resources are available for +explicit use beginning in Ant 1.7. +

+ +

The built-in resource types are:

+ + + +

resource

+ +

A basic resource. Other resource types derive from this basic +type; as such all its attributes are available, though in most cases +irrelevant attributes will be ignored. This and all resource +implementations are also usable as single-element +Resource Collections. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
nameThe name of this resourceNo
existsWhether this resource existsNo, default true
lastmodifiedThe last modification time of this resourceNo
directoryWhether this resource is directory-likeNo, default false
sizeThe size of this resourceNo
+ +

file

+ +

Represents a file accessible via local filesystem conventions.

+ + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
fileThe file represented by this resourceYes
baseThe base directory of this resource. When this + attribute is set, attempts to access the name of the resource + will yield a path relative to this location.No
+ +

zipentry

+ +

Represents an entry in a ZIP archive.

+ + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
zipfileThe zip file containing this resourceYes
nameThe name of the archived resourceYes
encodingThe encoding of the zipfileNo; + platform default used if unspecified
+ +

url

+ +

Represents a URL.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
urlThe url to exposeExactly one of these
fileThe file to expose as a file: url
javaresourceThe Java resource to expose as a jar: url
classpathThe classpath to use when establishing the URL + for a Java resourceNo
+

The classpath along which to search for a Java resource + can also be specified by means of one or more nested + classpath elements. +

+ +

string

+ +

Represents a Java String. As such a string is readable but not writable.

+ + + + + + + + + + + + +
AttributeDescriptionRequired
valueThe value of this resourceYes
+ +

property

+ +

Represents an Ant property.

+ + + + + + + + + + + + +
AttributeDescriptionRequired
nameThe property nameYes
+ +
+

Resource Collections

+

+A Resource Collection is an abstraction of an entity that groups +together a number of resources. Several of +Ant's "legacy" datatypes have been modified to behave as Resource Collections: +

+

+

The additional built-in resource collections are:

+ +

resources

+

A generic resource collection, designed for use with + references. + For example, if a third-party Ant task generates a Resource Collection + of an unknown type, it can still be accessed via a + <resources> collection. The secondary use of this + collection type is as a container of other resource collections, + preserving the order of nested collections as well as + duplicate resources (contrast with union). +

+ +

files

+

A group of files. These files are matched by absolute patterns + taken from a number of PatternSets. + These can be specified as nested <patternset> + elements. In addition, <files> holds an implicit + PatternSet and supports the nested <include>, + <includesfile>, <exclude> + and <excludesfile> elements of PatternSet directly, + as well as PatternSet's attributes. +

+

File Selectors are available as nested + elements. A file must be selected by all selectors in order to be included; + <files> is thus equivalent to an + <and> file selector container. +

+

More simply put, this type is equivalent to a + fileset with no base directory. + Please note that without a base directory, + filesystem scanning is based entirely on include and exclude patterns. + A filename (or any) + selector can only influence the scanning process after + the file has been included based on pattern-based selection. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
includescomma- or space-separated list of patterns + of files that must be includedAt least one of these
includesfilethe name of a file; each line of this file is + taken to be an include pattern.
excludescomma- or space-separated list of patterns + of files that must be excludedNo, default none + (except default excludes when true)
excludesfilethe name of a file; each line of this file is + taken to be an exclude pattern.
defaultexcludesWhether + default excludes + should be usedNo, default true
casesensitiveWhether patterns are case-sensitiveNo, default true
followsymlinksWhether to follow symbolic links + (see note below)No, default true
+ +

Note: All files/directories for which +the canonical path is different from its path are considered symbolic +links. On Unix systems this usually means the file really is a +symbolic link but it may lead to false results on other +platforms. +

+ +

restrict

+

Restricts another nested resource collection using resource selectors: +

+

Parameters specified as nested elements

+

A single resource collection is required.

+

Nested resource selectors are used to "narrow down" the included + resources. These are patterned after file + selectors but are, unsurprisingly, targeted to resources. + Several built-in resource selectors are available in the internal + antlib + org.apache.tools.ant.types.resources.selectors: +

+ + + +

name

+

Selects resources by name.

+ + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
nameThe name pattern to testYes
casesensitiveWhether name comparisons are case-sensitiveNo, default true
+ +

exists

+

Selects existing resources.

+ +

date

+

Selects resources by date.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
millisThe comparison date/time in ms since January 1, 1970One of these
datetimeThe formatted comparison date/time
patternSimpleDateFormat-compatible pattern + for use with the datetime attribute + No, default is "MM/DD/YYYY HH:MM AM_or_PM"
granularityThe number of milliseconds leeway to use when + comparing file modification times. This is needed because not + every file system supports tracking the last modified time to + the millisecond level.No; default varies by platform: + FAT filesystems = 2 sec; Unix = 1 sec; NTFS = 1 ms.
whenOne of "before", "after", "equal"No, default "equal"
+ +

type

+

Selects resources by type (file or directory).

+ + + + + + + + + + + +
AttributeDescriptionRequired
typeOne of "file", "dir"Yes
+ +

size

+

Selects resources by size.

+ + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
sizeThe size to compareYes
whenOne of "equal", "eq", "greater", "gt", "less", "lt", + "ge" (greater or equal), "ne" (not equal), "le" (less or equal)No, default "equal"
+ +

instanceof

+

Selects resources by type.

+ + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
classThe class of which the resource must be an instanceOne of these
typeThe Ant type that must + be assignable from the resource
uriThe uri in which type must be definedNo
+ +

and

+

Selects a resource if it is selected by all nested resource selectors.

+ +

or

+

Selects a resource if it is selected + by at least one nested resource selector.

+ +

not

+

Negates the selection result of the single + nested resource selector allowed.

+ +

none

+

Selects a resource if it is selected + by no nested resource selectors.

+ +

majority

+

Selects a resource if it is selected + by the majority of nested resource selectors.

+ + + + + + + + + + + +
AttributeDescriptionRequired
allowtieWhether a tie (when there is an even number + of nested resource selectors) is considered a majorityNo, default true
+ +
+ +

sort

+ +

Sorts another nested resource collection according to the resources' +natural order, or by one or more nested resource comparators:

+
+

Parameters specified as nested elements

+

A single resource collection is required.

+

The sort can be controlled and customized by specifying one or more + resource comparators. Resources can be sorted according to multiple + criteria; the first specified is the "outermost", while the last + specified is the "innermost". Several built-in resource comparators + are available in the internal antlib + org.apache.tools.ant.types.resources.comparators: +

+ + + +

name

+

Sort resources by name.

+ +

exists

+

Sort resources by existence. + Not existing is considered "less than" existing.

+ +

date

+

Sort resources by date.

+ +

type

+

Sort resources by type (file or directory). + Because directories contain files, they are considered "greater".

+ +

size

+

Sort resources by size.

+ +

content

+

Sort resources by content.

+ + + + + + + + + + + +
AttributeDescriptionRequired
binaryWhether content should be compared in binary mode. + If false, content will be compared without regard to + platform-specific line-ending conventions.No, default true
+ +

reverse

+

Reverse the natural sort order, or a single nested comparator.

+ +
+ +

Set operations

+
+

The following resource collections implement set operations:

+ + +

union

+

Union of nested resource collections.

+ +

intersect

+

Intersection of nested resource collections.

+ +

difference

+

Difference of nested resource collections.

+ +
+ +
+

Copyright © 2005 The Apache Software Foundation. All rights +Reserved.

+ + + diff --git a/docs/manual/conceptstypeslist.html b/docs/manual/conceptstypeslist.html index 6c3ad720a..f69d28a40 100644 --- a/docs/manual/conceptstypeslist.html +++ b/docs/manual/conceptstypeslist.html @@ -31,6 +31,8 @@ PropertySet
I/O Redirectors
Regexp
+Resources
+Resource Collections
Selectors
XMLCatalog
ZipFileSet
diff --git a/src/etc/testcases/taskdefs/concat.xml b/src/etc/testcases/taskdefs/concat.xml index 3c8cb3529..f4c25e3aa 100644 --- a/src/etc/testcases/taskdefs/concat.xml +++ b/src/etc/testcases/taskdefs/concat.xml @@ -15,6 +15,7 @@ + @@ -185,4 +186,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/etc/testcases/taskdefs/optional/depend/depend.xml b/src/etc/testcases/taskdefs/optional/depend/depend.xml index 1ac600974..150df3f13 100644 --- a/src/etc/testcases/taskdefs/optional/depend/depend.xml +++ b/src/etc/testcases/taskdefs/optional/depend/depend.xml @@ -82,6 +82,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/etc/testcases/types/resources/build.xml b/src/etc/testcases/types/resources/build.xml new file mode 100755 index 000000000..c93c24abe --- /dev/null +++ b/src/etc/testcases/types/resources/build.xml @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This is a test. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/etc/testcases/types/resources/comparators/build.xml b/src/etc/testcases/types/resources/comparators/build.xml new file mode 100755 index 000000000..e07eeaa1f --- /dev/null +++ b/src/etc/testcases/types/resources/comparators/build.xml @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/etc/testcases/types/resources/selectors/build.xml b/src/etc/testcases/types/resources/selectors/build.xml new file mode 100755 index 000000000..102ce94bf --- /dev/null +++ b/src/etc/testcases/types/resources/selectors/build.xml @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/Concat.java b/src/main/org/apache/tools/ant/taskdefs/Concat.java index d7a50113c..eafe8772b 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Concat.java +++ b/src/main/org/apache/tools/ant/taskdefs/Concat.java @@ -17,34 +17,46 @@ package org.apache.tools.ant.taskdefs; +import java.io.File; +import java.io.Reader; +import java.io.Writer; +import java.io.FileReader; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.OutputStream; +import java.io.StringReader; import java.io.BufferedReader; import java.io.BufferedWriter; -import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; import java.io.InputStreamReader; -import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringReader; -import java.io.Writer; -import java.util.Enumeration; -import java.util.Iterator; +import java.util.Arrays; import java.util.Vector; +import java.util.Iterator; +import java.util.Enumeration; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.Project; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; -import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; -import org.apache.tools.ant.Task; import org.apache.tools.ant.filters.util.ChainReaderHelper; -import org.apache.tools.ant.types.FileList; +import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.FilterChain; -import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.resources.Restrict; +import org.apache.tools.ant.types.resources.Resources; +import org.apache.tools.ant.types.resources.FileResource; +import org.apache.tools.ant.types.resources.StringResource; +import org.apache.tools.ant.types.resources.selectors.Not; +import org.apache.tools.ant.types.resources.selectors.Exists; +import org.apache.tools.ant.types.resources.selectors.ResourceSelector; import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.ConcatResourceInputStream; /** * This class contains the 'concat' task, used to concatenate a series @@ -68,32 +80,36 @@ public class Concat extends Task { // The size of buffers to be used private static final int BUFFER_SIZE = 8192; - private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + private static final ResourceSelector EXISTS = new Exists(); + private static final ResourceSelector NOT_EXISTS = new Not(EXISTS); + // Attributes. /** * The destination of the stream. If null, the system * console is used. */ - private File destinationFile = null; + private File destinationFile; /** * Whether or not the stream should be appended if the destination file * exists. * Defaults to false. */ - private boolean append = false; + private boolean append; /** * Stores the input file encoding. */ - private String encoding = null; + private String encoding; /** Stores the output file encoding. */ - private String outputEncoding = null; + private String outputEncoding; /** Stores the binary attribute */ - private boolean binary = false; + private boolean binary; // Child elements. @@ -106,25 +122,49 @@ public class Concat extends Task { * Stores a collection of file sets and/or file lists, used to * select multiple files for concatenation. */ - private Vector sources = new Vector(); + private Resources rc; /** for filtering the concatenated */ - private Vector filterChains = null; + private Vector filterChains; /** ignore dates on input files */ - private boolean forceOverwrite = true; + private boolean forceOverwrite = true; /** String to place at the start of the concatented stream */ - private TextElement footer; + private TextElement footer; /** String to place at the end of the concatented stream */ - private TextElement header; + private TextElement header; /** add missing line.separator to files **/ - private boolean fixLastLine = false; + private boolean fixLastLine = false; /** endofline for fixlast line */ - private String eolString = System.getProperty("line.separator"); + private String eolString; /** outputwriter */ - private Writer outputWriter = null; + private Writer outputWriter = null; - /** internal variable - used to collect the source files from sources */ - private Vector sourceFiles = new Vector(); + /** + * Construct a new Concat task. + */ + public Concat() { + reset(); + } + + /** + * Reset state to default. + */ + public void reset() { + append = false; + forceOverwrite = true; + destinationFile = null; + encoding = null; + outputEncoding = null; + fixLastLine = false; + filterChains = null; + footer = null; + header = null; + binary = false; + outputWriter = null; + textBuffer = null; + eolString = System.getProperty("line.separator"); + rc = null; + } // Attribute setters. @@ -187,7 +227,7 @@ public class Concat extends Task { */ public Path createPath() { Path path = new Path(getProject()); - sources.addElement(path); + add(path); return path; } @@ -196,7 +236,7 @@ public class Concat extends Task { * @param set the set of files */ public void addFileset(FileSet set) { - sources.addElement(set); + add(set); } /** @@ -204,7 +244,17 @@ public class Concat extends Task { * @param list the list of files */ public void addFilelist(FileList list) { - sources.addElement(list); + add(list); + } + + /** + * Add an arbitrary ResourceCollection. + * @param c the ResourceCollection to add. + * @since Ant 1.7 + */ + public void add(ResourceCollection c) { + rc = (rc == null) ? new Resources() : rc; + rc.add(c); } /** @@ -284,9 +334,9 @@ public class Concat extends Task { } /** - * set the output writer, this is to allow - * concat to be used as a nested element - * @param outputWriter the output writer + * Set the output writer. This is to allow + * concat to be used as a nested element. + * @param outputWriter the output writer. * @since Ant 1.6 */ public void setWriter(Writer outputWriter) { @@ -294,23 +344,20 @@ public class Concat extends Task { } /** - * set the binary attribute. - * if true, concat will concatenate the files - * byte for byte. This mode does not allow - * any filtering, or other modifications - * to the input streams. - * The default value is false. - * @since ant 1.6.2 - * @param binary if true, enable binary mode + * Set the binary attribute. If true, concat will concatenate the files + * byte for byte. This mode does not allow any filtering or other + * modifications to the input streams. The default value is false. + * @since Ant 1.6.2 + * @param binary if true, enable binary mode. */ public void setBinary(boolean binary) { this.binary = binary; } /** - * This method checks the attributes and performs the concatenation. + * Validate configuration options. */ - private void checkAndExecute() { + private ResourceCollection validate() { // treat empty nested text as no text sanitizeText(); @@ -319,9 +366,8 @@ public class Concat extends Task { if (binary) { if (destinationFile == null) { throw new BuildException( - "DestFile attribute is required for binary concatenation"); + "destfile attribute is required for binary concatenation"); } - if (textBuffer != null) { throw new BuildException( "Nested text is incompatible with binary concatenation"); @@ -344,187 +390,117 @@ public class Concat extends Task { "Nested header or footer is incompatible with binary concatenation"); } } - if (destinationFile != null && outputWriter != null) { throw new BuildException( "Cannot specify both a destination file and an output writer"); } - // Sanity check our inputs. - if (sources.size() == 0 && textBuffer == null) { + if (rc == null && textBuffer == null) { // Nothing to concatenate! throw new BuildException( - "At least one file must be provided, or some text."); + "At least one resource must be provided, or some text."); } - - // If using filesets, disallow inline text. This is similar to - // using GNU 'cat' with file arguments -- stdin is simply - // ignored. - if (sources.size() > 0 && textBuffer != null) { - throw new BuildException( - "Cannot include inline text when using filesets."); - } - - // Iterate thru the sources - paths, filesets and filelists - for (Enumeration e = sources.elements(); e.hasMoreElements();) { - Object o = e.nextElement(); - if (o instanceof Path) { - Path path = (Path) o; - checkAddFiles(null, path.list()); - - } else if (o instanceof FileSet) { - FileSet fileSet = (FileSet) o; - DirectoryScanner scanner = - fileSet.getDirectoryScanner(getProject()); - checkAddFiles(fileSet.getDir(getProject()), - scanner.getIncludedFiles()); - - } else if (o instanceof FileList) { - FileList fileList = (FileList) o; - checkAddFiles(fileList.getDir(getProject()), - fileList.getFiles(getProject())); - } - } - - // check if the files are outofdate - if (destinationFile != null && !forceOverwrite - && (sourceFiles.size() > 0) && destinationFile.exists()) { - boolean outofdate = false; - for (int i = 0; i < sourceFiles.size(); ++i) { - File file = (File) sourceFiles.elementAt(i); - if (file.lastModified() > destinationFile.lastModified()) { - outofdate = true; - break; + if (rc != null) { + // If using resources, disallow inline text. This is similar to + // using GNU 'cat' with file arguments -- stdin is simply + // ignored. + if (textBuffer != null) { + throw new BuildException( + "Cannot include inline text when using resources."); + } + Restrict noexistRc = new Restrict(); + noexistRc.add(NOT_EXISTS); + noexistRc.add(rc); + for (Iterator i = noexistRc.iterator(); i.hasNext();) { + log(i.next() + " does not exist.", Project.MSG_ERR); + } + if (destinationFile != null) { + for (Iterator i = rc.iterator(); i.hasNext();) { + Object o = i.next(); + if (o instanceof FileResource) { + File f = ((FileResource) o).getFile(); + if (FILE_UTILS.fileNameEquals(f, destinationFile)) { + throw new BuildException("Input file \"" + + f + "\" is the same as the output file."); + } + } + } + } + Restrict existRc = new Restrict(); + existRc.add(EXISTS); + existRc.add(rc); + boolean outofdate = destinationFile == null || forceOverwrite; + if (!outofdate) { + for (Iterator i = existRc.iterator(); !outofdate && i.hasNext();) { + Resource r = (Resource) i.next(); } } if (!outofdate) { log(destinationFile + " is up-to-date.", Project.MSG_VERBOSE); - return; // no need to do anything + return null; // no need to do anything } - } - - // Do nothing if all the sources are not present - // And textBuffer is null - if (textBuffer == null && sourceFiles.size() == 0 - && header == null && footer == null) { - log("No existing files and no nested text, doing nothing", - Project.MSG_INFO); - return; - } - - if (binary) { - binaryCat(); + return existRc; } else { - cat(); + StringResource s = new StringResource(); + s.setProject(getProject()); + s.setValue(textBuffer.toString()); + return s; } } /** - * execute the concat task. + * Execute the concat task. */ public void execute() { - try { - checkAndExecute(); - } finally { - resetTask(); + ResourceCollection c = validate(); + if (c == null) { + return; } - } - - /** - * Reset state to default. - */ - public void reset() { - append = false; - forceOverwrite = true; - destinationFile = null; - encoding = null; - outputEncoding = null; - fixLastLine = false; - sources.removeAllElements(); - sourceFiles.removeAllElements(); - filterChains = null; - footer = null; - header = null; - } - - /** - * reset the used variables to allow the same task - * instance to be used again. - */ - private void resetTask() { - sourceFiles.clear(); - } - - private void checkAddFiles(File base, String[] filenames) { - for (int i = 0; i < filenames.length; ++i) { - File file = new File(base, filenames[i]); - if (!file.exists()) { - log("File " + file + " does not exist.", Project.MSG_ERR); - continue; - } - if (destinationFile != null - && FILE_UTILS.fileNameEquals(destinationFile, file)) { - throw new BuildException("Input file \"" - + file + "\" " - + "is the same as the output file."); - } - sourceFiles.addElement(file); + // Do nothing if no resources (including nested text) + if (c.size() < 1 && header == null && footer == null) { + log("No existing resources and no nested text, doing nothing", + Project.MSG_INFO); + return; + } + if (binary) { + binaryCat(c); + } else { + cat(c); } } /** perform the binary concatenation */ - private void binaryCat() { - log("Binary concatenation of " + sourceFiles.size() - + " files to " + destinationFile); + private void binaryCat(ResourceCollection c) { + log("Binary concatenation of " + c.size() + + " resources to " + destinationFile); FileOutputStream out = null; - FileInputStream in = null; + InputStream in = null; byte[] buffer = new byte[BUFFER_SIZE]; try { try { out = new FileOutputStream(destinationFile); } catch (Exception t) { - throw new BuildException( - "Unable to open " + destinationFile - + " for writing", t); + throw new BuildException("Unable to open " + + destinationFile + " for writing", t); } - for (Iterator i = sourceFiles.iterator(); i.hasNext();) { - File sourceFile = (File) i.next(); - try { - in = new FileInputStream(sourceFile); - } catch (Exception t) { - throw new BuildException( - "Unable to open input file " + sourceFile, - t); - } - int count = 0; - do { - try { - count = in.read(buffer, 0, buffer.length); - } catch (Exception t) { - throw new BuildException( - "Unable to read from " + sourceFile, t); - } - try { - if (count > 0) { - out.write(buffer, 0, count); - } - } catch (Exception t) { - throw new BuildException( - "Unable to write to " + destinationFile, t); - } - } while (count > 0); - + try { + in = new ConcatResourceInputStream(c); + ((ConcatResourceInputStream) in).setManagingComponent(this); + } catch (IOException e) { + throw new BuildException(e); + } + Thread t = new Thread(new StreamPumper(in, out)); + t.start(); + try { + t.join(); + } catch (InterruptedException e) { try { - in.close(); - } catch (Exception t) { - throw new BuildException( - "Unable to close " + sourceFile, t); + t.join(); + } catch (InterruptedException ee) { } - in = null; } } finally { FileUtils.close(in); - if (out != null) { try { out.close(); @@ -537,13 +513,11 @@ public class Concat extends Task { } /** perform the concatenation */ - private void cat() { + private void cat(ResourceCollection c) { OutputStream os = null; - Reader reader = null; - char[] buffer = new char[BUFFER_SIZE]; + char[] buffer = new char[BUFFER_SIZE]; try { - PrintWriter writer = null; if (outputWriter != null) { @@ -558,11 +532,9 @@ public class Concat extends Task { if (!parent.exists()) { parent.mkdirs(); } - os = new FileOutputStream(destinationFile.getAbsolutePath(), append); } - if (outputEncoding == null) { writer = new PrintWriter( new BufferedWriter( @@ -573,7 +545,6 @@ public class Concat extends Task { new OutputStreamWriter(os, outputEncoding))); } } - if (header != null) { if (header.getFiltering()) { concatenate( @@ -582,16 +553,9 @@ public class Concat extends Task { writer.print(header.getValue()); } } - - if (textBuffer != null) { - reader = new StringReader( - getProject().replaceProperties(textBuffer.substring(0))); - } else { - reader = new MultiReader(); + if (c.size() > 0) { + concatenate(buffer, writer, new MultiReader(c)); } - - concatenate(buffer, writer, reader); - if (footer != null) { if (footer.getFiltering()) { concatenate( @@ -600,34 +564,18 @@ public class Concat extends Task { writer.print(footer.getValue()); } } - writer.flush(); if (os != null) { os.flush(); } - } catch (IOException ioex) { throw new BuildException("Error while concatenating: " + ioex.getMessage(), ioex); } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException ignore) { - // ignore - } - } - if (os != null) { - try { - os.close(); - } catch (IOException ignore) { - // ignore - } - } + FILE_UTILS.close(os); } } - /** Concatenate a single reader to the writer using buffer */ private void concatenate(char[] buffer, Writer writer, Reader in) throws IOException { @@ -639,7 +587,6 @@ public class Concat extends Task { helper.setProject(getProject()); in = new BufferedReader(helper.getAssembledReader()); } - while (true) { int nRead = in.read(buffer, 0, buffer.length); if (nRead == -1) { @@ -647,7 +594,6 @@ public class Concat extends Task { } writer.write(buffer, 0, nRead); } - writer.flush(); } @@ -796,34 +742,34 @@ public class Concat extends Task { * a single stream. */ private class MultiReader extends Reader { - private int pos = 0; private Reader reader = null; private int lastPos = 0; private char[] lastChars = new char[eolString.length()]; private boolean needAddSeparator = false; + private Iterator i; + + private MultiReader(ResourceCollection c) { + i = c.iterator(); + } private Reader getReader() throws IOException { - if (reader == null) { - log("Concating file " + sourceFiles.elementAt(pos), - Project.MSG_VERBOSE); - if (encoding == null) { - reader = new BufferedReader( - new FileReader((File) sourceFiles.elementAt(pos))); - } else { - // invoke the zoo of io readers - reader = new BufferedReader( - new InputStreamReader( - new FileInputStream( - (File) sourceFiles.elementAt(pos)), - encoding)); - } - for (int i = 0; i < lastChars.length; ++i) { - lastChars[i] = 0; - } + if (reader == null && i.hasNext()) { + Resource r = (Resource) i.next(); + log("Concating " + r.toLongString(), Project.MSG_VERBOSE); + InputStream is = r.getInputStream(); + reader = new BufferedReader(encoding == null + ? new InputStreamReader(is) + : new InputStreamReader(is, encoding)); + Arrays.fill(lastChars, (char) 0); } return reader; } + private void nextReader() throws IOException { + close(); + reader = null; + } + /** * Read a character from the current reader object. Advance * to the next if the reader is finished. @@ -840,12 +786,10 @@ public class Concat extends Task { } return ret; } - - while (pos < sourceFiles.size()) { + while (getReader() != null) { int ch = getReader().read(); if (ch == -1) { - reader.close(); - reader = null; + nextReader(); if (fixLastLine && isMissingEndOfLine()) { needAddSeparator = true; lastPos = 0; @@ -854,7 +798,6 @@ public class Concat extends Task { addLastChar((char) ch); return ch; } - pos++; } return -1; } @@ -871,13 +814,12 @@ public class Concat extends Task { throws IOException { int amountRead = 0; - while (pos < sourceFiles.size() || (needAddSeparator)) { + while (getReader() != null || needAddSeparator) { if (needAddSeparator) { cbuf[off] = eolString.charAt(lastPos++); if (lastPos >= eolString.length()) { lastPos = 0; needAddSeparator = false; - pos++; } len--; off++; @@ -889,13 +831,10 @@ public class Concat extends Task { } int nRead = getReader().read(cbuf, off, len); if (nRead == -1 || nRead == 0) { - reader.close(); - reader = null; + nextReader(); if (fixLastLine && isMissingEndOfLine()) { needAddSeparator = true; lastPos = 0; - } else { - pos++; } } else { if (fixLastLine) { @@ -931,6 +870,7 @@ public class Concat extends Task { reader.close(); } } + /** * if checking for end of line at end of file * add a character to the lastchars buffer diff --git a/src/main/org/apache/tools/ant/taskdefs/Length.java b/src/main/org/apache/tools/ant/taskdefs/Length.java index 285a9f5bb..a7d3cd1d7 100755 --- a/src/main/org/apache/tools/ant/taskdefs/Length.java +++ b/src/main/org/apache/tools/ant/taskdefs/Length.java @@ -21,18 +21,21 @@ import java.io.File; import java.io.PrintStream; import java.io.OutputStream; import java.io.ByteArrayOutputStream; -import java.util.Vector; import java.util.Iterator; import org.apache.tools.ant.Task; import org.apache.tools.ant.Project; import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.taskdefs.condition.Condition; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.Comparison; +import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.types.resources.Resources; +import org.apache.tools.ant.types.resources.FileResource; import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.PropertyOutputStream; /** * Gets lengths: of files/resources, byte size; of strings, length (optionally trimmed). @@ -52,9 +55,9 @@ public class Length extends Task implements Condition { private String string; private Boolean trim; private String mode = ALL; - private When when = When.EQUAL; + private Comparison when = Comparison.EQUAL; private Long length; - private Vector filesets; + private Resources resources; /** * The property in which the length will be stored. @@ -69,9 +72,7 @@ public class Length extends Task implements Condition { * @param file the File whose length to retrieve. */ public synchronized void setFile(File file) { - FileSet fs = new FileSet(); - fs.setFile(file); - add(fs); + add(new FileResource(file)); } /** @@ -79,11 +80,20 @@ public class Length extends Task implements Condition { * @param fs the FileSet to add. */ public synchronized void add(FileSet fs) { - if (fs == null) { + add((ResourceCollection) fs); + } + + /** + * Add a ResourceCollection. + * @param c the ResourceCollection to add. + * @since Ant 1.7 + */ + public synchronized void add(ResourceCollection c) { + if (c == null) { return; } - filesets = (filesets == null) ? new Vector() : filesets; - filesets.add(fs); + resources = (resources == null) ? new Resources() : resources; + resources.add(c); } /** @@ -95,12 +105,22 @@ public class Length extends Task implements Condition { } /** - * Set the comparison criteria for use as a Condition: - * "equal", "greater", "less". Default is "equal". + * Set the comparison for use as a Condition. * @param w EnumeratedAttribute When. + * @see org.apache.tools.ant.types.Comparison */ public synchronized void setWhen(When w) { - when = w; + setWhen((Comparison) w); + } + + /** + * Set the comparison for use as a Condition. + * @param c Comparison. + * @see org.apache.tools.ant.types.Comparison + * @since Ant 1.7 + */ + public synchronized void setWhen(Comparison c) { + when = c; } /** @@ -142,7 +162,7 @@ public class Length extends Task implements Condition { public void execute() { validate(); PrintStream ps = new PrintStream((property != null) - ? (OutputStream) new PropertyOutputStream() + ? (OutputStream) new PropertyOutputStream(getProject(), property) : (OutputStream) new LogOutputStream(this, Project.MSG_INFO)); if (STRING.equals(mode)) { @@ -173,27 +193,23 @@ public class Length extends Task implements Condition { handleResources(h); ell = new Long(h.getLength()); } - int w = when.getIndex(); - int comp = ell.compareTo(length); - return (w == 0 && comp == 0) - || (w == 1 && comp > 0) - || (w == 2 && comp < 0); + return when.evaluate(ell.compareTo(length)); } private void validate() { if (string != null) { - if (filesets != null && filesets.size() > 0) { + if (resources != null) { throw new BuildException("the string length function" - + " is incompatible with the file length function"); + + " is incompatible with the file/resource length function"); } if (!(STRING.equals(mode))) { throw new BuildException("the mode attribute is for use" + " with the file/resource length function"); } - } else if (filesets != null) { + } else if (resources != null) { if (!(EACH.equals(mode) || ALL.equals(mode))) { throw new BuildException("invalid mode setting for" - + " file length function: \"" + mode + "\""); + + " file/resource length function: \"" + mode + "\""); } else if (trim != null) { throw new BuildException("the trim attribute is" + " for use with the string length function only"); @@ -201,30 +217,20 @@ public class Length extends Task implements Condition { } else { throw new BuildException("you must set either the string attribute" + " or specify one or more files using the file attribute or" - + " nested filesets"); + + " nested resource collections"); } } private void handleResources(Handler h) { - for (Iterator i = filesets.iterator(); i.hasNext();) { - FileSet fs = (FileSet) i.next(); - DirectoryScanner ds = fs.getDirectoryScanner(getProject()); - String[] f = ds.getIncludedFiles(); - for (int j = 0; j < f.length; j++) { - Resource r = ds.getResource(f[j]); - if (!r.isExists()) { - log(r.getName() + " does not exist", Project.MSG_ERR); - } else if (r.isDirectory()) { - log(r.getName() + " is a directory; length unspecified", - Project.MSG_ERR); - } else { - //force a full path: - File basedir = ds.getBasedir(); - String s = FileUtils.getFileUtils().resolveFile( - basedir, r.getName()).getAbsolutePath(); - h.handle(new Resource(s, true, - r.getLastModified(), false, r.getSize())); - } + for (Iterator i = resources.iterator(); i.hasNext();) { + Resource r = (Resource) i.next(); + if (!r.isExists()) { + log(r + " does not exist", Project.MSG_ERR); + } else if (r.isDirectory()) { + log(r + " is a directory; length unspecified", + Project.MSG_ERR); + } else { + h.handle(r); } } h.complete(); @@ -251,27 +257,8 @@ public class Length extends Task implements Condition { /** * EnumeratedAttribute for the when attribute. */ - public static class When extends EnumeratedAttribute { - private static final String[] VALUES - = new String[] {"equal", "greater", "less"}; - - private static final When EQUAL = new When("equal"); - - public When() { - } - public When(String value) { - setValue(value); - } - public String[] getValues() { - return VALUES; - } - } - - private class PropertyOutputStream extends ByteArrayOutputStream { - public void close() { - getProject().setNewProperty( - property, new String(toByteArray()).trim()); - } + public static class When extends Comparison { + //extend Comparison; retain for BC only } private abstract class Handler { @@ -292,7 +279,7 @@ public class Length extends Task implements Condition { super(ps); } protected void handle(Resource r) { - ps.print(r.getName()); + ps.print(r.toString()); ps.print(" : "); //when writing to the log, we'll see what's happening: long size = r.getSize(); @@ -312,7 +299,7 @@ public class Length extends Task implements Condition { protected synchronized void handle(Resource r) { long size = r.getSize(); if (size == Resource.UNKNOWN_SIZE) { - log("Size unknown for " + r.getName(), Project.MSG_WARN); + log("Size unknown for " + r.toString(), Project.MSG_WARN); } else { accum += size; } diff --git a/src/main/org/apache/tools/ant/taskdefs/PathConvert.java b/src/main/org/apache/tools/ant/taskdefs/PathConvert.java index 224048ff5..c93d1b2aa 100644 --- a/src/main/org/apache/tools/ant/taskdefs/PathConvert.java +++ b/src/main/org/apache/tools/ant/taskdefs/PathConvert.java @@ -17,21 +17,23 @@ package org.apache.tools.ant.taskdefs; import java.io.File; -import java.util.StringTokenizer; -import java.util.Vector; import java.util.List; +import java.util.Vector; import java.util.ArrayList; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; +import java.util.StringTokenizer; import org.apache.tools.ant.Task; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.DirSet; -import org.apache.tools.ant.types.EnumeratedAttribute; -import org.apache.tools.ant.types.FileList; +import org.apache.tools.ant.types.Mapper; import org.apache.tools.ant.types.FileSet; -import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.Reference; -import org.apache.tools.ant.types.Mapper; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.types.resources.Union; import org.apache.tools.ant.util.FileNameMapper; /** @@ -43,11 +45,16 @@ import org.apache.tools.ant.util.FileNameMapper; */ public class PathConvert extends Task { + /** + * Set if we're running on windows + */ + private static boolean onWindows = Os.isFamily("dos"); + // Members /** * Path to be converted */ - private Path path = null; + private Union path = null; /** * Reference to path/fileset to convert */ @@ -60,10 +67,6 @@ public class PathConvert extends Task { * Set when targetOS is set to windows */ private boolean targetWindows = false; - /** - * Set if we're running on windows - */ - private boolean onWindows = false; /** * Set if we should create a new property even if the result is empty */ @@ -92,7 +95,6 @@ public class PathConvert extends Task { * Construct a new instance of the PathConvert task. */ public PathConvert() { - onWindows = Os.isFamily("dos"); } /** @@ -164,17 +166,36 @@ public class PathConvert extends Task { } /** - * Create a nested PATH element. + * Create a nested path element. * @return a Path to be used by Ant reflection. */ public Path createPath() { if (isReference()) { throw noChildrenAllowed(); } + Path result = new Path(getProject()); + add(result); + return result; + } + + /** + * Add an arbitrary ResourceCollection. + * @param rc the ResourceCollection to add. + * @since Ant 1.7 + */ + public void add(ResourceCollection rc) { + if (isReference()) { + throw noChildrenAllowed(); + } + getPath().add(rc); + } + + private synchronized Union getPath() { if (path == null) { - path = new Path(getProject()); + path = new Union(); + path.setProject(getProject()); } - return path.createPath(); + return path; } /** @@ -283,28 +304,19 @@ public class PathConvert extends Task { * @throws BuildException if something is invalid. */ public void execute() throws BuildException { - Path savedPath = path; + Union savedPath = path; String savedPathSep = pathSep; // may be altered in validateSetup String savedDirSep = dirSep; // may be altered in validateSetup try { // If we are a reference, create a Path from the reference if (isReference()) { - path = new Path(getProject()).createPath(); - Object obj = refid.getReferencedObject(getProject()); - - if (obj instanceof Path) { - path.setRefid(refid); - } else if (obj instanceof FileSet) { - path.addFileset((FileSet) obj); - } else if (obj instanceof DirSet) { - path.addDirset((DirSet) obj); - } else if (obj instanceof FileList) { - path.addFilelist((FileList) obj); - } else { - throw new BuildException("'refid' does not refer to a " - + "path, fileset, dirset, or filelist."); + Object o = refid.getReferencedObject(getProject()); + if (!(o instanceof ResourceCollection)) { + throw new BuildException("refid '" + refid.getRefId() + + "' does not refer to a resource collection."); } + getPath().add((ResourceCollection) o); } validateSetup(); // validate our setup @@ -355,9 +367,13 @@ public class PathConvert extends Task { // unless setonempty == false if (setonempty || rslt.length() > 0) { String value = rslt.toString(); - log("Set property " + property + " = " + value, - Project.MSG_VERBOSE); - getProject().setNewProperty(property, value); + if (property == null) { + log(value); + } else { + log("Set property " + property + " = " + value, + Project.MSG_VERBOSE); + getProject().setNewProperty(property, value); + } } } finally { path = savedPath; @@ -423,7 +439,6 @@ public class PathConvert extends Task { addMapper(m); } - /** * Validate that all our parameters have been properly initialized. * @@ -434,9 +449,6 @@ public class PathConvert extends Task { if (path == null) { throw new BuildException("You must specify a path to convert"); } - if (property == null) { - throw new BuildException("You must specify a property"); - } // Determine the separator strings. The dirsep and pathsep attributes // override the targetOS settings. String dsep = File.separator; @@ -464,7 +476,7 @@ public class PathConvert extends Task { * @return BuildException. */ private BuildException noChildrenAllowed() { - return new BuildException("You must not specify nested " + return new BuildException("You must not specify nested " + "elements when using the refid attribute."); } diff --git a/src/main/org/apache/tools/ant/taskdefs/ResourceCount.java b/src/main/org/apache/tools/ant/taskdefs/ResourceCount.java new file mode 100755 index 000000000..72c333a89 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/ResourceCount.java @@ -0,0 +1,124 @@ +/* + * 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.taskdefs; + +import org.apache.tools.ant.Task; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.condition.Condition; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.types.Comparison; +import org.apache.tools.ant.types.ResourceCollection; + +/** + * Count resources from a ResourceCollection, storing to a property or + * writing to the log. Can also be used as a Condition. + * @since Ant 1.7 + */ +public class ResourceCount extends Task implements Condition { + + private static final String ONE_NESTED_MESSAGE + = "ResourceCount can count resources from exactly one nested ResourceCollection."; + + private static final String COUNT_REQUIRED + = "Use of the ResourceCount condition requires that the count attribute be set."; + + private ResourceCollection rc; + private Comparison when = Comparison.EQUAL; + private Integer count; + private String property; + + /** + * Add the ResourceCollection to count. + * @param r the ResourceCollection to count. + * @throws BuildException if already set. + */ + public void add(ResourceCollection r) { + if (rc != null) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + rc = r; + } + + /** + * Set the ResourceCollection reference. + * @param r the Reference. + */ + public void setRefid(Reference r) { + Object o = r.getReferencedObject(); + if (!(o instanceof ResourceCollection)) { + throw new BuildException(r.getRefId() + + " doesn\'t denote a ResourceCollection"); + } + add((ResourceCollection) o); + } + + /** + * Execute as a Task. + */ + public void execute() { + if (rc == null) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + if (property == null) { + log("resource count = " + rc.size()); + } else { + getProject().setNewProperty(property, Integer.toString(rc.size())); + } + } + + /** + * Fulfill the condition contract. + * @return true if the specified ResourceCollection satisfies the set criteria. + * @throws BuildException if an error occurs. + */ + public boolean eval() { + if (rc == null) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + if (count == null) { + throw new BuildException(COUNT_REQUIRED); + } + return when.evaluate(new Integer(rc.size()).compareTo(count)); + } + + /** + * Set the target count number for use as a Condition. + * @param c number of Resources as int. + */ + public void setCount(int c) { + count = new Integer(c); + } + + /** + * Set the comparison for use as a Condition. + * @param w EnumeratedAttribute When. + * @see org.apache.tools.ant.types.Comparison + */ + public void setWhen(Comparison c) { + when = c; + } + + /** + * Set the name of the property to set in task mode. + * @param p the property name to set. + */ + public void setProperty(String p) { + property = p; + } + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index ec9281480..aee966d51 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -207,6 +207,7 @@ ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm apt=org.apache.tools.ant.taskdefs.Apt schemavalidate=org.apache.tools.ant.taskdefs.optional.SchemaValidate verifyjar=org.apache.tools.ant.taskdefs.VerifyJar +resourcecount=org.apache.tools.ant.taskdefs.ResourceCount # deprecated ant tasks (kept for back compatibility) starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut diff --git a/src/main/org/apache/tools/ant/types/Comparison.java b/src/main/org/apache/tools/ant/types/Comparison.java new file mode 100755 index 000000000..d146efc89 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/Comparison.java @@ -0,0 +1,93 @@ +/* + * 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; + +import java.util.Arrays; + +import org.apache.tools.ant.BuildException; + +/** + * EnumeratedAttribute for generic comparisons. Accepts values + * "equal", "greater", "less", "ne" (not equal), "ge" (greater or equal), + * "le" (less or equal), "eq" (equal), "gt" (greater), "lt" (less). + * @since Ant 1.7 + */ +public class Comparison extends EnumeratedAttribute { + private static final String[] VALUES + = new String[] {"equal", "greater", "less", + "ne", "ge", "le", "eq", "gt", "lt"}; + + /** Equal Comparison. */ + public static final Comparison EQUAL = new Comparison("equal"); + + /** Not-Equal Comparison. */ + public static final Comparison NOT_EQUAL = new Comparison("ne"); + + /** Greater Comparison. */ + public static final Comparison GREATER = new Comparison("greater"); + + /** Less Comparison. */ + public static final Comparison LESS = new Comparison("less"); + + /** Greater-or-Equal Comparison. */ + public static final Comparison GREATER_EQUAL = new Comparison("ge"); + + /** Less-or-Equal Comparison. */ + public static final Comparison LESS_EQUAL = new Comparison("le"); + + private static final int[] EQUAL_INDEX = {0, 4, 5, 6}; + private static final int[] LESS_INDEX = {2, 3, 5, 8}; + private static final int[] GREATER_INDEX = {1, 3, 4, 7}; + + /** + * Default constructor. + */ + public Comparison() { + } + + /** + * Construct a new Comparison with the specified value. + * @param value the EnumeratedAttribute value. + */ + public Comparison(String value) { + setValue(value); + } + + /** + * Return the possible values. + * @return String[] of EnumeratedAttribute values. + */ + public String[] getValues() { + return VALUES; + } + + /** + * Evaluate a comparison result as from Comparator.compare() or Comparable.compareTo(). + * @param comparisonResult the result to evaluate. + * @return true if the comparison result fell within the parameters of this Comparison. + */ + public boolean evaluate(int comparisonResult) { + if (getIndex() == -1) { + throw new BuildException("Comparison value not set."); + } + int[] i = comparisonResult < 0 ? LESS_INDEX + : comparisonResult > 0 ? GREATER_INDEX : EQUAL_INDEX; + return Arrays.binarySearch(i, getIndex()) >= 0; + } + +} + diff --git a/src/main/org/apache/tools/ant/types/DirSet.java b/src/main/org/apache/tools/ant/types/DirSet.java index 1ffe58d37..7fa1b542e 100644 --- a/src/main/org/apache/tools/ant/types/DirSet.java +++ b/src/main/org/apache/tools/ant/types/DirSet.java @@ -17,13 +17,17 @@ package org.apache.tools.ant.types; +import java.util.Iterator; + +import org.apache.tools.ant.types.resources.FileResourceIterator; + /** * Subclass as hint for supporting tasks that the included directories * instead of files should be used. * * @since Ant 1.5 */ -public class DirSet extends AbstractFileSet { +public class DirSet extends AbstractFileSet implements ResourceCollection { /** * Constructor for DirSet. @@ -53,4 +57,38 @@ public class DirSet extends AbstractFileSet { } } + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator iterator() { + if (isReference()) { + return ((DirSet) getRef(getProject())).iterator(); + } + return new FileResourceIterator(getDir(getProject()), + getDirectoryScanner(getProject()).getIncludedDirectories()); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + * @since Ant 1.7 + */ + public int size() { + if (isReference()) { + return ((DirSet) getRef(getProject())).size(); + } + return getDirectoryScanner(getProject()).getIncludedDirsCount(); + } + + /** + * Always returns true. + * @return true indicating that all elements will be FileResources. + * @since Ant 1.7 + */ + public boolean isFilesystemOnly() { + return true; + } + } diff --git a/src/main/org/apache/tools/ant/types/FileList.java b/src/main/org/apache/tools/ant/types/FileList.java index ba1464456..f682de9b0 100644 --- a/src/main/org/apache/tools/ant/types/FileList.java +++ b/src/main/org/apache/tools/ant/types/FileList.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2002,2004 The Apache Software Foundation + * Copyright 2001-2002,2004-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. @@ -21,8 +21,11 @@ import java.io.File; import java.util.Stack; import java.util.StringTokenizer; import java.util.Vector; -import org.apache.tools.ant.BuildException; +import java.util.Iterator; + import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.resources.FileResourceIterator; /** * FileList represents an explicitly named list of files. FileLists @@ -31,7 +34,7 @@ import org.apache.tools.ant.Project; * filter, only returning the name of a matched file if it currently * exists in the file system. */ -public class FileList extends DataType { +public class FileList extends DataType implements ResourceCollection { private Vector filenames = new Vector(); private File dir; @@ -78,9 +81,7 @@ public class FileList extends DataType { * @exception BuildException if an error occurs */ public void setDir(File dir) throws BuildException { - if (isReference()) { - throw tooManyAttributes(); - } + checkAttributesAllowed(); this.dir = dir; } @@ -102,9 +103,7 @@ public class FileList extends DataType { * by whitespace. */ public void setFiles(String filenames) { - if (isReference()) { - throw tooManyAttributes(); - } + checkAttributesAllowed(); if (filenames != null && filenames.length() > 0) { StringTokenizer tok = new StringTokenizer( filenames, ", \t\n\r\f", false); @@ -144,19 +143,7 @@ public class FileList extends DataType { * @return the FileList represented by a referenced filelist. */ protected FileList getRef(Project p) { - if (!isChecked()) { - Stack stk = new Stack(); - stk.push(this); - dieOnCircularReference(stk, p); - } - - Object o = getRefid().getReferencedObject(p); - if (!(o instanceof FileList)) { - String msg = getRefid().getRefId() + " doesn\'t denote a filelist"; - throw new BuildException(msg); - } else { - return (FileList) o; - } + return (FileList) getCheckedRef(p); } /** @@ -194,4 +181,39 @@ public class FileList extends DataType { } filenames.addElement(name.getName()); } + + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator iterator() { + if (isReference()) { + return ((FileList) getRef(getProject())).iterator(); + } + return new FileResourceIterator(dir, + (String[]) (filenames.toArray(new String[filenames.size()]))); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + * @since Ant 1.7 + */ + public int size() { + if (isReference()) { + return ((FileList) getRef(getProject())).size(); + } + return filenames.size(); + } + + /** + * Always returns true. + * @return true indicating that all elements will be FileResources. + * @since Ant 1.7 + */ + public boolean isFilesystemOnly() { + return true; + } + } diff --git a/src/main/org/apache/tools/ant/types/FileSet.java b/src/main/org/apache/tools/ant/types/FileSet.java index 53d0e0d8b..e2f5cbc49 100644 --- a/src/main/org/apache/tools/ant/types/FileSet.java +++ b/src/main/org/apache/tools/ant/types/FileSet.java @@ -17,12 +17,16 @@ package org.apache.tools.ant.types; +import java.util.Iterator; + +import org.apache.tools.ant.types.resources.FileResourceIterator; + /** * Moved out of MatchingTask to make it a standalone object that could * be referenced (by scripts for example). * */ -public class FileSet extends AbstractFileSet { +public class FileSet extends AbstractFileSet implements ResourceCollection { /** * Constructor for FileSet. @@ -52,4 +56,38 @@ public class FileSet extends AbstractFileSet { } } + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator iterator() { + if (isReference()) { + return ((FileSet) getRef(getProject())).iterator(); + } + return new FileResourceIterator(getDir(getProject()), + getDirectoryScanner(getProject()).getIncludedFiles()); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + * @since Ant 1.7 + */ + public int size() { + if (isReference()) { + return ((FileSet) getRef(getProject())).size(); + } + return getDirectoryScanner(getProject()).getIncludedFilesCount(); + } + + /** + * Always returns true. + * @return true indicating that all elements will be FileResources. + * @since Ant 1.7 + */ + public boolean isFilesystemOnly() { + return true; + } + } diff --git a/src/main/org/apache/tools/ant/types/Path.java b/src/main/org/apache/tools/ant/types/Path.java index 6e42d31d7..224b2c6b6 100644 --- a/src/main/org/apache/tools/ant/types/Path.java +++ b/src/main/org/apache/tools/ant/types/Path.java @@ -18,17 +18,22 @@ package org.apache.tools.ant.types; import java.io.File; -import java.util.Enumeration; -import java.util.Locale; +import java.util.Set; import java.util.Stack; +import java.util.Locale; import java.util.Vector; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Collection; +import java.util.Enumeration; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.PathTokenizer; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.resources.Union; +import org.apache.tools.ant.types.resources.FileResourceIterator; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.JavaEnvUtils; - /** * This object represents a path as used by CLASSPATH or PATH * environment variable. @@ -56,28 +61,25 @@ import org.apache.tools.ant.util.JavaEnvUtils; * */ -public class Path extends DataType implements Cloneable { - - private Vector elements; +public class Path extends Union { - /** The system classspath as a Path object */ + /** The system classpath as a Path object */ public static Path systemClasspath = new Path(null, System.getProperty("java.class.path")); /** - * The system bootclassspath as a Path object. + * The system bootclasspath as a Path object. * * @since Ant 1.6.2 */ public static Path systemBootClasspath = new Path(null, System.getProperty("sun.boot.class.path")); - /** * Helper class, holds the nested <pathelement> values. */ - public class PathElement { + public class PathElement implements ResourceCollection { private String[] parts; /** @@ -106,6 +108,19 @@ public class Path extends DataType implements Cloneable { public String[] getParts() { return parts; } + + public Iterator iterator() { + return new FileResourceIterator(null, parts); + } + + public boolean isFilesystemOnly() { + return true; + } + + public int size() { + return parts == null ? 0 : parts.length; + } + } /** @@ -125,7 +140,6 @@ public class Path extends DataType implements Cloneable { */ public Path(Project project) { setProject(project); - elements = new Vector(); } /** @@ -135,22 +149,17 @@ public class Path extends DataType implements Cloneable { * @throws BuildException on error */ public void setLocation(File location) throws BuildException { - if (isReference()) { - throw tooManyAttributes(); - } + checkAttributesAllowed(); createPathElement().setLocation(location); } - /** * Parses a path definition and creates single PathElements. * @param path the String path definition. * @throws BuildException on error */ public void setPath(String path) throws BuildException { - if (isReference()) { - throw tooManyAttributes(); - } + checkAttributesAllowed(); createPathElement().setPath(path); } @@ -163,10 +172,9 @@ public class Path extends DataType implements Cloneable { * @throws BuildException on error */ public void setRefid(Reference r) throws BuildException { - if (!elements.isEmpty()) { + if (!getResourceCollections().isEmpty()) { throw tooManyAttributes(); } - elements.addElement(r); super.setRefid(r); } @@ -180,7 +188,7 @@ public class Path extends DataType implements Cloneable { throw noChildrenAllowed(); } PathElement pe = new PathElement(); - elements.addElement(pe); + add(pe); return pe; } @@ -190,11 +198,7 @@ public class Path extends DataType implements Cloneable { * @throws BuildException on error */ public void addFileset(FileSet fs) throws BuildException { - if (isReference()) { - throw noChildrenAllowed(); - } - elements.addElement(fs); - setChecked(false); + add(fs); } /** @@ -203,11 +207,7 @@ public class Path extends DataType implements Cloneable { * @throws BuildException on error */ public void addFilelist(FileList fl) throws BuildException { - if (isReference()) { - throw noChildrenAllowed(); - } - elements.addElement(fl); - setChecked(false); + add(fl); } /** @@ -216,11 +216,7 @@ public class Path extends DataType implements Cloneable { * @throws BuildException on error */ public void addDirset(DirSet dset) throws BuildException { - if (isReference()) { - throw noChildrenAllowed(); - } - elements.addElement(dset); - setChecked(false); + add(dset); } /** @@ -230,12 +226,7 @@ public class Path extends DataType implements Cloneable { * @since Ant 1.6 */ public void add(Path path) throws BuildException { - if (isReference()) { - throw noChildrenAllowed(); - } - elements.addElement(path); - setChecked(false); - + add((ResourceCollection) path); } /** @@ -244,12 +235,8 @@ public class Path extends DataType implements Cloneable { * @throws BuildException on error */ public Path createPath() throws BuildException { - if (isReference()) { - throw noChildrenAllowed(); - } Path p = new Path(getProject()); - elements.addElement(p); - setChecked(false); + add(p); return p; } @@ -261,17 +248,12 @@ public class Path extends DataType implements Cloneable { if (other == null) { return; } - String[] l = other.list(); - for (int i = 0; i < l.length; i++) { - if (elements.indexOf(l[i]) == -1) { - elements.addElement(l[i]); - } - } + add(other); } - /** + /** * Adds the components on the given path which exist to this - * Path. Components that don't exist, aren't added. + * Path. Components that don't exist aren't added. * * @param source - source path whose components are examined for existence */ @@ -309,92 +291,29 @@ public class Path extends DataType implements Cloneable { } /** - * Returns all path elements defined by this and nested path objects. - * @return list of path elements. - */ - public String[] list() { - if (!isChecked()) { - // make sure we don't have a circular reference here - Stack stk = new Stack(); - stk.push(this); - dieOnCircularReference(stk, getProject()); - } - - Vector result = new Vector(2 * elements.size()); - for (int i = 0; i < elements.size(); i++) { - Object o = elements.elementAt(i); - if (o instanceof Reference) { - Reference r = (Reference) o; - o = r.getReferencedObject(getProject()); - // we only support references to paths right now - if (!(o instanceof Path)) { - String msg = r.getRefId() + " doesn\'t denote a path " + o; - throw new BuildException(msg); - } + * Override Union.getCollection() + * so we can check our children first. + * @return a Collection. + */ + protected Collection getCollection() { + for (Iterator i = getResourceCollections().iterator(); i.hasNext();) { + ResourceCollection rc = (ResourceCollection) i.next(); + if (!(rc.isFilesystemOnly())) { + throw new BuildException(getDataTypeName() + + " allows only filesystem resources."); } - - if (o instanceof String) { - // obtained via append - addUnlessPresent(result, (String) o); - } else if (o instanceof PathElement) { - String[] parts = ((PathElement) o).getParts(); - if (parts == null) { - throw new BuildException("You must either set location or" - + " path on "); - } - for (int j = 0; j < parts.length; j++) { - addUnlessPresent(result, parts[j]); - } - } else if (o instanceof Path) { - Path p = (Path) o; + if (rc instanceof PathElement + && ((PathElement) rc).getParts() == null) { + throw new BuildException( + "Either location or path must be set on a pathelement."); + } else if (rc instanceof Path) { + Path p = (Path) rc; if (p.getProject() == null) { p.setProject(getProject()); } - String[] parts = p.list(); - for (int j = 0; j < parts.length; j++) { - addUnlessPresent(result, parts[j]); - } - } else if (o instanceof DirSet) { - DirSet dset = (DirSet) o; - addUnlessPresent(result, dset.getDir(getProject()), - dset.getDirectoryScanner(getProject()).getIncludedDirectories()); - } else if (o instanceof FileSet) { - FileSet fs = (FileSet) o; - addUnlessPresent(result, fs.getDir(getProject()), - fs.getDirectoryScanner(getProject()).getIncludedFiles()); - } else if (o instanceof FileList) { - FileList fl = (FileList) o; - addUnlessPresent(result, - fl.getDir(getProject()), fl.getFiles(getProject())); } } - String[] res = new String[result.size()]; - result.copyInto(res); - return res; - } - - - /** - * Returns a textual representation of the path, which can be used as - * CLASSPATH or PATH environment variable definition. - * @return a textual representation of the path. - */ - public String toString() { - final String[] list = list(); - - // empty path return empty string - if (list.length == 0) { - return ""; - } - - // path containing one or more elements - final StringBuffer result = new StringBuffer(list[0].toString()); - for (int i = 1; i < list.length; i++) { - result.append(File.pathSeparatorChar); - result.append(list[i]); - } - - return result.toString(); + return super.getCollection(); } /** @@ -466,62 +385,6 @@ public class Path extends DataType implements Cloneable { return false; } - /** - * How many parts does this Path instance consist of. - * @return the number of parts - */ - public int size() { - return list().length; - } - - /** - * Return a Path that holds the same elements as this instance. - * @return a copy of the path - */ - public Object clone() { - try { - Path p = (Path) super.clone(); - p.elements = (Vector) elements.clone(); - return p; - } catch (CloneNotSupportedException e) { - throw new BuildException(e); - } - } - - /** - * 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 void dieOnCircularReference(Stack stk, Project p) - throws BuildException { - - if (isChecked()) { - return; - } - - Enumeration e = elements.elements(); - while (e.hasMoreElements()) { - Object o = e.nextElement(); - if (o instanceof Reference) { - o = ((Reference) o).getReferencedObject(p); - } - - if (o instanceof DataType) { - if (stk.contains(o)) { - throw circularReference(); - } else { - stk.push(o); - ((DataType) o).dieOnCircularReference(stk, p); - stk.pop(); - } - } - } - setChecked(true); - } - /** * Resolve a filename with Project's help - if we know one that is. */ @@ -530,27 +393,6 @@ public class Path extends DataType implements Cloneable { (project == null) ? null : project.getBaseDir(), relativeName); } - /** - * Adds a String to the Vector if it isn't already included. - */ - private static void addUnlessPresent(Vector v, String s) { - if (v.indexOf(s) == -1) { - v.addElement(s); - } - } - - /** - * Adds absolute path names of listed files in the given directory - * to the Vector if they are not already included. - */ - private static void addUnlessPresent(Vector v, File dir, String[] s) { - for (int j = 0; j < s.length; j++) { - File d = new File(dir, s[j]); - String absolutePath = d.getAbsolutePath(); - addUnlessPresent(v, translateFile(absolutePath)); - } - } - /** * Concatenates the system class path in the order specified by * the ${build.sysclasspath} property - using "last" as @@ -737,4 +579,5 @@ public class Path extends DataType implements Cloneable { } } } + } diff --git a/src/main/org/apache/tools/ant/types/PropertySet.java b/src/main/org/apache/tools/ant/types/PropertySet.java index 4b6f19a36..431a5cb8c 100644 --- a/src/main/org/apache/tools/ant/types/PropertySet.java +++ b/src/main/org/apache/tools/ant/types/PropertySet.java @@ -30,6 +30,8 @@ import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.resources.PropertyResource; import org.apache.tools.ant.util.FileNameMapper; import org.apache.tools.ant.util.regexp.RegexpMatcher; import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; @@ -39,7 +41,7 @@ import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; * * @since Ant 1.6 */ -public class PropertySet extends DataType { +public class PropertySet extends DataType implements ResourceCollection { private boolean dynamic = true; private boolean negate = false; @@ -463,4 +465,40 @@ public class PropertySet extends DataType { return b.toString(); } + /** + * Fulfill the ResourceCollection interface. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator iterator() { + final Enumeration e = getProperties().propertyNames(); + return new Iterator() { + public boolean hasNext() { + return e.hasMoreElements(); + } + public Object next() { + return new PropertyResource(getProject(), (String) e.nextElement()); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /** + * Fulfill the ResourceCollection contract. + * @return the size of this ResourceCollection. + */ + public int size() { + return isReference() ? getRef().size() : getProperties().size(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return whether this is a filesystem-only resource collection. + */ + public boolean isFilesystemOnly() { + return isReference() && getRef().isFilesystemOnly(); + } + } diff --git a/src/main/org/apache/tools/ant/types/Resource.java b/src/main/org/apache/tools/ant/types/Resource.java index 4893fa44a..fc59fa0ed 100644 --- a/src/main/org/apache/tools/ant/types/Resource.java +++ b/src/main/org/apache/tools/ant/types/Resource.java @@ -16,24 +16,51 @@ */ package org.apache.tools.ant.types; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Stack; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.apache.tools.ant.BuildException; + /** - * Describes a File or a ZipEntry. + * Describes a "File-like" resource (File, ZipEntry, etc.). * * This class is meant to be used by classes needing to record path * and date/time information about a file, a zip entry or some similar * resource (URL, archive in a version control repository, ...). * * @since Ant 1.5.2 + * @see org.apache.tools.ant.types.resources.Touchable */ -public class Resource implements Cloneable, Comparable { +public class Resource extends DataType + implements Cloneable, Comparable, ResourceCollection { + /** Constant unknown size */ public static final long UNKNOWN_SIZE = -1; + /** Magic number */ + protected static final int MAGIC = getMagicNumber("Resource".getBytes()); + + private static final int NULL_NAME = getMagicNumber("null name".getBytes()); + + /** + * Create a "magic number" for use in hashCode calculations. + * @param seed byte[] to seed with. + * @return a magic number as int. + */ + protected static int getMagicNumber(byte[] seed) { + return new BigInteger(seed).intValue(); + } + private String name = null; - private boolean exists = true; - private long lastmodified = 0; - private boolean directory = false; - private long size = UNKNOWN_SIZE; + private Boolean exists = null; + private Long lastmodified = null; + private Boolean directory = null; + private Long size = null; /** * Default constructor. @@ -112,7 +139,7 @@ public class Resource implements Cloneable, Comparable { * @return the name of this resource. */ public String getName() { - return name; + return isReference() ? ((Resource) getCheckedRef()).getName() : name; } /** @@ -121,6 +148,7 @@ public class Resource implements Cloneable, Comparable { * "/" to be used as the directory separator. */ public void setName(String name) { + checkAttributesAllowed(); this.name = name; } @@ -129,7 +157,11 @@ public class Resource implements Cloneable, Comparable { * @return true if this resource exists. */ public boolean isExists() { - return exists; + if (isReference()) { + return ((Resource) getCheckedRef()).isExists(); + } + //default true: + return exists == null || exists.booleanValue(); } /** @@ -137,7 +169,8 @@ public class Resource implements Cloneable, Comparable { * @param exists if true, this resource exists. */ public void setExists(boolean exists) { - this.exists = exists; + checkAttributesAllowed(); + this.exists = exists ? Boolean.TRUE : Boolean.FALSE; } /** @@ -147,7 +180,14 @@ public class Resource implements Cloneable, Comparable { * of {@link java.io.File File}. */ public long getLastModified() { - return !exists || lastmodified < 0 ? 0L : lastmodified; + if (isReference()) { + return ((Resource) getCheckedRef()).getLastModified(); + } + if (!isExists() || lastmodified == null) { + return 0L; + } + long result = lastmodified.longValue(); + return result < 0L ? 0L : result; } /** @@ -155,7 +195,8 @@ public class Resource implements Cloneable, Comparable { * @param lastmodified the modification time in milliseconds since 01.01.1970. */ public void setLastModified(long lastmodified) { - this.lastmodified = lastmodified; + checkAttributesAllowed(); + this.lastmodified = new Long(lastmodified); } /** @@ -163,7 +204,11 @@ public class Resource implements Cloneable, Comparable { * @return boolean flag indicating if the resource is a directory. */ public boolean isDirectory() { - return directory; + if (isReference()) { + return ((Resource) getCheckedRef()).isDirectory(); + } + //default false: + return directory != null && directory.booleanValue(); } /** @@ -171,26 +216,31 @@ public class Resource implements Cloneable, Comparable { * @param directory if true, this resource is a directory. */ public void setDirectory(boolean directory) { - this.directory = directory; + checkAttributesAllowed(); + this.directory = directory ? Boolean.TRUE : Boolean.FALSE; } /** * Set the size of this Resource. * @param size the size, as a long. - * @since Ant 1.7 + * @since Ant 1.6.3 */ public void setSize(long size) { - this.size = (size > UNKNOWN_SIZE) ? size : UNKNOWN_SIZE; + checkAttributesAllowed(); + this.size = new Long(size > UNKNOWN_SIZE ? size : UNKNOWN_SIZE); } /** * Get the size of this Resource. * @return the size, as a long, 0 if the Resource does not exist (for * compatibility with java.io.File), or UNKNOWN_SIZE if not known. - * @since Ant 1.7 + * @since Ant 1.6.3 */ public long getSize() { - return (exists) ? size : 0L; + if (isReference()) { + return ((Resource) getCheckedRef()).getSize(); + } + return isExists() && size != null ? size.longValue() : 0L; } /** @@ -215,12 +265,168 @@ public class Resource implements Cloneable, Comparable { * @since Ant 1.6 */ public int compareTo(Object other) { + if (isReference()) { + return ((Comparable) getCheckedRef()).compareTo(other); + } if (!(other instanceof Resource)) { - throw new IllegalArgumentException("Can only be compared with " - + "Resources"); + throw new IllegalArgumentException( + "Can only be compared with Resources"); } Resource r = (Resource) other; - return getName().compareTo(r.getName()); + String name = getName(); + String oname = r.getName(); + if (name == null && oname == null) { + return 0; + } + if (name == null) { + return -1; + } + return oname == null ? 1 : name.compareTo(oname); + } + + /** + * Implement basic Resource equality. + * @return true if the specified Object is equal to this Resource. + * @since Ant 1.7 + */ + public boolean equals(Object other) { + if (isReference()) { + return getCheckedRef().equals(other); + } + return other.getClass().equals(getClass()) && compareTo(other) == 0; + } + + /** + * Get the hash code for this Resource. + * @return hash code as int. + * @since Ant 1.7 + */ + public int hashCode() { + if (isReference()) { + return getCheckedRef().hashCode(); + } + String name = getName(); + return MAGIC * (name == null ? name.hashCode() : NULL_NAME); + } + + /** + * Get an InputStream for the Resource. + * @return an InputStream containing this Resource's content. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if InputStreams are not + * supported for this Resource type. + * @since Ant 1.7 + */ + public InputStream getInputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getInputStream(); + } + throw new UnsupportedOperationException(); + } + + /** + * Get an OutputStream for the Resource. + * @return an OutputStream to which content can be written. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if OutputStreams are not + * supported for this Resource type. + * @since Ant 1.7 + */ + public OutputStream getOutputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getOutputStream(); + } + throw new UnsupportedOperationException(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator iterator() { + return isReference() ? ((Resource) getCheckedRef()).iterator() + : new Iterator() { + boolean done = false; + public boolean hasNext() { + return !done; + } + public Object next() { + if (done) { + throw new NoSuchElementException(); + } + done = true; + return Resource.this; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /** + * Fulfill the ResourceCollection contract. + * @return the size of this ResourceCollection. + * @since Ant 1.7 + */ + public int size() { + return isReference() ? ((Resource) getCheckedRef()).size() : 1; + } + + /** + * Fulfill the ResourceCollection contract. + * @return whether this Resource is a FileResource. + * @since Ant 1.7 + */ + public boolean isFilesystemOnly() { + //default false: + return isReference() && ((Resource) getCheckedRef()).isFilesystemOnly(); + } + + /** + * Get the string representation of this Resource. + * @return this Resource formatted as a String. + * @since Ant 1.7 + */ + public String toString() { + if (isReference()) { + return getCheckedRef().toString(); + } + String n = getName(); + if (n != null) { + return n; + } + String classname = getClass().getName(); + return "anonymous " + classname.substring(classname.lastIndexOf('.') + 1); + } + + /** + * Get a long String representation of this Resource. + * This typically should be the value of toString() + * prefixed by a type description. + * @return this Resource formatted as a long String. + * @since Ant 1.7 + */ + public final String toLongString() { + return isReference() ? ((Resource) getCheckedRef()).toLongString() + : getDataTypeName() + " \"" + toString() + '"'; + } + + /** + * Overrides the base version. + * @param r the Reference to set. + */ + public void setRefid(Reference r) { + if (name != null + || exists != null + || lastmodified != null + || directory != null + || size != null) { + throw tooManyAttributes(); + } + super.setRefid(r); } } diff --git a/src/main/org/apache/tools/ant/types/ResourceCollection.java b/src/main/org/apache/tools/ant/types/ResourceCollection.java new file mode 100755 index 000000000..672701997 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/ResourceCollection.java @@ -0,0 +1,49 @@ +/* + * 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; + +import java.util.Iterator; + +/** + * Interface describing a collection of Resources. + * @since Ant 1.7 + */ +public interface ResourceCollection { + + /** + * Get an Iterator over the contents of this ResourceCollection, whose elements + * are org.apache.tools.ant.types.Resource instances. + * @return an Iterator of Resources. + */ + public Iterator iterator(); + + /** + * Learn the number of contained Resources. + * @return number of elements as int. + */ + public int size(); + + /** + * Indicate whether this ResourceCollection is composed entirely of + * Resources accessible via local filesystem conventions. If true, + * all Resources returned from this ResourceCollection should be + * instances of FileResource. + * @return whether this is a filesystem-only resource collection. + */ + public boolean isFilesystemOnly(); + +} diff --git a/src/main/org/apache/tools/ant/types/ZipFileSet.java b/src/main/org/apache/tools/ant/types/ZipFileSet.java index f39a7f387..331ed64b3 100644 --- a/src/main/org/apache/tools/ant/types/ZipFileSet.java +++ b/src/main/org/apache/tools/ant/types/ZipFileSet.java @@ -18,6 +18,7 @@ package org.apache.tools.ant.types; import java.io.File; import java.util.Stack; +import java.util.Iterator; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; @@ -62,6 +63,8 @@ public class ZipFileSet extends FileSet { private boolean fileModeHasBeenSet = false; private boolean dirModeHasBeenSet = false; + private String encoding = null; + /** Constructor for ZipFileSet */ public ZipFileSet() { super(); @@ -89,6 +92,7 @@ public class ZipFileSet extends FileSet { dirMode = fileset.dirMode; fileModeHasBeenSet = fileset.fileModeHasBeenSet; dirModeHasBeenSet = fileset.dirModeHasBeenSet; + encoding = fileset.encoding; } /** @@ -98,9 +102,7 @@ public class ZipFileSet extends FileSet { * @throws BuildException on error */ public void setDir(File dir) throws BuildException { - if (isReference()) { - throw tooManyAttributes(); - } + checkAttributesAllowed(); if (srcFile != null) { throw new BuildException("Cannot set both dir and src attributes"); } else { @@ -116,9 +118,7 @@ public class ZipFileSet extends FileSet { * @param srcFile The zip file from which to extract entries. */ public void setSrc(File srcFile) { - if (isReference()) { - throw tooManyAttributes(); - } + checkAttributesAllowed(); if (hasDir) { throw new BuildException("Cannot set both dir and src attributes"); } @@ -189,6 +189,24 @@ public class ZipFileSet extends FileSet { return fullpath; } + /** + * Set the encoding used for this ZipFileSet. + * @param enc encoding as String. + * @since Ant 1.7 + */ + public void setEncoding(String enc) { + this.encoding = enc; + } + + /** + * Get the encoding used for this ZipFileSet. + * @return String encoding. + * @since Ant 1.7 + */ + public String getEncoding() { + return encoding; + } + /** * Return the DirectoryScanner associated with this FileSet. * If the ZipFileSet defines a source Zip file, then a ZipScanner @@ -200,16 +218,60 @@ public class ZipFileSet extends FileSet { if (isReference()) { return getRef(p).getDirectoryScanner(p); } - if (srcFile != null) { - ZipScanner zs = new ZipScanner(); - zs.setSrc(srcFile); - super.setDir(p.getBaseDir()); - setupDirectoryScanner(zs, p); - zs.init(); - return zs; - } else { + if (srcFile == null) { return super.getDirectoryScanner(p); } + ZipScanner zs = new ZipScanner(); + zs.setSrc(srcFile); + super.setDir(p.getBaseDir()); + setupDirectoryScanner(zs, p); + zs.init(); + zs.setEncoding(encoding); + return zs; + } + + /** + * Fulfill the ResourceCollection contract. + * @return Iterator of Resources. + * @since Ant 1.7 + */ + public Iterator iterator() { + if (isReference()) { + return ((ResourceCollection) (getRef(getProject()))).iterator(); + } + if (srcFile == null) { + return super.iterator(); + } + ZipScanner zs = (ZipScanner) getDirectoryScanner(getProject()); + return zs.getResourceFiles(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return size of the collection as int. + * @since Ant 1.7 + */ + public int size() { + if (isReference()) { + return ((ResourceCollection) (getRef(getProject()))).size(); + } + if (srcFile == null) { + return super.size(); + } + ZipScanner zs = (ZipScanner) getDirectoryScanner(getProject()); + return zs.getIncludedFilesCount(); + } + + /** + * Indicate whether this ResourceCollection is composed entirely of + * Resources accessible via local filesystem conventions. If true, + * all Resources returned from this ResourceCollection should be + * instances of FileResource. + * @return whether this is a filesystem-only resource collection. + * @since Ant 1.7 + */ + public boolean isFilesystemOnly() { + return srcFile == null; } /** @@ -297,11 +359,7 @@ public class ZipFileSet extends FileSet { * @return the abstract fileset instance */ protected AbstractFileSet getRef(Project p) { - if (!isChecked()) { - Stack stk = new Stack(); - stk.push(this); - dieOnCircularReference(stk, p); - } + dieOnCircularReference(p); Object o = getRefid().getReferencedObject(p); if (o instanceof ZipFileSet) { return (AbstractFileSet) o; @@ -319,6 +377,7 @@ public class ZipFileSet extends FileSet { throw new BuildException(msg); } } + /** * Return a ZipFileSet that has the same properties * as this one. diff --git a/src/main/org/apache/tools/ant/types/ZipScanner.java b/src/main/org/apache/tools/ant/types/ZipScanner.java index 5c733d684..23cdaf9c5 100644 --- a/src/main/org/apache/tools/ant/types/ZipScanner.java +++ b/src/main/org/apache/tools/ant/types/ZipScanner.java @@ -19,14 +19,20 @@ package org.apache.tools.ant.types; import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Vector; +import java.util.Set; +import java.util.TreeMap; +import java.util.Iterator; +import java.util.ArrayList; import java.util.Hashtable; +import java.util.Comparator; +import java.util.Collections; import java.util.Enumeration; import java.util.zip.ZipException; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.resources.ZipResource; +import org.apache.tools.ant.types.resources.FileResourceIterator; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; @@ -44,14 +50,31 @@ public class ZipScanner extends DirectoryScanner { * The zip file which should be scanned. */ protected File srcFile; + /** * to record the last scanned zip file with its modification date */ private Resource lastScannedResource; + + /** + * record list of all file zip entries + */ + private TreeMap fileEntries = new TreeMap(); + /** - * record list of all zip entries + * record list of all directory zip entries */ - private Hashtable myentries; + private TreeMap dirEntries = new TreeMap(); + + /** + * record list of matching file zip entries + */ + private TreeMap matchFileEntries = new TreeMap(); + + /** + * record list of matching directory zip entries + */ + private TreeMap matchDirEntries = new TreeMap(); /** * encoding of file names. @@ -60,6 +83,17 @@ public class ZipScanner extends DirectoryScanner { */ private String encoding; + /** + * Don't scan when we have no zipfile. + * @since Ant 1.7 + */ + public void scan() { + if (srcFile == null) { + return; + } + super.scan(); + } + /** * Sets the srcFile for scanning. This is the jar or zip file that * is scanned for matching entries. @@ -88,23 +122,25 @@ public class ZipScanner extends DirectoryScanner { * include patterns and none of the exclude patterns. */ public String[] getIncludedFiles() { - if (srcFile != null) { - Vector myvector = new Vector(); - // first check if the archive needs to be scanned again - scanme(); - for (Enumeration e = myentries.elements(); e.hasMoreElements();) { - Resource myresource = (Resource) e.nextElement(); - if (!myresource.isDirectory() && match(myresource.getName())) { - myvector.addElement(myresource.getName()); - } - } - String[] files = new String[myvector.size()]; - myvector.copyInto(files); - Arrays.sort(files); - return files; - } else { + if (srcFile == null) { return super.getIncludedFiles(); } + scanme(); + Set s = matchFileEntries.keySet(); + return (String[]) (s.toArray(new String[s.size()])); + } + + /** + * Override parent implementation. + * @return count of included files. + * @since Ant 1.7 + */ + public int getIncludedFilesCount() { + if (srcFile == null) { + return super.getIncludedFilesCount(); + } + scanme(); + return matchFileEntries.size(); } /** @@ -116,23 +152,51 @@ public class ZipScanner extends DirectoryScanner { * include patterns and none of the exclude patterns. */ public String[] getIncludedDirectories() { - if (srcFile != null) { - Vector myvector = new Vector(); - // first check if the archive needs to be scanned again - scanme(); - for (Enumeration e = myentries.elements(); e.hasMoreElements();) { - Resource myresource = (Resource) e.nextElement(); - if (myresource.isDirectory() && match(myresource.getName())) { - myvector.addElement(myresource.getName()); - } - } - String[] files = new String[myvector.size()]; - myvector.copyInto(files); - Arrays.sort(files); - return files; - } else { + if (srcFile == null) { return super.getIncludedDirectories(); } + scanme(); + Set s = matchDirEntries.keySet(); + return (String[]) (s.toArray(new String[s.size()])); + } + + /** + * Override parent implementation. + * @return count of included directories. + * @since Ant 1.7 + */ + public int getIncludedDirsCount() { + if (srcFile == null) { + return super.getIncludedDirsCount(); + } + scanme(); + return matchDirEntries.size(); + } + + /** + * Get the set of Resources that represent files. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + /* package-private for now */ Iterator getResourceFiles() { + if (srcFile == null) { + return new FileResourceIterator(getBasedir(), getIncludedFiles()); + } + scanme(); + return matchFileEntries.values().iterator(); + } + + /** + * Get the set of Resources that represent directories. + * @return an Iterator of Resources. + * @since Ant 1.7 + */ + /* package-private for now */ Iterator getResourceDirectories() { + if (srcFile == null) { + return new FileResourceIterator(getBasedir(), getIncludedDirectories()); + } + scanme(); + return matchDirEntries.values().iterator(); } /** @@ -165,6 +229,7 @@ public class ZipScanner extends DirectoryScanner { } /** + * Get the named Resource. * @param name path name of the file sought in the archive * @return the resource * @since Ant 1.5.2 @@ -172,34 +237,35 @@ public class ZipScanner extends DirectoryScanner { public Resource getResource(String name) { if (srcFile == null) { return super.getResource(name); - } else if (name.equals("")) { + } + if (name.equals("")) { // special case in ZIPs, we do not want this thing included return new Resource("", true, Long.MAX_VALUE, true); } - // first check if the archive needs to be scanned again scanme(); - if (myentries.containsKey(name)) { - return (Resource) myentries.get(name); - } else if (myentries.containsKey(name + "/")) { - return (Resource) myentries.get(name + "/"); - } else { - return new Resource(name); + if (fileEntries.containsKey(name)) { + return (Resource) fileEntries.get(name); + } + name = trimSeparator(name); + + if (dirEntries.containsKey(name)) { + return (Resource) dirEntries.get(name); } + return new Resource(name); } /** * if the datetime of the archive did not change since * lastScannedResource was initialized returns immediately else if * the archive has not been scanned yet, then all the zip entries - * are put into the vector myentries as a vector of the resource - * type + * are put into the appropriate tables. */ private void scanme() { + //do not use a FileResource b/c it pulls File info from the filesystem: Resource thisresource = new Resource(srcFile.getAbsolutePath(), srcFile.exists(), srcFile.lastModified()); - // spare scanning again and again if (lastScannedResource != null && lastScannedResource.getName().equals(thisresource.getName()) @@ -207,10 +273,15 @@ public class ZipScanner extends DirectoryScanner { == thisresource.getLastModified()) { return; } - + init(); ZipEntry entry = null; ZipFile zf = null; - myentries = new Hashtable(); + + fileEntries.clear(); + dirEntries.clear(); + matchFileEntries.clear(); + matchDirEntries.clear(); + try { try { zf = new ZipFile(srcFile, encoding); @@ -219,15 +290,23 @@ public class ZipScanner extends DirectoryScanner { } catch (IOException ex) { throw new BuildException("problem opening " + srcFile, ex); } - Enumeration e = zf.getEntries(); while (e.hasMoreElements()) { entry = (ZipEntry) e.nextElement(); - myentries.put(new String(entry.getName()), - new Resource(entry.getName(), true, - entry.getTime(), - entry.isDirectory(), - entry.getSize())); + Resource r = new ZipResource(srcFile, encoding, entry); + String name = entry.getName(); + if (entry.isDirectory()) { + name = trimSeparator(name); + dirEntries.put(name, r); + if (match(name)) { + matchDirEntries.put(name, r); + } + } else { + fileEntries.put(name, r); + if (match(name)) { + matchFileEntries.put(name, r); + } + } } } finally { if (zf != null) { @@ -241,4 +320,9 @@ public class ZipScanner extends DirectoryScanner { // record data about the last scanned resource lastScannedResource = thisresource; } + + private static String trimSeparator(String s) { + return s.endsWith("/") ? s.substring(0, s.length() - 1) : s; + } + } diff --git a/src/main/org/apache/tools/ant/types/defaults.properties b/src/main/org/apache/tools/ant/types/defaults.properties index d1d1fa9c6..05ee6c4d9 100644 --- a/src/main/org/apache/tools/ant/types/defaults.properties +++ b/src/main/org/apache/tools/ant/types/defaults.properties @@ -1,8 +1,4 @@ -classfileset=org.apache.tools.ant.types.optional.depend.ClassfileSet description=org.apache.tools.ant.types.Description -dirset=org.apache.tools.ant.types.DirSet -filelist=org.apache.tools.ant.types.FileList -fileset=org.apache.tools.ant.types.FileSet filterchain=org.apache.tools.ant.types.FilterChain filterreader=org.apache.tools.ant.types.AntFilterReader filterset=org.apache.tools.ant.types.FilterSet @@ -20,19 +16,15 @@ compositemapper=org.apache.tools.ant.util.CompositeMapper chainedmapper=org.apache.tools.ant.util.ChainedMapper filtermapper=org.apache.tools.ant.types.mappers.FilterMapper -path=org.apache.tools.ant.types.Path patternset=org.apache.tools.ant.types.PatternSet regexp=org.apache.tools.ant.types.RegularExpression substitution=org.apache.tools.ant.types.Substitution xmlcatalog=org.apache.tools.ant.types.XMLCatalog extensionSet=org.apache.tools.ant.taskdefs.optional.extension.ExtensionSet extension=org.apache.tools.ant.taskdefs.optional.extension.ExtensionAdapter -libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet selector=org.apache.tools.ant.types.selectors.SelectSelector signedselector=org.apache.tools.ant.types.selectors.SignedSelector -zipfileset=org.apache.tools.ant.types.ZipFileSet scriptfilter=org.apache.tools.ant.types.optional.ScriptFilter -propertyset=org.apache.tools.ant.types.PropertySet assertions=org.apache.tools.ant.types.Assertions concatfilter=org.apache.tools.ant.filters.ConcatFilter issigned=org.apache.tools.ant.taskdefs.condition.IsSigned @@ -45,3 +37,28 @@ xor=org.apache.tools.ant.taskdefs.condition.Xor parsersupports=org.apache.tools.ant.taskdefs.condition.ParserSupports scriptmapper=org.apache.tools.ant.types.optional.ScriptMapper isfailure=org.apache.tools.ant.taskdefs.condition.IsFailure + +#ResourceCollections: +dirset=org.apache.tools.ant.types.DirSet +filelist=org.apache.tools.ant.types.FileList +fileset=org.apache.tools.ant.types.FileSet +path=org.apache.tools.ant.types.Path +propertyset=org.apache.tools.ant.types.PropertySet +zipfileset=org.apache.tools.ant.types.ZipFileSet +classfileset=org.apache.tools.ant.types.optional.depend.ClassfileSet +libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet +files=org.apache.tools.ant.types.resources.Files +restrict=org.apache.tools.ant.types.resources.Restrict +union=org.apache.tools.ant.types.resources.Union +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 + +#Resources (single-element ResourceCollections): +resource=org.apache.tools.ant.types.Resource +file=org.apache.tools.ant.types.resources.FileResource +url=org.apache.tools.ant.types.resources.URLResource +string=org.apache.tools.ant.types.resources.StringResource +zipentry=org.apache.tools.ant.types.resources.ZipResource +propertyresource=org.apache.tools.ant.types.resources.PropertyResource diff --git a/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionContainer.java b/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionContainer.java new file mode 100755 index 000000000..b86cde118 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionContainer.java @@ -0,0 +1,223 @@ +/* + * 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.HashSet; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Collection; +import java.util.Collections; +import java.util.NoSuchElementException; +import java.util.ConcurrentModificationException; + +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.Resource; +import org.apache.tools.ant.types.ResourceCollection; + +/** + * Base class for ResourceCollections that nest multiple ResourceCollections. + * @since Ant 1.7 + */ +public abstract class BaseResourceCollectionContainer + extends DataType implements ResourceCollection, Cloneable { + private List rc = new ArrayList(); + private Collection coll = null; + + /** + * 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; + } + rc.add(c); + FailFast.invalidate(this); + coll = null; + setChecked(false); + } + + /** + * Add the Collection of ResourceCollections to the container. + * @param c the Collection whose elements to add. + * @throws BuildException on error. + */ + public synchronized void addAll(Collection c) throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + try { + for (Iterator i = c.iterator(); i.hasNext();) { + add((ResourceCollection) i.next()); + } + } catch (ClassCastException e) { + throw new BuildException(e); + } + } + + /** + * Fulfill the ResourceCollection contract. The Iterator returned + * will throw ConcurrentModificationExceptions if ResourceCollections + * are added to this container while the Iterator is in use. + * @return a "fail-fast" Iterator. + */ + public synchronized final Iterator iterator() { + if (isReference()) { + return ((BaseResourceCollectionContainer) getCheckedRef()).iterator(); + } + dieOnCircularReference(); + cacheCollection(); + return new FailFast(this, coll.iterator()); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + */ + public synchronized int size() { + if (isReference()) { + return ((BaseResourceCollectionContainer) getCheckedRef()).size(); + } + dieOnCircularReference(); + cacheCollection(); + return coll.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(); + //first the easy way, if all children are filesystem-only, return true: + boolean goEarly = true; + for (Iterator i = rc.iterator(); goEarly && i.hasNext();) { + goEarly &= ((ResourceCollection) i.next()).isFilesystemOnly(); + } + if (goEarly) { + return true; + } + /* now check each Resource in case the child only + lets through files from any children IT may have: */ + cacheCollection(); + for (Iterator i = coll.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 void dieOnCircularReference(Stack stk, Project p) + throws BuildException { + if (isChecked()) { + return; + } + if (isReference()) { + super.dieOnCircularReference(stk, p); + } else { + for (Iterator i = rc.iterator(); i.hasNext();) { + Object o = i.next(); + if (o instanceof DataType) { + stk.push(o); + invokeCircularReferenceCheck((DataType) o, stk, p); + stk.pop(); + } + } + setChecked(true); + } + } + + /** + * Get the nested ResourceCollections. + * @return List. + */ + protected synchronized final List getResourceCollections() { + dieOnCircularReference(); + return Collections.unmodifiableList(rc); + } + + /** + * Template method for subclasses to return a Collection object of Resources. + * @return Collection. + */ + protected abstract Collection getCollection(); + + /** + * Implement clone. The set of nested resource + * collections is shallowly cloned. + * @return a cloned instance. + */ + public Object clone() { + try { + BaseResourceCollectionContainer c + = (BaseResourceCollectionContainer) super.clone(); + c.rc = new ArrayList(rc); + c.coll = null; + return c; + } catch (CloneNotSupportedException e) { + throw new BuildException(e); + } + } + + /** + * Format this BaseResourceCollectionContainer as a String. + * @return a descriptive String. + */ + public String toString() { + if (isReference()) { + return getCheckedRef().toString(); + } + cacheCollection(); + if (coll.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 void cacheCollection() { + coll = (coll == null) ? getCollection() : coll; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Difference.java b/src/main/org/apache/tools/ant/types/resources/Difference.java new file mode 100755 index 000000000..dbaf80663 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Difference.java @@ -0,0 +1,67 @@ +/* + * 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.HashSet; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.ResourceCollection; + +/** + * ResourceCollection representing the difference between + * two or more nested ResourceCollections. + * @since Ant 1.7 + */ +public class Difference extends BaseResourceCollectionContainer { + + /** + * Calculate the difference of the nested ResourceCollections. + * @return a Collection of Resources. + */ + protected Collection getCollection() { + List rc = getResourceCollections(); + int size = rc.size(); + if (size < 2) { + throw new BuildException("The difference of " + size + + " resource collection" + ((size == 1) ? "" : "s") + + " is undefined."); + } + HashSet hs = new HashSet(); + ArrayList al = new ArrayList(); + for (Iterator rcIter = rc.iterator(); rcIter.hasNext();) { + for (Iterator r = nextRC(rcIter).iterator(); r.hasNext();) { + Object next = r.next(); + if (hs.add(next)) { + al.add(next); + } else { + al.remove(next); + } + } + } + return al; + } + + private static ResourceCollection nextRC(Iterator i) { + return (ResourceCollection) i.next(); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/FailFast.java b/src/main/org/apache/tools/ant/types/resources/FailFast.java new file mode 100755 index 000000000..d95f68daa --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/FailFast.java @@ -0,0 +1,132 @@ +/* + * 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.Set; +import java.util.HashSet; +import java.util.Iterator; +import java.util.WeakHashMap; +import java.util.NoSuchElementException; +import java.util.ConcurrentModificationException; + +/** + * Helper class for ResourceCollections to return Iterators + * that fail on changes to the object. + * @since Ant 1.7 + */ +/*package-private*/ class FailFast implements Iterator { + private static final WeakHashMap map = new WeakHashMap(); + + /** + * Invalidate any in-use Iterators from the specified Object. + * @param o the parent Object. + */ + static synchronized void invalidate(Object o) { + Set s = (Set) (map.get(o)); + if (s != null) { + s.clear(); + } + } + + private static synchronized void add(FailFast f) { + Set s = (Set) (map.get(f.parent)); + if (s == null) { + s = new HashSet(); + map.put(f.parent, s); + } + s.add(f); + } + + private static synchronized void remove(FailFast f) { + Set s = (Set) (map.get(f.parent)); + if (s != null) { + s.remove(f); + } + } + + private static synchronized void failFast(FailFast f) { + Set s = (Set) (map.get(f.parent)); + if (!s.contains(f)) { + throw new ConcurrentModificationException(); + } + } + + private Object parent; + private Iterator wrapped; + + /** + * Construct a new FailFast Iterator wrapping the specified Iterator + * and dependent upon the specified parent Object. + * @param o the parent Object. + * @param i the wrapped Iterator. + */ + FailFast(Object o, Iterator i) { + if (o == null) { + throw new IllegalArgumentException("parent object is null"); + } + if (i == null) { + throw new IllegalArgumentException("cannot wrap null iterator"); + } + parent = o; + if (i.hasNext()) { + wrapped = i; + add(this); + } + } + + /** + * Fulfill the Iterator contract. + * @return true if there are more elements. + */ + public boolean hasNext() { + if (wrapped == null) { + return false; + } + failFast(this); + return wrapped.hasNext(); + } + + /** + * Fulfill the Iterator contract. + * @return the next element. + * @throws NoSuchElementException if no more elements. + */ + public Object next() { + if (wrapped == null || !wrapped.hasNext()) { + throw new NoSuchElementException(); + } + failFast(this); + try { + return wrapped.next(); + } finally { + if (!wrapped.hasNext()) { + wrapped = null; + remove(this); + } + } + } + + /** + * Fulfill the Iterator contract. + * @throws UnsupportedOperationException always. + */ + public void remove() { + throw new UnsupportedOperationException(); + } + +} + diff --git a/src/main/org/apache/tools/ant/types/resources/FileResource.java b/src/main/org/apache/tools/ant/types/resources/FileResource.java new file mode 100755 index 000000000..224cc1736 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/FileResource.java @@ -0,0 +1,300 @@ +/* + * 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.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.Reference; + +/** + * A Resource representation of a File. + * @since Ant 1.7 + */ +public class FileResource extends Resource implements Touchable { + + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private static final int NULL_FILE + = Resource.getMagicNumber("null file".getBytes()); + + private File file; + private File base; + + /** + * Default constructor. + */ + public FileResource() { + } + + /** + * Construct a new FileResource using the specified base File and relative name. + * @param b the base File (directory). + * @param name the relative filename. + */ + public FileResource(File b, String name) { + setFile(FILE_UTILS.resolveFile(b, name)); + setBase(b); + } + + /** + * Construct a new FileResource from a File. + * @param f the File represented. + */ + public FileResource(File f) { + setFile(f); + } + + /** + * Constructor for Ant attribute introspection. + * @param p the Project against which to resolve s. + * @param s the absolute or Project-relative filename as a String. + * @see org.apache.tools.ant.IntrospectionHelper + */ + public FileResource(Project p, String s) { + this(p.resolveFile(s)); + setProject(p); + } + + /** + * Set the File for this FileResource. + * @param f the File to be represented. + */ + public void setFile(File f) { + checkAttributesAllowed(); + file = f; + } + + /** + * Get the file represented by this FileResource. + * @return the File. + */ + public File getFile() { + return isReference() ? ((FileResource) getCheckedRef()).getFile() : file; + } + + /** + * Set the base File for this FileResource. + * @param b the base File. + */ + public void setBase(File b) { + checkAttributesAllowed(); + base = b; + } + + /** + * Return the base to which the name is relative. + * @return the base File. + */ + public File getBase() { + return isReference() + ? ((FileResource) getCheckedRef()).getBase() : base; + } + + /** + * Overrides the super version. + * @param r the Reference to set. + */ + public void setRefid(Reference r) { + if (file != null || base != null) { + throw tooManyAttributes(); + } + super.setRefid(r); + } + + /** + * Get the name of this FileResource relative to its base, if any. + * @return the name of this resource. + */ + public String getName() { + if (isReference()) { + return ((Resource) getCheckedRef()).getName(); + } + File b = getBase(); + return b == null ? getNotNullFile().getAbsolutePath() + : FILE_UTILS.removeLeadingPath(b, getNotNullFile()); + } + + /** + * Learn whether this file exists. + * @return true if this resource exists. + */ + public boolean isExists() { + return isReference() ? ((Resource) getCheckedRef()).isExists() + : getNotNullFile().exists(); + } + + /** + * Get the modification time in milliseconds since 01.01.1970 . + * @return 0 if the resource does not exist. + */ + public long getLastModified() { + return isReference() + ? ((Resource) getCheckedRef()).getLastModified() + : getNotNullFile().lastModified(); + } + + /** + * Learn whether the resource is a directory. + * @return boolean flag indicating if the resource is a directory. + */ + public boolean isDirectory() { + return isReference() ? ((Resource) getCheckedRef()).isDirectory() + : getNotNullFile().isDirectory(); + } + + /** + * Get the size of this Resource. + * @return the size, as a long, 0 if the Resource does not exist. + */ + public long getSize() { + return isReference() ? ((Resource) getCheckedRef()).getSize() + : getNotNullFile().length(); + } + + /** + * Return an InputStream for reading the contents of this Resource. + * @return an InputStream object. + * @throws IOException if an error occurs. + */ + public InputStream getInputStream() throws IOException { + return isReference() + ? ((Resource) getCheckedRef()).getInputStream() + : new FileInputStream(getNotNullFile()); + } + + /** + * Get an OutputStream for the Resource. + * @return an OutputStream to which content can be written. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if OutputStreams are not + * supported for this Resource type. + */ + public OutputStream getOutputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getOutputStream(); + } + File f = getNotNullFile(); + if (f.exists()) { + if (f.isFile()) { + f.delete(); + } + } else { + File p = f.getParentFile(); + if (p != null && !(p.exists())) { + p.mkdirs(); + } + } + return new FileOutputStream(f); + } + + /** + * Compare this FileResource to another Resource. + * @param another the other Resource against which to compare. + * @return a negative integer, zero, or a positive integer as this FileResource + * is less than, equal to, or greater than the specified Resource. + */ + public int compareTo(Object another) { + if (isReference()) { + return ((Comparable) getCheckedRef()).compareTo(another); + } + return this.equals(another) ? 0 : super.compareTo(another); + } + + /** + * Compare another Object to this FileResource for equality. + * @param another the other Object to compare. + * @return true if another is a FileResource representing the same file. + */ + public boolean equals(Object another) { + if (this == another) { + return true; + } + if (isReference()) { + return getCheckedRef().equals(another); + } + if (!(another.getClass().equals(getClass()))) { + return false; + } + FileResource otherfr = (FileResource) another; + return getFile() == null + ? otherfr.getFile() == null + : getFile().equals(otherfr.getFile()); + } + + /** + * Get the hash code for this Resource. + * @return hash code as int. + */ + public int hashCode() { + if (isReference()) { + return getCheckedRef().hashCode(); + } + return MAGIC * (getFile() == null ? NULL_FILE : getFile().hashCode()); + } + + /** + * Get the string representation of this Resource. + * @return this FileResource formatted as a String. + */ + public String toString() { + return isReference() ? getCheckedRef().toString() + : FILE_UTILS.normalize(file.getAbsolutePath()).getAbsolutePath(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return whether this Resource is a FileResource. + */ + public boolean isFilesystemOnly() { + return !isReference() + || ((FileResource) getCheckedRef()).isFilesystemOnly(); + } + + /** + * Implement the Touchable interface. + * @param modTime new last modification time. + */ + public void touch(long modTime) { + if (isReference()) { + ((FileResource) getCheckedRef()).touch(modTime); + return; + } + getNotNullFile().setLastModified(modTime); + } + + /** + * Get the file represented by this FileResource, ensuring it is not null. + * @return the not-null File. + * @throws BuildException if file is null. + */ + protected File getNotNullFile() { + if (getFile() == null) { + throw new BuildException("file attribute is null!"); + } + return getFile(); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/FileResourceIterator.java b/src/main/org/apache/tools/ant/types/resources/FileResourceIterator.java new file mode 100755 index 000000000..d217cb5fe --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/FileResourceIterator.java @@ -0,0 +1,108 @@ +/* + * 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.Arrays; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.NoSuchElementException; + +/** + * Iterator of FileResources from filenames. + * @since Ant 1.7 + */ +public class FileResourceIterator implements Iterator { + private File basedir; + private String[] files; + private int pos = 0; + + /** + * Construct a new FileResourceIterator. + */ + public FileResourceIterator() { + } + + /** + * Construct a new FileResourceIterator relative to the specified + * base directory. + * @param f the base directory of this instance. + */ + public FileResourceIterator(File f) { + basedir = f; + } + + /** + * Construct a new FileResourceIterator over the specified filenames, + * relative to the specified base directory. + * @param f the base directory of this instance. + * @param files the String[] of filenames. + */ + public FileResourceIterator(File f, String[] s) { + this(f); + addFiles(s); + } + + /** + * Add an array of filenames to this FileResourceIterator. + * @param s the filenames to add. + */ + public void addFiles(String[] s) { + int start = (files == null) ? 0 : files.length; + String[] newfiles = new String[start + s.length]; + if (start > 0) { + System.arraycopy(files, 0, newfiles, 0, start); + } + files = newfiles; + System.arraycopy(s, 0, files, start, s.length); + } + + /** + * Find out whether this FileResourceIterator has more elements. + * @return whether there are more Resources to iterate over. + */ + public boolean hasNext() { + return pos < files.length; + } + + /** + * Get the next element from this FileResourceIterator. + * @return the next Object. + */ + public Object next() { + return nextResource(); + } + + /** + * Not implemented. + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + /** + * Convenience method to return the next resource. + * @return the next File. + */ + public FileResource nextResource() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return new FileResource(basedir, files[pos++]); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Files.java b/src/main/org/apache/tools/ant/types/resources/Files.java new file mode 100755 index 000000000..52a534c3a --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Files.java @@ -0,0 +1,503 @@ +/* + * 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.Stack; +import java.util.Arrays; +import java.util.Vector; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.types.PatternSet; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.selectors.FileSelector; +import org.apache.tools.ant.types.selectors.AbstractSelectorContainer; + +/** + * ResourceCollection implementation; like AbstractFileSet with absolute paths. + * @since Ant 1.7 + */ +public class Files extends AbstractSelectorContainer + implements Cloneable, ResourceCollection { + + private static final Iterator EMPTY_ITERATOR + = Collections.EMPTY_SET.iterator(); + + private PatternSet defaultPatterns = new PatternSet(); + private Vector additionalPatterns = new Vector(); + private Vector selectors = new Vector(); + + private boolean useDefaultExcludes = true; + private boolean caseSensitive = true; + private boolean followSymlinks = true; + + /* cached DirectoryScanner instance */ + private DirectoryScanner ds = null; + + /** + * Construct a new Files collection. + */ + public Files() { + super(); + } + + /** + * Construct a new Files collection, shallowly cloned + * from the specified Files. + * @param f the Files to use as a template. + */ + protected Files(Files f) { + this.defaultPatterns = f.defaultPatterns; + this.additionalPatterns = f.additionalPatterns; + this.selectors = f.selectors; + this.useDefaultExcludes = f.useDefaultExcludes; + this.caseSensitive = f.caseSensitive; + this.followSymlinks = f.followSymlinks; + this.ds = f.ds; + setProject(f.getProject()); + } + + /** + * Make this instance in effect a reference to another instance. + * + *

You must not set another attribute or nest elements inside + * this element if you make it a reference.

+ * @param r the Reference to use. + */ + public void setRefid(Reference r) throws BuildException { + if (hasPatterns(defaultPatterns)) { + throw tooManyAttributes(); + } + if (!additionalPatterns.isEmpty()) { + throw noChildrenAllowed(); + } + if (!selectors.isEmpty()) { + throw noChildrenAllowed(); + } + super.setRefid(r); + } + + /** + * Create a nested patternset. + * @return PatternSet. + */ + public synchronized PatternSet createPatternSet() { + if (isReference()) { + throw noChildrenAllowed(); + } + PatternSet patterns = new PatternSet(); + additionalPatterns.addElement(patterns); + ds = null; + return patterns; + } + + /** + * Add a name entry to the include list. + * @return PatternSet.NameEntry. + */ + public synchronized PatternSet.NameEntry createInclude() { + if (isReference()) { + throw noChildrenAllowed(); + } + ds = null; + return defaultPatterns.createInclude(); + } + + /** + * Add a name entry to the include files list. + * @return PatternSet.NameEntry. + */ + public synchronized PatternSet.NameEntry createIncludesFile() { + if (isReference()) { + throw noChildrenAllowed(); + } + ds = null; + return defaultPatterns.createIncludesFile(); + } + + /** + * Add a name entry to the exclude list. + * @return PatternSet.NameEntry. + */ + public synchronized PatternSet.NameEntry createExclude() { + if (isReference()) { + throw noChildrenAllowed(); + } + ds = null; + return defaultPatterns.createExclude(); + } + + /** + * Add a name entry to the excludes files list. + * @return PatternSet.NameEntry. + */ + public synchronized PatternSet.NameEntry createExcludesFile() { + if (isReference()) { + throw noChildrenAllowed(); + } + ds = null; + return defaultPatterns.createExcludesFile(); + } + + /** + * Append includes to the current list of include + * patterns. + * + *

Patterns may be separated by a comma or a space.

+ * + * @param includes the String containing the include patterns. + */ + public synchronized void setIncludes(String includes) { + checkAttributesAllowed(); + defaultPatterns.setIncludes(includes); + ds = null; + } + + /** + * Append includes to the current list of include + * patterns. + * + * @param includes array containing the include patterns. + */ + public synchronized void appendIncludes(String[] includes) { + checkAttributesAllowed(); + if (includes != null) { + for (int i = 0; i < includes.length; i++) { + defaultPatterns.createInclude().setName(includes[i]); + } + ds = null; + } + } + + /** + * Append excludes to the current list of exclude + * patterns. + * + *

Patterns may be separated by a comma or a space.

+ * + * @param excludes the String containing the exclude patterns. + */ + public synchronized void setExcludes(String excludes) { + checkAttributesAllowed(); + defaultPatterns.setExcludes(excludes); + ds = null; + } + + /** + * Append excludes to the current list of include + * patterns. + * + * @param excludes array containing the exclude patterns. + */ + public synchronized void appendExcludes(String[] excludes) { + checkAttributesAllowed(); + if (excludes != null) { + for (int i = 0; i < excludes.length; i++) { + defaultPatterns.createExclude().setName(excludes[i]); + } + ds = null; + } + } + + /** + * Set the File containing the includes patterns. + * + * @param incl File instance. + */ + public synchronized void setIncludesfile(File incl) throws BuildException { + checkAttributesAllowed(); + defaultPatterns.setIncludesfile(incl); + ds = null; + } + + /** + * Set the File containing the excludes patterns. + * + * @param excl File instance. + */ + public synchronized void setExcludesfile(File excl) throws BuildException { + checkAttributesAllowed(); + defaultPatterns.setExcludesfile(excl); + ds = null; + } + + /** + * Set whether default exclusions should be used or not. + * + * @param useDefaultExcludes boolean. + */ + public synchronized void setDefaultexcludes(boolean useDefaultExcludes) { + checkAttributesAllowed(); + this.useDefaultExcludes = useDefaultExcludes; + ds = null; + } + + /** + * Get whether default exclusions should be used or not. + */ + public synchronized boolean getDefaultexcludes() { + return (isReference()) + ? getRef().getDefaultexcludes() : useDefaultExcludes; + } + + /** + * Set case-sensitivity of the Files collection. + * + * @param caseSensitive boolean. + */ + public synchronized void setCaseSensitive(boolean caseSensitive) { + checkAttributesAllowed(); + this.caseSensitive = caseSensitive; + ds = null; + } + + /** + * Find out if this Files collection is case-sensitive. + * + * @return boolean indicating whether the Files + * collection is case-sensitive. + */ + public synchronized boolean isCaseSensitive() { + return (isReference()) + ? getRef().isCaseSensitive() : caseSensitive; + } + + /** + * Set whether or not symbolic links should be followed. + * + * @param followSymlinks whether or not symbolic links should be followed. + */ + public synchronized void setFollowSymlinks(boolean followSymlinks) { + checkAttributesAllowed(); + this.followSymlinks = followSymlinks; + ds = null; + } + + /** + * Find out whether symbolic links should be followed. + * + * @return boolean indicating whether symbolic links + * should be followed. + */ + public synchronized boolean isFollowSymlinks() { + return (isReference()) + ? getRef().isFollowSymlinks() : followSymlinks; + } + + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + */ + public synchronized Iterator iterator() { + if (isReference()) { + return getRef().iterator(); + } + ensureDirectoryScannerSetup(); + ds.scan(); + int fct = ds.getIncludedFilesCount(); + int dct = ds.getIncludedDirsCount(); + if (fct + dct == 0) { + return EMPTY_ITERATOR; + } + FileResourceIterator result = new FileResourceIterator(); + if (fct > 0) { + result.addFiles(ds.getIncludedFiles()); + } + if (dct > 0) { + result.addFiles(ds.getIncludedDirectories()); + } + return result; + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + */ + public synchronized int size() { + if (isReference()) { + return getRef().size(); + } + ensureDirectoryScannerSetup(); + ds.scan(); + return ds.getIncludedFilesCount() + ds.getIncludedDirsCount(); + } + + /** + * Find out whether this Files collection has patterns. + * + * @return whether any patterns are in this container. + */ + public synchronized boolean hasPatterns() { + if (isReference()) { + return getRef().hasPatterns(); + } + if (hasPatterns(defaultPatterns)) { + return true; + } + for (Iterator i = additionalPatterns.iterator(); i.hasNext();) { + if (hasPatterns((PatternSet) i.next())) { + return true; + } + } + return false; + } + + /** + * Add a new selector into this container. + * + * @param selector the new FileSelector to add. + */ + public synchronized void appendSelector(FileSelector selector) { + if (isReference()) { + throw noChildrenAllowed(); + } + super.appendSelector(selector); + ds = null; + } + + /** + * Format this Files collection as a String. + * @return a descriptive String. + */ + public String toString() { + if (isReference()) { + return getRef().toString(); + } + Iterator i = iterator(); + if (!i.hasNext()) { + return ""; + } + StringBuffer sb = new StringBuffer(); + while (i.hasNext()) { + if (sb.length() > 0) { + sb.append(File.pathSeparatorChar); + } + sb.append(i.next()); + } + return sb.toString(); + } + + /** + * Create a deep clone of this instance, except for the nested selectors + * (the list of selectors is a shallow clone of this instance's list). + * @return a cloned Object. + */ + public synchronized Object clone() { + if (isReference()) { + return getRef().clone(); + } + try { + Files f = (Files) super.clone(); + f.defaultPatterns = (PatternSet) defaultPatterns.clone(); + f.additionalPatterns = new Vector(additionalPatterns.size()); + for (Iterator iter = additionalPatterns.iterator(); iter.hasNext();) { + PatternSet ps = (PatternSet) iter.next(); + f.additionalPatterns.add(ps.clone()); + } + f.selectors = new Vector(selectors); + return f; + } catch (CloneNotSupportedException e) { + throw new BuildException(e); + } + } + + /** + * Get the merged include patterns for this Files collection. + * @param p Project instance. + * @return the include patterns of the default pattern set and all + * nested patternsets. + */ + public String[] mergeIncludes(Project p) { + return mergePatterns(p).getIncludePatterns(p); + } + + /** + * Get the merged exclude patterns for this Files collection. + * @param p Project instance. + * @return the exclude patterns of the default pattern set and all + * nested patternsets. + */ + public String[] mergeExcludes(Project p) { + return mergePatterns(p).getExcludePatterns(p); + } + + /** + * Get the merged patterns for this Files collection. + * @param p Project instance. + * @return the default patternset merged with the additional sets + * in a new PatternSet instance. + */ + public synchronized PatternSet mergePatterns(Project p) { + if (isReference()) { + return getRef().mergePatterns(p); + } + PatternSet ps = new PatternSet(); + ps.append(defaultPatterns, p); + final int count = additionalPatterns.size(); + for (int i = 0; i < count; i++) { + Object o = additionalPatterns.elementAt(i); + ps.append((PatternSet) o, p); + } + return ps; + } + + /** + * Always returns true. + * @return true indicating that all elements of a Files collection + * will be FileResources. + */ + public boolean isFilesystemOnly() { + return true; + } + + /** + * Perform the check for circular references and return the + * referenced Files collection. + * @return FileCollection. + */ + protected Files getRef() { + return (Files) getCheckedRef(); + } + + private synchronized void ensureDirectoryScannerSetup() { + if (ds == null) { + ds = new DirectoryScanner(); + PatternSet ps = mergePatterns(getProject()); + ds.setIncludes(ps.getIncludePatterns(getProject())); + ds.setExcludes(ps.getExcludePatterns(getProject())); + ds.setSelectors(getSelectors(getProject())); + if (useDefaultExcludes) { + ds.addDefaultExcludes(); + } + ds.setCaseSensitive(caseSensitive); + ds.setFollowSymlinks(followSymlinks); + } + } + + private boolean hasPatterns(PatternSet ps) { + return ps.getIncludePatterns(getProject()).length > 0 + || ps.getExcludePatterns(getProject()).length > 0; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/ImmutableResourceException.java b/src/main/org/apache/tools/ant/types/resources/ImmutableResourceException.java new file mode 100755 index 000000000..e828440df --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/ImmutableResourceException.java @@ -0,0 +1,44 @@ +/* + * 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.IOException; + +/** + * Exception thrown when an attempt is made to get an OutputStream + * from an immutable Resource. + * @since Ant 1.7 + */ +public class ImmutableResourceException extends IOException { + + /** + * Default constructor. + */ + public ImmutableResourceException() { + super(); + } + + /** + * Construct a new ImmutableResourceException with the specified message. + * @param s the message String. + */ + public ImmutableResourceException(String s) { + super(s); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Intersect.java b/src/main/org/apache/tools/ant/types/resources/Intersect.java new file mode 100755 index 000000000..f1947e546 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Intersect.java @@ -0,0 +1,62 @@ +/* + * 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 org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.ResourceCollection; + +/** + * ResourceCollection representing the intersection + * of multiple nested ResourceCollections. + * @since Ant 1.7 + */ +public class Intersect extends BaseResourceCollectionContainer { + + /** + * Calculate the intersection of the nested ResourceCollections. + * @return a Collection of Resources. + */ + protected Collection getCollection() { + List rcs = getResourceCollections(); + int size = rcs.size(); + if (size < 2) { + throw new BuildException("The intersection of " + size + + " resource collection" + ((size == 1) ? "" : "s") + + " is undefined."); + } + ArrayList al = new ArrayList(); + Iterator rc = rcs.iterator(); + al.addAll(collect(rc.next())); + while (rc.hasNext()) { + al.retainAll(collect(rc.next())); + } + return al; + } + + private ArrayList collect(Object o) { + ArrayList result = new ArrayList(); + for (Iterator i = ((ResourceCollection) o).iterator(); i.hasNext();) { + result.add(i.next()); + } + return result; + } +} diff --git a/src/main/org/apache/tools/ant/types/resources/PropertyResource.java b/src/main/org/apache/tools/ant/types/resources/PropertyResource.java new file mode 100755 index 000000000..b99b7eb64 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/PropertyResource.java @@ -0,0 +1,133 @@ +/* + * 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.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.ByteArrayInputStream; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.util.PropertyOutputStream; + +/** + * Exposes an Ant property as a Resource. + * @since Ant 1.7 + */ +public class PropertyResource extends Resource { + + /** Magic number */ + private static final int PROPERTY_MAGIC + = Resource.getMagicNumber("PropertyResource".getBytes()); + + private static final InputStream UNSET = new InputStream() { + public int read() { + return -1; + } + }; + + /** + * Default constructor. + */ + public PropertyResource() { + } + + /** + * Construct a new PropertyResource with the specified name. + * @param n the String name of this PropertyResource (Ant property name/key). + */ + public PropertyResource(Project p, String n) { + super(n); + setProject(p); + } + + /** + * Get the value of this PropertyResource. + * @return the value of the specified Property. + */ + public String getValue() { + Project p = getProject(); + return p == null ? null : p.getProperty(getName()); + } + + /** + * Find out whether this Resource exists. + * @return true if the Property is set, false otherwise. + */ + public boolean isExists() { + return getValue() != null; + } + + /** + * Get the size of this Resource. + * @return the size, as a long, 0 if the Resource does not exist (for + * compatibility with java.io.File), or UNKNOWN_SIZE if not known. + */ + public long getSize() { + if (isReference()) { + return ((Resource) getCheckedRef()).getSize(); + } + return isExists() ? (long) getValue().length() : 0L; + } + + /** + * Get the hash code for this Resource. + * @return hash code as int. + */ + public int hashCode() { + if (isReference()) { + return getCheckedRef().hashCode(); + } + return super.hashCode() * PROPERTY_MAGIC; + } + + /** + * Get an InputStream for the Resource. + * @return an InputStream containing this Resource's content. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if InputStreams are not + * supported for this Resource type. + */ + public InputStream getInputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getInputStream(); + } + return isExists() ? new ByteArrayInputStream(getValue().getBytes()) : UNSET; + } + + /** + * Get an OutputStream for the Resource. + * @return an OutputStream to which content can be written. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if OutputStreams are not + * supported for this Resource type. + */ + public OutputStream getOutputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getOutputStream(); + } + if (isExists()) { + throw new ImmutableResourceException(); + } + return new PropertyOutputStream(getProject(), getName()); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Resources.java b/src/main/org/apache/tools/ant/types/resources/Resources.java new file mode 100755 index 000000000..a20bb2bd5 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Resources.java @@ -0,0 +1,187 @@ +/* + * 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.Stack; +import java.util.Vector; +import java.util.Iterator; +import java.util.Collection; +import java.util.AbstractCollection; +import java.util.NoSuchElementException; + +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; + +/** + * Generic ResourceCollection: Either stores nested ResourceCollections, + * making no attempt to remove duplicates, or references another ResourceCollection. + * @since Ant 1.7 + */ +public class Resources extends DataType implements ResourceCollection { + + private class MyCollection extends AbstractCollection { + int size; + + MyCollection() { + size = 0; + for (Iterator rci = rc.iterator(); rci.hasNext();) { + size += ((ResourceCollection) rci.next()).size(); + } + } + public int size() { + return size; + } + public Iterator iterator() { + return new MyIterator(); + } + private class MyIterator implements Iterator { + Iterator rci = rc.iterator(); + Iterator ri = null; + public boolean hasNext() { + if ((ri == null || !ri.hasNext()) && rci.hasNext()) { + ri = ((ResourceCollection) rci.next()).iterator(); + } + return ri != null && ri.hasNext(); + } + public Object next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return ri.next(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + } + } + + private Vector rc = null; + private Collection coll = null; + + /** + * Add a ResourceCollection. + * @param c the ResourceCollection to add. + */ + public synchronized void add(ResourceCollection c) { + if (isReference()) { + throw noChildrenAllowed(); + } + rc = (rc == null) ? new Vector() : rc; + rc.add(c); + FailFast.invalidate(this); + coll = null; + setChecked(false); + } + + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + */ + public synchronized Iterator iterator() { + if (isReference()) { + return getRef().iterator(); + } + validate(); + return new FailFast(this, coll.iterator()); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + */ + public synchronized int size() { + if (isReference()) { + return getRef().size(); + } + validate(); + return coll.size(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return true if all Resources represent files. + */ + public boolean isFilesystemOnly() { + if (isReference()) { + return getRef().isFilesystemOnly(); + } + validate(); + //first the easy way, if all children are filesystem-only, return true: + boolean goEarly = true; + for (Iterator i = rc.iterator(); goEarly && i.hasNext();) { + goEarly &= ((ResourceCollection) i.next()).isFilesystemOnly(); + } + if (goEarly) { + return true; + } + /* now check each Resource in case the child only + lets through files from any children IT may have: */ + for (Iterator i = coll.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 void dieOnCircularReference(Stack stk, Project p) + throws BuildException { + if (isChecked()) { + return; + } + if (isReference()) { + super.dieOnCircularReference(stk, p); + } else { + for (Iterator i = rc.iterator(); i.hasNext();) { + Object o = i.next(); + if (o instanceof DataType) { + invokeCircularReferenceCheck((DataType) o, stk, p); + } + } + setChecked(true); + } + } + + /** + * Resolves references, allowing any ResourceCollection. + * @return the referenced ResourceCollection. + */ + private ResourceCollection getRef() { + return (ResourceCollection) getCheckedRef( + ResourceCollection.class, "ResourceCollection"); + } + + private synchronized void validate() { + dieOnCircularReference(); + if (rc == null || rc.size() == 0) { + throw new BuildException("Resources: no resources specified."); + } + coll = (coll == null) ? new MyCollection() : coll; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Restrict.java b/src/main/org/apache/tools/ant/types/resources/Restrict.java new file mode 100755 index 000000000..fa591b49f --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Restrict.java @@ -0,0 +1,137 @@ +/* + * 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.Iterator; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.resources.selectors.ResourceSelector; +import org.apache.tools.ant.types.resources.selectors.ResourceSelectorContainer; + +/** + * ResourceCollection that allows a number of selectors to be + * applied to a single ResourceCollection for the purposes of + * restricting or narrowing results. + * @since Ant 1.7 + */ +public class Restrict + extends ResourceSelectorContainer implements ResourceCollection { + + private static final String ONE_NESTED_MESSAGE + = "Restriction is to be applied to exactly one nested resource collection."; + + private ResourceCollection rc; + + /** + * Add the ResourceCollection. + * @param c the ResourceCollection to add. + */ + public synchronized void add(ResourceCollection c) { + if (isReference()) { + throw noChildrenAllowed(); + } + if (rc != null) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + rc = c; + } + + /** + * Add a ResourceSelector. + * @param the ResourceSelector to add. + */ + public synchronized void add(ResourceSelector s) { + super.add(s); + FailFast.invalidate(this); + } + + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + */ + public final synchronized Iterator iterator() { + if (isReference()) { + return ((Restrict) getCheckedRef()).iterator(); + } + dieOnCircularReference(); + if (rc == null) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + return new FailFast(this, getCollection().iterator()); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + */ + public synchronized int size() { + if (isReference()) { + return ((Restrict) getCheckedRef()).size(); + } + dieOnCircularReference(); + return getCollection().size(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return whether this is a filesystem-only resource collection. + */ + public synchronized boolean isFilesystemOnly() { + if (isReference()) { + return ((Restrict) getCheckedRef()).isFilesystemOnly(); + } + dieOnCircularReference(); + if (rc == null) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + //first the easy way, if child is filesystem-only, return true: + if (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 = getCollection().iterator(); i.hasNext();) { + if (!(i.next() instanceof FileResource)) { + return false; + } + } + return true; + } + + /** + * Restrict the nested ResourceCollection based on the nested selectors. + * @return a Collection of Resources. + */ + protected Collection getCollection() { + ArrayList result = new ArrayList(); +outer: for (Iterator ri = rc.iterator(); ri.hasNext();) { + Resource r = (Resource) ri.next(); + for (Iterator i = getSelectors(); i.hasNext();) { + if (!((ResourceSelector) (i.next())).isSelected(r)) { + continue outer; + } + } + result.add(r); + } + return result; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Sort.java b/src/main/org/apache/tools/ant/types/resources/Sort.java new file mode 100755 index 000000000..79dbe31b5 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Sort.java @@ -0,0 +1,107 @@ +/* + * 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.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; +import org.apache.tools.ant.types.resources.comparators.ResourceComparator; + +/** + * ResourceCollection that sorts another ResourceCollection. + * @since Ant 1.7 + */ +public class Sort extends BaseResourceCollectionContainer { + private static final String ONE_NESTED_MESSAGE + = "Sorting is to be applied to exactly one nested resource collection."; + + private Stack compStack = new Stack(); + + /** + * Sort the contained elements. + * @return a Collection of Resources. + */ + protected Collection getCollection() { + List rcs = getResourceCollections(); + if (rcs.size() != 1) { + throw new BuildException(ONE_NESTED_MESSAGE); + } + Iterator nested = ((ResourceCollection) (rcs.get(0))).iterator(); + if (!(nested.hasNext())) { + return Collections.EMPTY_SET; + } + ArrayList al = new ArrayList(); + while (nested.hasNext()) { + al.add(nested.next()); + } + if (compStack.empty()) { + Collections.sort(al); + } else { + for (Stack s = (Stack) compStack.clone(); !s.empty();) { + Collections.sort(al, (ResourceComparator) s.pop()); + } + } + return al; + } + + /** + * Add a ResourceComparator to this Sort ResourceCollection. + * If multiple ResourceComparator are added, they will be processed in LIFO order. + * @param c the ResourceComparator to add. + */ + public void add(ResourceComparator c) { + if (isReference()) { + throw noChildrenAllowed(); + } + compStack.push(c); + } + + /** + * Overrides the BaseResourceCollectionContainer version + * to recurse on nested ResourceComparators. + * @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 void dieOnCircularReference(Stack stk, Project p) + throws BuildException { + if (isChecked()) { + return; + } + if (isReference()) { + super.dieOnCircularReference(stk, p); + } else { + for (Iterator i = compStack.iterator(); i.hasNext();) { + Object o = i.next(); + if (o instanceof DataType) { + stk.push(o); + invokeCircularReferenceCheck((DataType) o, stk, p); + } + } + setChecked(true); + } + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/StringResource.java b/src/main/org/apache/tools/ant/types/resources/StringResource.java new file mode 100755 index 000000000..41cf93370 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/StringResource.java @@ -0,0 +1,204 @@ +/* + * 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.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FilterOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.Reference; + +/** + * Exposes a string as a Resource. + * @since Ant 1.7 + */ +public class StringResource extends Resource { + + /** Magic number */ + private static final int STRING_MAGIC + = Resource.getMagicNumber("StringResource".getBytes()); + + private String encoding = null; + + /** + * Default constructor. + */ + public StringResource() { + } + + /** + * Construct a StringResource with the supplied value. + * @param value the value of this StringResource. + */ + public StringResource(String value) { + setValue(value); + } + + /** + * Enforce String immutability. + * @param s the new name/value for this StringResource. + */ + public synchronized void setName(String s) { + if (getName() != null) { + throw new BuildException(new ImmutableResourceException()); + } + super.setName(s); + } + + /** + * The value attribute is a semantically superior alias for the name attribute. + * @param s the String's value. + */ + public synchronized void setValue(String s) { + setName(s); + } + + /** + * Synchronize access. + * @return the name/value of this StringResource. + */ + public synchronized String getName() { + return super.getName(); + } + + /** + * Get the value of this StringResource. + * @return the represented String. + */ + public synchronized String getValue() { + return getName(); + } + + /** + * Set the encoding to be used for this StringResource. + * @param s the encoding name. + */ + public synchronized void setEncoding(String s) { + encoding = s; + } + + /** + * Get the encoding used by this StringResource. + * @return the encoding name. + */ + public synchronized String getEncoding() { + return encoding; + } + + /** + * Get the size of this Resource. + * @return the size, as a long, 0 if the Resource does not exist (for + * compatibility with java.io.File), or UNKNOWN_SIZE if not known. + */ + public synchronized long getSize() { + return isReference() + ? ((Resource) getCheckedRef()).getSize() + : (long) getContent().length(); + } + + /** + * Get the hash code for this Resource. + * @return hash code as int. + */ + public synchronized int hashCode() { + if (isReference()) { + return getCheckedRef().hashCode(); + } + return super.hashCode() * STRING_MAGIC; + } + + /** + * Get an InputStream for the Resource. + * @return an InputStream containing this Resource's content. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if InputStreams are not + * supported for this Resource type. + */ + public synchronized InputStream getInputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getInputStream(); + } + //I can't get my head around this; is encoding treatment needed here? + return + //new oata.util.ReaderInputStream(new InputStreamReader( + new ByteArrayInputStream(getContent().getBytes()) + //, encoding), encoding) + ; + } + + /** + * Get an OutputStream for the Resource. + * @return an OutputStream to which content can be written. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if OutputStreams are not + * supported for this Resource type. + */ + public synchronized OutputStream getOutputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getOutputStream(); + } + if (getValue() != null) { + throw new ImmutableResourceException(); + } + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + return new FilterOutputStream(baos) { + public void close() throws IOException { + super.close(); + StringResource.this.setValue(encoding == null + ? baos.toString() : baos.toString(encoding)); + } + }; + } + + /** + * Overrides the super version. + * @param r the Reference to set. + */ + public void setRefid(Reference r) { + if (encoding != null) { + throw tooManyAttributes(); + } + super.setRefid(r); + } + + /** + * Get the content of this StringResource. + * @return a String; if the Project has been set properties + * replacement will be attempted. + */ + protected synchronized String getContent() { + if (isReference()) { + return ((StringResource) getCheckedRef()).getContent(); + } + String value = getValue(); + if (value == null) { + return value; + } + return getProject() == null + ? value : getProject().replaceProperties(value); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Touchable.java b/src/main/org/apache/tools/ant/types/resources/Touchable.java new file mode 100755 index 000000000..9960678e2 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Touchable.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * Interface to be implemented by "touchable" resources; i.e. those + * whose modification time can be altered. + * @since Ant 1.7 + */ +public interface Touchable { + void touch(long modTime); +} diff --git a/src/main/org/apache/tools/ant/types/resources/URLResource.java b/src/main/org/apache/tools/ant/types/resources/URLResource.java new file mode 100755 index 000000000..df8e4f2c7 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/URLResource.java @@ -0,0 +1,373 @@ +/* + * 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.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.MalformedURLException; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.util.FileUtils; + +/** + * Exposes a URL as a Resource. + * @since Ant 1.7 + */ +public class URLResource extends Resource { + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private static final int NULL_URL + = Resource.getMagicNumber("null URL".getBytes()); + + private URL url; + private String javaResource; + private URLConnection conn; + private Path classpath; + + /** + * Default constructor. + */ + public URLResource() { + } + + /** + * Convenience constructor. + * @param u the URL to expose. + */ + public URLResource(URL u) { + setURL(u); + } + + /** + * Convenience constructor. + * @param f the File to set as a URL. + */ + public URLResource(File f) { + setFile(f); + } + + /** + * String constructor for Ant attribute introspection. + * @param u String representation of this URL. + * @see org.apache.tools.ant.IntrospectionHelper + */ + public URLResource(String u) { + this(newURL(u)); + } + + /** + * Set the URL for this URLResource. + * @param u the URL to expose. + */ + public synchronized void setURL(URL u) { + checkAttributesAllowed(); + url = u; + } + + /** + * Set the URL from a File. + * @param f the File to set as a URL. + */ + public synchronized void setFile(File f) { + try { + setURL(FILE_UTILS.getFileURL(f)); + } catch (MalformedURLException e) { + throw new BuildException(e); + } + } + + /** + * Set the resource name with which to expose a Java resource. + * @param s the Java resource name. + * @see java.lang.ClassLoader#getResource() + */ + public synchronized void setJavaResource(String s) { + checkAttributesAllowed(); + javaResource = s; + } + + /** + * Set the classpath for this URLResource. + * @param p the Path against which to resolve Java resources. + */ + public synchronized void setClasspath(Path p) { + checkAttributesAllowed(); + addConfiguredClasspath(p); + } + + /** + * Create a nested classpath element. + * @return a Path object. + */ + public synchronized void addConfiguredClasspath(Path p) { + checkChildrenAllowed(); + if (classpath == null) { + classpath = new Path(getProject()); + } + classpath.add(p); + } + + /** + * Get the URL used by this URLResource. + * @return a URL object. + */ + public synchronized URL getURL() { + if (isReference()) { + return ((URLResource) getCheckedRef()).getURL(); + } + if (url == null && javaResource != null) { + ClassLoader cl = null; + AntClassLoader acl = null; + if (classpath != null) { + acl = getProject().createClassLoader(classpath); + cl = acl; + } else { + cl = getClass().getClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + } + if (cl != null) { + setURL(cl.getResource(javaResource)); + if (acl != null) { + acl.cleanup(); + } + } + } + return url; + } + + /** + * Overrides the super version. + * @param r the Reference to set. + */ + public synchronized void setRefid(Reference r) { + //not using the accessor in this case to avoid side effects + if (url != null || javaResource != null) { + throw tooManyAttributes(); + } + super.setRefid(r); + } + + /** + * Get the name of this URLResource + * (its file component minus the leading separator). + * @return the name of this resource. + */ + public synchronized String getName() { + return isReference() ? ((Resource) getCheckedRef()).getName() + : getURL().getFile().substring(1); + } + + /** + * Return this URLResource formatted as a String. + * @return a String representation of this URLResource. + */ + public synchronized String toString() { + return isReference() + ? getCheckedRef().toString() : String.valueOf(getURL()); + } + + /** + * Find out whether the URL exists . + * @return true if this resource exists. + */ + public synchronized boolean isExists() { + if (isReference()) { + return ((Resource) getCheckedRef()).isExists(); + } + if (getURL() == null) { + return false; + } + try { + connect(); + return true; + } catch (IOException e) { + return false; + } + } + + /** + * Tells the modification time in milliseconds since 01.01.1970 . + * + * @return 0 if the resource does not exist to mirror the behavior + * of {@link java.io.File File}. + */ + public synchronized long getLastModified() { + if (isReference()) { + return ((Resource) getCheckedRef()).getLastModified(); + } + if (!isExists()) { + return 0L; + } + try { + connect(); + return conn.getLastModified(); + } catch (IOException e) { + return 0L; + } + } + + /** + * Tells if the resource is a directory. + * @return boolean whether the resource is a directory. + */ + public synchronized boolean isDirectory() { + return isReference() + ? ((Resource) getCheckedRef()).isDirectory() + : getName().endsWith("/"); + } + + /** + * Get the size of this Resource. + * @return the size, as a long, 0 if the Resource does not exist (for + * compatibility with java.io.File), or UNKNOWN_SIZE if not known. + */ + public synchronized long getSize() { + if (isReference()) { + return ((Resource) getCheckedRef()).getSize(); + } + if (!isExists()) { + return 0L; + } + try { + connect(); + return conn.getContentLength(); + } catch (IOException e) { + return UNKNOWN_SIZE; + } + } + + /** + * Test whether an Object equals this URLResource. + * @param another the other Object to compare. + * @return true if the specified Object is equal to this Resource. + */ + public synchronized boolean equals(Object another) { + if (this == another) { + return true; + } + if (isReference()) { + return getCheckedRef().equals(another); + } + if (!(another.getClass().equals(getClass()))) { + return false; + } + URLResource otheru = (URLResource) another; + return getURL() == null + ? otheru.getURL() == null + : getURL().equals(otheru.getURL()); + } + + /** + * Get the hash code for this Resource. + * @return hash code as int. + */ + public synchronized int hashCode() { + if (isReference()) { + return getCheckedRef().hashCode(); + } + return MAGIC * ((getURL() == null) ? NULL_URL : getURL().hashCode()); + } + + /** + * Get an InputStream for the Resource. + * @return an InputStream containing this Resource's content. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if InputStreams are not + * supported for this Resource type. + */ + public synchronized InputStream getInputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getInputStream(); + } + connect(); + try { + return conn.getInputStream(); + } finally { + conn = null; + } + } + + /** + * Get an OutputStream for the Resource. + * @return an OutputStream to which content can be written. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if OutputStreams are not + * supported for this Resource type. + */ + public synchronized OutputStream getOutputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getOutputStream(); + } + connect(); + try { + return conn.getOutputStream(); + } finally { + conn = null; + } + } + + /** + * Ensure that we have a connection. + */ + protected synchronized void connect() throws IOException { + URL u = getURL(); + if (u == null) { + throw new BuildException("URL not set"); + } + if (conn == null) { + try { + conn = u.openConnection(); + conn.connect(); + } catch (IOException e) { + log(e.toString(), Project.MSG_ERR); + conn = null; + throw e; + } + } + } + + /** + * Finalize this URLResource. + * @throws Throwable on error. + */ + protected void finalize() throws Throwable { + conn = null; + super.finalize(); + } + + private static URL newURL(String u) { + try { + return new URL(u); + } catch (MalformedURLException e) { + throw new BuildException(e); + } + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/Union.java b/src/main/org/apache/tools/ant/types/resources/Union.java new file mode 100755 index 000000000..11c3a6703 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/Union.java @@ -0,0 +1,85 @@ +/* + * 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.types.ResourceCollection; + +/** + * ResourceCollection representing the union of multiple nested ResourceCollections. + * @since Ant 1.7 + */ +public class Union extends BaseResourceCollectionContainer { + + /** + * Returns all Resources in String format. Moved up from + * Path for convenience. + * @return String array of Resources. + */ + public String[] list() { + if (isReference()) { + return ((Union) getCheckedRef()).list(); + } + Collection result = getCollection(true); + return (String[]) (result.toArray(new String[result.size()])); + } + + /** + * Unify the contained Resources. + * @return a Collection of Resources. + */ + protected Collection getCollection() { + return getCollection(false); + } + + /** + * Unify the contained Resources. + * @param asString indicates whether the resulting Collection + * should contain Strings instead of Resources. + * @return a Collection of Resources. + */ + protected Collection getCollection(boolean asString) { + List rc = getResourceCollections(); + if (rc.isEmpty()) { + return Collections.EMPTY_LIST; + } + //preserve order-encountered using a list; enforce set logic manually: + ArrayList union = new ArrayList(rc.size() * 2); + for (Iterator rcIter = rc.iterator(); rcIter.hasNext();) { + for (Iterator r = nextRC(rcIter).iterator(); r.hasNext();) { + Object o = r.next(); + if (asString) { + o = o.toString(); + } + if (!(union.contains(o))) { + union.add(o); + } + } + } + return union; + } + + private static ResourceCollection nextRC(Iterator i) { + return (ResourceCollection) i.next(); + } +} + diff --git a/src/main/org/apache/tools/ant/types/resources/ZipResource.java b/src/main/org/apache/tools/ant/types/resources/ZipResource.java new file mode 100755 index 000000000..debbe76dc --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/ZipResource.java @@ -0,0 +1,299 @@ +/* + * 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.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.FilterInputStream; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.zip.ZipFile; +import org.apache.tools.zip.ZipEntry; + +/** + * A Resource representation of an entry in a zipfile. + * @since Ant 1.7 + */ +public class ZipResource extends Resource { + private static final int NULL_ZIPFILE + = Resource.getMagicNumber("null zipfile".getBytes()); + + private String encoding; + private File zipfile; + private boolean haveEntry = false; + + /** + * Default constructor. + */ + public ZipResource() { + } + + /** + * Construct a ZipResource representing the specified + * entry in the specified zipfile. + * @param z the zipfile as File. + * @param enc the encoding used for filenames. + * @param e the ZipEntry. + */ + public ZipResource(File z, String enc, ZipEntry e) { + setEntry(e); + setZipfile(z); + setEncoding(enc); + } + + /** + * Set the zipfile that holds this ZipResource. + * @param z the zipfile as a File. + */ + public void setZipfile(File z) { + checkAttributesAllowed(); + zipfile = z; + } + + /** + * Get the zipfile that holds this ZipResource. + * @return the zipfile as a File. + */ + public File getZipfile() { + return isReference() + ? ((ZipResource) getCheckedRef()).getZipfile() : zipfile; + } + + /** + * Set the encoding to use with the zipfile. + * @param enc the String encoding. + */ + public void setEncoding(String enc) { + checkAttributesAllowed(); + encoding = enc; + } + + /** + * Get the encoding to use with the zipfile. + * @return String encoding. + */ + public String getEncoding() { + return isReference() + ? ((ZipResource) getCheckedRef()).getEncoding() : encoding; + } + + /** + * Get the last modified date of this ZipResource. + * @return the last modification date. + */ + public long getLastModified() { + if (isReference()) { + return ((Resource) getCheckedRef()).getLastModified(); + } + checkEntry(); + return super.getLastModified(); + } + + /** + * Get the size of this ZipResource. + * @return the long size of this ZipResource. + */ + public long getSize() { + if (isReference()) { + return ((Resource) getCheckedRef()).getSize(); + } + checkEntry(); + return super.getSize(); + } + + /** + * Learn whether this ZipResource represents a directory. + * @return boolean flag indicating whether the zip entry is a directory. + */ + public boolean isDirectory() { + if (isReference()) { + return ((Resource) getCheckedRef()).isDirectory(); + } + checkEntry(); + return super.isDirectory(); + } + + /** + * Find out whether this ZipResource represents an existing Resource. + * @return boolean existence flag. + */ + public boolean isExists() { + if (isReference()) { + return ((Resource) getCheckedRef()).isExists(); + } + checkEntry(); + return super.isExists(); + } + + /** + * Overrides the super version. + * @param r the Reference to set. + */ + public void setRefid(Reference r) { + if (encoding != null || zipfile != null) { + throw tooManyAttributes(); + } + super.setRefid(r); + } + + /** + * Return an InputStream for reading the contents of this Resource. + * @return an InputStream object. + * @throws IOException if the zip file cannot be opened, + * or the entry cannot be read. + */ + public InputStream getInputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getInputStream(); + } + final ZipFile z = new ZipFile(getZipfile(), getEncoding()); + return new FilterInputStream(z.getInputStream(z.getEntry(getName()))) { + public void close() throws IOException { + FileUtils.close(in); + z.close(); + } + protected void finalize() throws Throwable { + try { + close(); + } finally { + super.finalize(); + } + } + }; + } + + /** + * Get an OutputStream for the Resource. + * @return an OutputStream to which content can be written. + * @throws IOException if unable to provide the content of this + * Resource as a stream. + * @throws UnsupportedOperationException if OutputStreams are not + * supported for this Resource type. + */ + public OutputStream getOutputStream() throws IOException { + if (isReference()) { + return ((Resource) getCheckedRef()).getOutputStream(); + } + throw new UnsupportedOperationException( + "Use the zip task for zip output."); + } + + /** + * Compare this ZipResource to another Resource. + * @param another the other Resource against which to compare. + * @return a negative integer, zero, or a positive integer as this ZipResource + * is less than, equal to, or greater than the specified Resource. + */ + public int compareTo(Object another) { + return this.equals(another) ? 0 : super.compareTo(another); + } + + /** + * Compare another Object to this ZipResource for equality. + * @param another the other Object to compare. + * @return true if another is a ZipResource representing + * the same entry in the same zipfile. + */ + public boolean equals(Object another) { + if (this == another) { + return true; + } + if (isReference()) { + return getCheckedRef().equals(another); + } + if (!(another.getClass().equals(getClass()))) { + return false; + } + ZipResource r = (ZipResource) another; + return getZipfile().equals(r.getZipfile()) + && getName().equals(r.getName()); + } + + /** + * Get the hash code for this Resource. + * @return hash code as int. + */ + public int hashCode() { + return super.hashCode() + * (getZipfile() == null ? NULL_ZIPFILE : getZipfile().hashCode()); + } + + /** + * Format this ZipResource as a String. + * @return String representatation of this ZipResource. + */ + public String toString() { + return isReference() ? getCheckedRef().toString() + : getZipfile().toString() + ':' + getName(); + } + + private synchronized void checkEntry() throws BuildException { + if (haveEntry) { + return; + } + String name = getName(); + if (name == null) { + throw new BuildException("zip entry name not set"); + } + File f = getZipfile(); + if (f == null) { + throw new BuildException("zipfile attribute not set"); + } + if (!f.exists()) { + throw new BuildException(f.getAbsolutePath() + " does not exist."); + } + if (f.isDirectory()) { + throw new BuildException(f + " denotes a directory."); + } + ZipFile z = null; + try { + z = new ZipFile(f, getEncoding()); + setEntry(z.getEntry(name)); + } catch (IOException e) { + log(e.getMessage(), Project.MSG_DEBUG); + throw new BuildException(e); + } finally { + if (z != null) { + try { + z.close(); + } catch (IOException e) { + //? + } + } + } + } + + private synchronized void setEntry(ZipEntry e) { + haveEntry = true; + if (e == null) { + super.setExists(false); + return; + } + super.setName(e.getName()); + super.setExists(true); + super.setLastModified(e.getTime()); + super.setDirectory(e.isDirectory()); + super.setSize(e.getSize()); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Content.java b/src/main/org/apache/tools/ant/types/resources/comparators/Content.java new file mode 100755 index 000000000..d212cf037 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Content.java @@ -0,0 +1,69 @@ +/* + * 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.comparators; + +import java.io.IOException; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.util.FileUtils; + +/** + * Compares Resources by content. + * @since Ant 1.7 + */ +public class Content extends ResourceComparator { + + private boolean binary = true; + + /** + * Set binary mode for this Content ResourceComparator. If this + * attribute is set to false, Resource content will be compared + * ignoring platform line-ending conventions. + * Default is true. + * @param b whether to compare content in binary mode. + */ + public void setBinary(boolean b) { + binary = b; + } + + /** + * Learn whether this Content ResourceComparator is operating in binary mode. + * @return boolean binary flag. + */ + public boolean isBinary() { + return binary; + } + + /** + * Compare two Resources by content. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + * @throws BuildException if I/O errors occur. + * @see org.apache.tools.ant.util.FileUtils#compareContent(Resource, Resource, boolean). + */ + protected int resourceCompare(Resource foo, Resource bar) { + try { + return FileUtils.getFileUtils().compareContent(foo, bar, !binary); + } catch (IOException e) { + throw new BuildException(e); + } + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Date.java b/src/main/org/apache/tools/ant/types/resources/comparators/Date.java new file mode 100755 index 000000000..e8aee0486 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Date.java @@ -0,0 +1,37 @@ +/* + * 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.comparators; + +import org.apache.tools.ant.types.Resource; + +/** + * Compares Resources by last modification date. + * @since Ant 1.7 + */ +public class Date extends ResourceComparator { + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + protected int resourceCompare(Resource foo, Resource bar) { + return (int) (foo.getLastModified() - bar.getLastModified()); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Exists.java b/src/main/org/apache/tools/ant/types/resources/comparators/Exists.java new file mode 100755 index 000000000..1930a334d --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Exists.java @@ -0,0 +1,42 @@ +/* + * 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.comparators; + +import org.apache.tools.ant.types.Resource; + +/** + * Compares Resources by existence. Not existing is "less than" existing. + * @since Ant 1.7 + */ +public class Exists extends ResourceComparator { + + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + protected int resourceCompare(Resource foo, Resource bar) { + boolean f = foo.isExists(); + if (f == bar.isExists()) { + return 0; + } + return f ? 1 : -1; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Name.java b/src/main/org/apache/tools/ant/types/resources/comparators/Name.java new file mode 100755 index 000000000..d7e5ec787 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Name.java @@ -0,0 +1,37 @@ +/* + * 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.comparators; + +import org.apache.tools.ant.types.Resource; + +/** + * Compares Resources by name. + * @since Ant 1.7 + */ +public class Name extends ResourceComparator { + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + protected int resourceCompare(Resource foo, Resource bar) { + return foo.getName().compareTo(bar.getName()); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/ResourceComparator.java b/src/main/org/apache/tools/ant/types/resources/comparators/ResourceComparator.java new file mode 100755 index 000000000..6f7b4bf66 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/ResourceComparator.java @@ -0,0 +1,62 @@ +/* + * 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.comparators; + +import java.util.Comparator; + +import org.apache.tools.ant.types.Resource; + +/** + * Abstract Resource Comparator. + * @since Ant 1.7 + */ +public abstract class ResourceComparator implements Comparator { + + /** + * Compare two objects. + * @param foo the first Object. + * @param bar the second Object. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + * @throws ClassCastException if either argument is null. + */ + public final int compare(Object foo, Object bar) { + return resourceCompare((Resource) foo, (Resource) bar); + } + + /** + * Test for equality with this ResourceComparator. + * @param o the Object to compare against. + * @return true if the specified Object equals this one. + */ + public final boolean equals(Object o) { + if (o == null) { + return false; + } + return o == this || o.getClass().equals(getClass()); + } + + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + protected abstract int resourceCompare(Resource foo, Resource bar); + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Reverse.java b/src/main/org/apache/tools/ant/types/resources/comparators/Reverse.java new file mode 100755 index 000000000..1ff90af4f --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Reverse.java @@ -0,0 +1,56 @@ +/* + * 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.comparators; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; + +/** + * Reverses another ResourceComparator. If no nested ResourceComparator + * is supplied, the compared Resources' natural order will be reversed. + * @since Ant 1.7 + */ +public class Reverse extends ResourceComparator { + private static final String ONE_NESTED + = "You must not nest more than one ResourceComparator for reversal."; + + private ResourceComparator nested; + + /** + * Add the ResourceComparator to reverse. + * @param nested the ResourceComparator to add. + */ + public void add(ResourceComparator c) { + if (nested != null) { + throw new BuildException(ONE_NESTED); + } + nested = c; + } + + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is greater than, equal to, or less than the second. + */ + protected int resourceCompare(Resource foo, Resource bar) { + return -1 * (nested == null + ? foo.compareTo(bar) : nested.compare(foo, bar)); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Size.java b/src/main/org/apache/tools/ant/types/resources/comparators/Size.java new file mode 100755 index 000000000..faf13e28f --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Size.java @@ -0,0 +1,37 @@ +/* + * 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.comparators; + +import org.apache.tools.ant.types.Resource; + +/** + * Compares Resources by size. + * @since Ant 1.7 + */ +public class Size extends ResourceComparator { + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + protected int resourceCompare(Resource foo, Resource bar) { + return (int) (foo.getSize() - bar.getSize()); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/comparators/Type.java b/src/main/org/apache/tools/ant/types/resources/comparators/Type.java new file mode 100755 index 000000000..5a400cd00 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/comparators/Type.java @@ -0,0 +1,43 @@ +/* + * 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.comparators; + +import org.apache.tools.ant.types.Resource; + +/** + * Compares Resources by is-directory status. As a container + * of files, a directory is deemed "greater" than a file. + * @since Ant 1.7 + */ +public class Type extends ResourceComparator { + + /** + * Compare two Resources. + * @param foo the first Resource. + * @param bar the second Resource. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + */ + protected int resourceCompare(Resource foo, Resource bar) { + boolean f = foo.isDirectory(); + if (f == bar.isDirectory()) { + return 0; + } + return f ? 1 : -1; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/And.java b/src/main/org/apache/tools/ant/types/resources/selectors/And.java new file mode 100755 index 000000000..d91aadb70 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/And.java @@ -0,0 +1,43 @@ +/* + * 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.selectors; + +import java.util.Iterator; + +import org.apache.tools.ant.types.Resource; + +/** + * And ResourceSelector. + * @since Ant 1.7 + */ +public class And extends ResourceSelectorContainer implements ResourceSelector { + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + for (Iterator i = getSelectors(); i.hasNext();) { + if (!((ResourceSelector) i.next()).isSelected(r)) { + return false; + } + } + return true; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Date.java b/src/main/org/apache/tools/ant/types/resources/selectors/Date.java new file mode 100755 index 000000000..2ecb13276 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Date.java @@ -0,0 +1,161 @@ +/* + * 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.selectors; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.text.ParseException; +import java.util.Locale; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.TimeComparison; +import org.apache.tools.ant.util.FileUtils; + +/** + * Date ResourceSelector. Based on the date FileSelector, with the most + * notable difference being the lack of support for the includedirs attribute. + * It is recommended that the effect of includeDirs = "false" be achieved for + * resources by enclosing a "dir" Type ResourceSelector and a Date + * ResourceSelector in an Or ResourceSelector. + * @since Ant 1.7 + */ +public class Date implements ResourceSelector { + private static final String MILLIS_OR_DATETIME + = "Either the millis or the datetime attribute must be set."; + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + private Long millis = null; + private String dateTime = null; + private String pattern = null; + private TimeComparison when = TimeComparison.EQUAL; + private long granularity = FILE_UTILS.getFileTimestampGranularity(); + + /** + * Set the date/time in milliseconds since 1970. + * @param m the number of millis. + */ + public synchronized void setMillis(long m) { + millis = new Long(m); + } + + /** + * Get the date/time in ms. + * @return long number of millis since 1970. + */ + public synchronized long getMillis() { + return millis == null ? -1L : millis.longValue(); + } + + /** + * Set the date and time as a String. + * @param s the date & time to use. + */ + public synchronized void setDateTime(String s) { + dateTime = s; + millis = null; + } + + /** + * Get the date & time in String format. + * @return a String representing a date & time. + */ + public synchronized String getDatetime() { + return dateTime; + } + + /** + * Set the granularity to use for this ResourceSelector. + * @param g the timestamp granularity. + */ + public synchronized void setGranularity(long g) { + granularity = g; + } + + /** + * Get the timestamp granularity used by this ResourceSelector. + * @return the long granularity. + */ + public synchronized long getGranularity() { + return granularity; + } + + /** + * Set the optional pattern to use with the datetime attribute. + * @param p the SimpleDateFormat-compatible pattern string. + */ + public synchronized void setPattern(String p) { + pattern = p; + } + + /** + * Get the pattern for use with the datetime attribute. + * @return a SimpleDateFormat-compatible pattern string. + */ + public synchronized String getPattern() { + return pattern; + } + + /** + * Set the comparison mode. + * @param c a TimeComparison object. + */ + public synchronized void setWhen(TimeComparison c) { + when = c; + } + + /** + * Get the comparison mode. + * @return a TimeComparison object. + */ + public synchronized TimeComparison getWhen() { + return when; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public synchronized boolean isSelected(Resource r) { + if (dateTime == null && millis == null) { + throw new BuildException(MILLIS_OR_DATETIME); + } + if (millis == null) { + DateFormat df = ((pattern == null) + ? DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.SHORT, Locale.US) + : new SimpleDateFormat(pattern)); + try { + long m = df.parse(dateTime).getTime(); + if (m < 0) { + throw new BuildException("Date of " + dateTime + + " results in negative milliseconds value" + + " relative to epoch (January 1, 1970, 00:00:00 GMT)."); + } + setMillis(m); + } catch (ParseException pe) { + throw new BuildException("Date of " + dateTime + + " Cannot be parsed correctly. It should be in" + + (pattern == null + ? " MM/DD/YYYY HH:MM AM_PM" : pattern) + " format."); + } + } + return when.evaluate(r.getLastModified(), millis.longValue(), granularity); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Exists.java b/src/main/org/apache/tools/ant/types/resources/selectors/Exists.java new file mode 100755 index 000000000..1bf01a0e1 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Exists.java @@ -0,0 +1,36 @@ +/* + * 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.selectors; + +import org.apache.tools.ant.types.Resource; + +/** + * Exists ResourceSelector. + * @since Ant 1.7 + */ +public class Exists implements ResourceSelector { + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + return r.isExists(); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/InstanceOf.java b/src/main/org/apache/tools/ant/types/resources/selectors/InstanceOf.java new file mode 100755 index 000000000..9c4bb9f40 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/InstanceOf.java @@ -0,0 +1,129 @@ +/* + * 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.selectors; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ComponentHelper; +import org.apache.tools.ant.AntTypeDefinition; +import org.apache.tools.ant.types.Resource; + +/** + * InstanceOf ResourceSelector. + * @since Ant 1.7 + */ +public class InstanceOf implements ResourceSelector { + private static final String ONE_ONLY = "Exactly one of class|type must be set."; + + private Project project; + private Class clazz; + private String type; + private String uri; + + /** + * Set the Project instance for this InstanceOf selector. + * @param p the Project instance used for type comparisons. + */ + public void setProject(Project p) { + project = p; + } + + /** + * Set the class to compare against. + * @param c the class. + */ + public void setClass(Class c) { + if (clazz != null) { + throw new BuildException("The class attribute has already been set."); + } + clazz = c; + } + + /** + * Set the Ant type to compare against. + * @param s the type name. + */ + public void setType(String s) { + type = s; + } + + /** + * Set the URI in which the Ant type, if specified, should be defined. + * @param u the URI. + */ + public void setURI(String u) { + uri = u; + } + + /** + * Get the comparison class. + * @return the Class object. + */ + public Class getCheckClass() { + return clazz; + } + + /** + * Get the comparison type. + * @return the String typename. + */ + public String getType() { + return type; + } + + /** + * Get the type's URI. + * @return the String URI. + */ + public String getURI() { + return uri; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + * @throws BuildException if an error occurs. + */ + public boolean isSelected(Resource r) { + if ((clazz == null) == (type == null)) { + throw new BuildException(ONE_ONLY); + } + Class c = clazz; + if (type != null) { + if (project == null) { + throw new BuildException( + "No project set for InstanceOf ResourceSelector; " + + "the type attribute is invalid."); + } + AntTypeDefinition d = ComponentHelper.getComponentHelper( + project).getDefinition(ProjectHelper.genComponentName(uri, type)); + if (d == null) { + throw new BuildException("type " + type + " not found."); + } + try { + c = d.innerGetTypeClass(); + } catch (ClassNotFoundException e) { + throw new BuildException(e); + } + } + return c.isAssignableFrom(r.getClass()); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Majority.java b/src/main/org/apache/tools/ant/types/resources/selectors/Majority.java new file mode 100755 index 000000000..99846158b --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Majority.java @@ -0,0 +1,69 @@ +/* + * 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.selectors; + +import java.util.Iterator; + +import org.apache.tools.ant.types.Resource; + +/** + * Majority ResourceSelector. + * @since Ant 1.7 + */ +public class Majority + extends ResourceSelectorContainer implements ResourceSelector { + + private boolean tie = true; + + /** + * Set whether ties are allowed. + * @param b whether a tie is a pass. + */ + public synchronized void setAllowtie(boolean b) { + tie = b; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public synchronized boolean isSelected(Resource r) { + int passed = 0; + int failed = 0; + int count = selectorCount(); + boolean even = count % 2 == 0; + int threshold = count / 2; + + for (Iterator i = getSelectors(); i.hasNext();) { + if (((ResourceSelector) i.next()).isSelected(r)) { + ++passed; + if (passed > threshold || (even && tie && passed == threshold)) { + return true; + } + } else { + ++failed; + if (failed > threshold || (even && !tie && failed == threshold)) { + return false; + } + } + } + //dummy + return false; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Name.java b/src/main/org/apache/tools/ant/types/resources/selectors/Name.java new file mode 100755 index 000000000..b0ac0e7f8 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Name.java @@ -0,0 +1,76 @@ +/* + * 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.selectors; + +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.selectors.SelectorUtils; + +/** + * Name ResourceSelector. + * @since Ant 1.7 + */ +public class Name implements ResourceSelector { + private String pattern; + private boolean cs = true; + + /** + * Set the pattern to compare names against. + * @param n the pattern String to set. + */ + public void setName(String n) { + pattern = n; + } + + /** + * Get the pattern used by this Name ResourceSelector. + * @return the String selection pattern. + */ + public String getName() { + return pattern; + } + + /** + * Set whether the name comparisons are case-sensitive. + * @param b boolean case-sensitivity flag. + */ + public void setCaseSensitive(boolean b) { + cs = b; + } + + /** + * Learn whether this Name ResourceSelector is case-sensitive. + * @return boolean case-sensitivity flag. + */ + public boolean isCaseSensitive() { + return cs; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + String n = r.getName(); + if (SelectorUtils.match(pattern, n, cs)) { + return true; + } + String s = r.toString(); + return s.equals(n) ? false : SelectorUtils.match(pattern, s, cs); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/None.java b/src/main/org/apache/tools/ant/types/resources/selectors/None.java new file mode 100755 index 000000000..e33144d5e --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/None.java @@ -0,0 +1,43 @@ +/* + * 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.selectors; + +import java.util.Iterator; + +import org.apache.tools.ant.types.Resource; + +/** + * None ResourceSelector. + * @since Ant 1.7 + */ +public class None + extends ResourceSelectorContainer implements ResourceSelector { + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + boolean none = true; + for (Iterator i = getSelectors(); none && i.hasNext();) { + none = !((ResourceSelector) i.next()).isSelected(r); + } + return none; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Not.java b/src/main/org/apache/tools/ant/types/resources/selectors/Not.java new file mode 100755 index 000000000..fe74f8c5e --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Not.java @@ -0,0 +1,65 @@ +/* + * 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.selectors; + +import org.apache.tools.ant.types.Resource; + +/** + * Not ResourceSelector. + * @since Ant 1.7 + */ +public class Not implements ResourceSelector { + + private ResourceSelector sel; + + /** + * Default constructor. + */ + public Not() { + } + + /** + * Convenience constructor. + * @param s the ResourceSelector to negate. + */ + public Not(ResourceSelector s) { + add(s); + } + + /** + * Set the ResourceSelector. + * @param s the ResourceSelector to negate. + * @throws IllegalStateException if already set. + */ + public void add(ResourceSelector s) { + if (sel != null) { + throw new IllegalStateException( + "The Not ResourceSelector accepts a single nested ResourceSelector"); + } + sel = s; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + return !(sel.isSelected(r)); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Or.java b/src/main/org/apache/tools/ant/types/resources/selectors/Or.java new file mode 100755 index 000000000..9fafa1335 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Or.java @@ -0,0 +1,43 @@ +/* + * 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.selectors; + +import java.util.Iterator; + +import org.apache.tools.ant.types.Resource; + +/** + * Or ResourceSelector. + * @since Ant 1.7 + */ +public class Or extends ResourceSelectorContainer implements ResourceSelector { + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + for (Iterator i = getSelectors(); i.hasNext();) { + if (((ResourceSelector) i.next()).isSelected(r)) { + return true; + } + } + return false; + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelector.java b/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelector.java new file mode 100755 index 000000000..4a7387fbb --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelector.java @@ -0,0 +1,34 @@ +/* + * 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.selectors; + +import org.apache.tools.ant.types.Resource; + +/** + * Interface for a Resource selector. + * @since Ant 1.7 + */ +public interface ResourceSelector { + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r); + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelectorContainer.java b/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelectorContainer.java new file mode 100755 index 000000000..4a215ea9a --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelectorContainer.java @@ -0,0 +1,111 @@ +/* + * 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.selectors; + +import java.util.Stack; +import java.util.Vector; +import java.util.Iterator; +import java.util.Collections; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.DataType; + +/** + * ResourceSelector container. + * @since Ant 1.7 + */ +public class ResourceSelectorContainer extends DataType { + + private Vector v = new Vector(); + + /** + * Add a ResourceSelector to the container. + * @param s the ResourceSelector to add. + */ + public void add(ResourceSelector s) { + if (isReference()) { + throw noChildrenAllowed(); + } + if (s == null) { + return; + } + v.add(s); + setChecked(false); + } + + /** + * Learn whether this ResourceSelectorContainer has selectors. + * @return boolean indicating whether selectors have been added to the container. + */ + public boolean hasSelectors() { + if (isReference()) { + return ((ResourceSelectorContainer) getCheckedRef()).hasSelectors(); + } + dieOnCircularReference(); + return !v.isEmpty(); + } + + /** + * Get the count of nested selectors. + * @return the selector count as int. + */ + public int selectorCount() { + if (isReference()) { + return ((ResourceSelectorContainer) getCheckedRef()).selectorCount(); + } + dieOnCircularReference(); + return v.size(); + } + + /** + * Return an Iterator over the nested selectors. + * @return Iterator of ResourceSelectors. + */ + public Iterator getSelectors() { + if (isReference()) { + return ((ResourceSelectorContainer) getCheckedRef()).getSelectors(); + } + dieOnCircularReference(); + return Collections.unmodifiableList(v).iterator(); + } + + /** + * Overrides the version from DataType to recurse on nested ResourceSelectors. + * @param stk the Stack of references. + * @param p the Project to resolve against. + * @throws BuildException on error. + */ + public void dieOnCircularReference(Stack stk, Project p) { + if (isChecked()) { + return; + } + if (isReference()) { + super.dieOnCircularReference(stk, p); + } else { + for (Iterator i = v.iterator(); i.hasNext();) { + Object o = i.next(); + if (o instanceof DataType) { + stk.push(o); + invokeCircularReferenceCheck((DataType) o, stk, p); + } + } + setChecked(true); + } + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Size.java b/src/main/org/apache/tools/ant/types/resources/selectors/Size.java new file mode 100755 index 000000000..45bf31fa0 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Size.java @@ -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.selectors; + +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.Comparison; + +/** + * Size ResourceSelector. + * @since Ant 1.7 + */ +public class Size implements ResourceSelector { + private long size = -1; + private Comparison when = Comparison.EQUAL; + + /** + * Set the size to compare against. + * @param l the long resource size. + */ + public void setSize(long l) { + size = l; + } + + /** + * Get the size compared to by this Size ResourceSelector. + * @return the long resource size. + */ + public long getSize() { + return size; + } + + /** + * Set the comparison mode. + * @param c a Comparison object. + */ + public void setWhen(Comparison c) { + when = c; + } + + /** + * Get the comparison mode. + * @return a Comparison object. + */ + public Comparison getWhen() { + return when; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + long diff = r.getSize() - size; + return when.evaluate(diff == 0 ? 0 : (int) (diff / Math.abs(diff))); + } + +} diff --git a/src/main/org/apache/tools/ant/types/resources/selectors/Type.java b/src/main/org/apache/tools/ant/types/resources/selectors/Type.java new file mode 100755 index 000000000..faa5d3c03 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/selectors/Type.java @@ -0,0 +1,67 @@ +/* + * 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.selectors; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.EnumeratedAttribute; + +/** + * Type file/dir ResourceSelector. + * @since Ant 1.7 + */ +public class Type implements ResourceSelector { + + /** + * Implements the type attribute. + */ + public static class FileDir extends EnumeratedAttribute { + private static final String[] VALUES = new String[] {"file", "dir"}; + + /** + * Return the possible values. + * @return a String array. + */ + public String[] getValues() { + return VALUES; + } + } + + private FileDir type = null; + + /** + * Set type; file|dir. + * @param fd a FileDir object. + */ + public void setType(FileDir fd) { + type = fd; + } + + /** + * Return true if this Resource is selected. + * @param r the Resource to check. + * @return whether the Resource was selected. + */ + public boolean isSelected(Resource r) { + if (type == null) { + throw new BuildException("The type attribute is required."); + } + int i = type.getIndex(); + return r.isDirectory() ? i == 1 : i == 0; + } + +} diff --git a/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java b/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java new file mode 100755 index 000000000..7174d0620 --- /dev/null +++ b/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java @@ -0,0 +1,143 @@ +/* + * 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.util; + +import java.io.InputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.util.Iterator; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceCollection; + +/** + * Special InputStream that will + * concatenate the contents of Resources from a single ResourceCollection. + */ +public class ConcatResourceInputStream extends InputStream { + + private static final int EOF = -1; + private boolean eof = false; + private Iterator iter; + private InputStream currentStream; + private ProjectComponent managingPc; + private boolean ignoreErrors = false; + + /** + * Construct a new ConcatResourceInputStream + * for the specified ResourceCollection. + * @param rc the ResourceCollection to combine. + * @throws IOException if I/O errors occur. + */ + public ConcatResourceInputStream(ResourceCollection rc) throws IOException { + iter = rc.iterator(); + } + + /** + * Set whether this ConcatResourceInputStream ignores errors. + * @param b whether to ignore errors. + */ + public void setIgnoreErrors(boolean b) { + ignoreErrors = b; + } + + /** + * Find out whether this ConcatResourceInputStream ignores errors. + * @return boolean ignore-errors flag. + */ + public boolean isIgnoreErrors() { + return ignoreErrors; + } + + // inherit doc + public void close() throws IOException { + closeCurrent(); + eof = true; + } + + // inherit doc + public int read() throws IOException { + if (eof) { + return EOF; + } + int result = readCurrent(); + if (result == EOF) { + nextResource(); + result = readCurrent(); + } + return result; + } + + /** + * Set a managing ProjectComponent for + * this ConcatResourceInputStream. + * @param task the managing Task. + */ + public void setManagingComponent(ProjectComponent pc) { + this.managingPc = pc; + } + + /** + * Log a message with the specified logging level. + * @param message the String message. + * @param loglevel the int logging level. + */ + public void log(String message, int loglevel) { + if (managingPc != null) { + managingPc.log(message, loglevel); + } else { + if (loglevel > Project.MSG_WARN) { + System.out.println(message); + } else { + System.err.println(message); + } + } + } + + private int readCurrent() throws IOException { + return (eof || currentStream == null) ? EOF : currentStream.read(); + } + + private void nextResource() throws IOException { + closeCurrent(); + while (iter.hasNext()) { + Resource r = (Resource) iter.next(); + if (!r.isExists()) { + continue; + } + log("Concating " + r.toLongString(), Project.MSG_VERBOSE); + try { + currentStream = new BufferedInputStream(r.getInputStream()); + return; + } catch (IOException eyeOhEx) { + if (!ignoreErrors) { + log("Failed to get input stream for " + r, Project.MSG_ERR); + throw eyeOhEx; + } + } + } + eof = true; + } + + private void closeCurrent() { + FileUtils.close(currentStream); + currentStream = null; + } +} diff --git a/src/main/org/apache/tools/ant/util/FileUtils.java b/src/main/org/apache/tools/ant/util/FileUtils.java index a0952720a..d37cfe5b0 100644 --- a/src/main/org/apache/tools/ant/util/FileUtils.java +++ b/src/main/org/apache/tools/ant/util/FileUtils.java @@ -45,7 +45,10 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.filters.util.ChainReaderHelper; import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.FilterSetCollection; +import org.apache.tools.ant.types.resources.Touchable; +import org.apache.tools.ant.types.resources.FileResource; import org.apache.tools.ant.launch.Locator; /** @@ -521,139 +524,204 @@ public class FileUtils { String inputEncoding, String outputEncoding, Project project) throws IOException { + copyResource(new FileResource(sourceFile), new FileResource(destFile), + filters, filterChains, overwrite, preserveLastModified, + inputEncoding, outputEncoding, project); + } - if (overwrite || !destFile.exists() - || destFile.lastModified() < sourceFile.lastModified()) { + /** + * Convenience method to copy content from one Resource to another. + * No filtering is performed. + * + * @param source the Resource to copy from. + * Must not be null. + * @param dest the Resource to copy to. + * Must not be null. + * + * @throws IOException if the copying fails. + * + * @since Ant 1.7 + */ + public void copyResource(Resource source, Resource dest) throws IOException { + copyResource(source, dest, null); + } - if (destFile.exists() && destFile.isFile()) { - destFile.delete(); - } - // ensure that parent dir of dest file exists! - // not using getParentFile method to stay 1.1 compat - File parent = destFile.getParentFile(); - if (parent != null && !parent.exists()) { - parent.mkdirs(); + /** + * Convenience method to copy content from one Resource to another. + * No filtering is performed. + * + * @param source the Resource to copy from. + * Must not be null. + * @param dest the Resource to copy to. + * Must not be null. + * @param project the project instance. + * + * @throws IOException if the copying fails. + * + * @since Ant 1.7 + */ + public void copyResource(Resource source, Resource dest, Project project) + throws IOException { + copyResource(source, dest, null, null, false, + false, null, null, project); + } + + /** + * Convenience method to copy content from one Resource to another + * specifying whether token filtering must be used, whether filter chains + * must be used, whether newer destination files may be overwritten and + * whether the last modified time of dest file should be made + * equal to the last modified time of source. + * + * @param source the Resource to copy from. + * Must not be null. + * @param dest the Resource to copy to. + * Must not be null. + * @param filters the collection of filters to apply to this copy. + * @param filterChains filterChains to apply during the copy. + * @param overwrite Whether or not the destination Resource should be + * overwritten if it already exists. + * @param preserveLastModified Whether or not the last modified time of + * the destination Resource should be set to that + * of the source. + * @param inputEncoding the encoding used to read the files. + * @param outputEncoding the encoding used to write the files. + * @param project the project instance. + * + * @throws IOException if the copying fails. + * + * @since Ant 1.7 + */ + public void copyResource(Resource source, Resource dest, + FilterSetCollection filters, Vector filterChains, + boolean overwrite, boolean preserveLastModified, + String inputEncoding, String outputEncoding, + Project project) + throws IOException { + if (!overwrite) { + long slm = source.getLastModified(); + if (dest.isExists() && slm != 0 + && dest.getLastModified() > slm) { + return; } - final boolean filterSetsAvailable = (filters != null - && filters.hasFilters()); - final boolean filterChainsAvailable = (filterChains != null - && filterChains.size() > 0); - if (filterSetsAvailable) { - BufferedReader in = null; - BufferedWriter out = null; - try { - if (inputEncoding == null) { - in = new BufferedReader(new FileReader(sourceFile)); - } else { - InputStreamReader isr - = new InputStreamReader(new FileInputStream(sourceFile), - inputEncoding); - in = new BufferedReader(isr); - } - if (outputEncoding == null) { - out = new BufferedWriter(new FileWriter(destFile)); + } + final boolean filterSetsAvailable = (filters != null + && filters.hasFilters()); + final boolean filterChainsAvailable = (filterChains != null + && filterChains.size() > 0); + if (filterSetsAvailable) { + BufferedReader in = null; + BufferedWriter out = null; + try { + InputStreamReader isr = null; + if (inputEncoding == null) { + isr = new InputStreamReader(source.getInputStream()); + } else { + isr = new InputStreamReader(source.getInputStream(), + inputEncoding); + } + in = new BufferedReader(isr); + OutputStreamWriter osw = null; + if (outputEncoding == null) { + osw = new OutputStreamWriter(dest.getOutputStream()); + } else { + osw = new OutputStreamWriter(dest.getOutputStream(), + outputEncoding); + } + out = new BufferedWriter(osw); + if (filterChainsAvailable) { + ChainReaderHelper crh = new ChainReaderHelper(); + crh.setBufferSize(BUF_SIZE); + crh.setPrimaryReader(in); + crh.setFilterChains(filterChains); + crh.setProject(project); + Reader rdr = crh.getAssembledReader(); + in = new BufferedReader(rdr); + } + LineTokenizer lineTokenizer = new LineTokenizer(); + lineTokenizer.setIncludeDelims(true); + String newline = null; + String line = lineTokenizer.getToken(in); + while (line != null) { + if (line.length() == 0) { + // this should not happen, because the lines are + // returned with the end of line delimiter + out.newLine(); } else { - OutputStreamWriter osw - = new OutputStreamWriter(new FileOutputStream(destFile), - outputEncoding); - out = new BufferedWriter(osw); - } - if (filterChainsAvailable) { - ChainReaderHelper crh = new ChainReaderHelper(); - crh.setBufferSize(BUF_SIZE); - crh.setPrimaryReader(in); - crh.setFilterChains(filterChains); - crh.setProject(project); - Reader rdr = crh.getAssembledReader(); - in = new BufferedReader(rdr); - } - LineTokenizer lineTokenizer = new LineTokenizer(); - lineTokenizer.setIncludeDelims(true); - String newline = null; - String line = lineTokenizer.getToken(in); - while (line != null) { - if (line.length() == 0) { - // this should not happen, because the lines are - // returned with the end of line delimiter - out.newLine(); - } else { - newline = filters.replaceTokens(line); - out.write(newline); - } - line = lineTokenizer.getToken(in); + newline = filters.replaceTokens(line); + out.write(newline); } - } finally { - close(out); - close(in); + line = lineTokenizer.getToken(in); } - } else if (filterChainsAvailable - || (inputEncoding != null - && !inputEncoding.equals(outputEncoding)) - || (inputEncoding == null && outputEncoding != null)) { - BufferedReader in = null; - BufferedWriter out = null; - try { - if (inputEncoding == null) { - in = new BufferedReader(new FileReader(sourceFile)); - } else { - in = - new BufferedReader( - new InputStreamReader( - new FileInputStream(sourceFile), - inputEncoding)); - } - if (outputEncoding == null) { - out = new BufferedWriter(new FileWriter(destFile)); - } else { - out = - new BufferedWriter( - new OutputStreamWriter( - new FileOutputStream(destFile), - outputEncoding)); - } - if (filterChainsAvailable) { - ChainReaderHelper crh = new ChainReaderHelper(); - crh.setBufferSize(BUF_SIZE); - crh.setPrimaryReader(in); - crh.setFilterChains(filterChains); - crh.setProject(project); - Reader rdr = crh.getAssembledReader(); - in = new BufferedReader(rdr); - } - char[] buffer = new char[BUF_SIZE]; - while (true) { - int nRead = in.read(buffer, 0, buffer.length); - if (nRead == -1) { - break; - } - out.write(buffer, 0, nRead); - } - } finally { - close(out); - close(in); - } - } else { - FileInputStream in = null; - FileOutputStream out = null; - try { - in = new FileInputStream(sourceFile); - out = new FileOutputStream(destFile); - - byte[] buffer = new byte[BUF_SIZE]; - int count = 0; - do { - out.write(buffer, 0, count); - count = in.read(buffer, 0, buffer.length); - } while (count != -1); - } finally { - close(out); - close(in); + } finally { + close(out); + close(in); + } + } else if (filterChainsAvailable + || (inputEncoding != null + && !inputEncoding.equals(outputEncoding)) + || (inputEncoding == null && outputEncoding != null)) { + BufferedReader in = null; + BufferedWriter out = null; + try { + InputStreamReader isr = null; + if (inputEncoding == null) { + isr = new InputStreamReader(source.getInputStream()); + } else { + isr = new InputStreamReader(source.getInputStream(), + inputEncoding); } + in = new BufferedReader(isr); + OutputStreamWriter osw = null; + if (outputEncoding == null) { + osw = new OutputStreamWriter(dest.getOutputStream()); + } else { + osw = new OutputStreamWriter(dest.getOutputStream(), + outputEncoding); + } + out = new BufferedWriter(osw); + if (filterChainsAvailable) { + ChainReaderHelper crh = new ChainReaderHelper(); + crh.setBufferSize(BUF_SIZE); + crh.setPrimaryReader(in); + crh.setFilterChains(filterChains); + crh.setProject(project); + Reader rdr = crh.getAssembledReader(); + in = new BufferedReader(rdr); + } + char[] buffer = new char[BUF_SIZE]; + while (true) { + int nRead = in.read(buffer, 0, buffer.length); + if (nRead == -1) { + break; + } + out.write(buffer, 0, nRead); + } + } finally { + close(out); + close(in); } - if (preserveLastModified) { - setFileLastModified(destFile, sourceFile.lastModified()); + } else { + InputStream in = null; + OutputStream out = null; + try { + in = source.getInputStream(); + out = dest.getOutputStream(); + + byte[] buffer = new byte[BUF_SIZE]; + int count = 0; + do { + out.write(buffer, 0, count); + count = in.read(buffer, 0, buffer.length); + } while (count != -1); + } finally { + close(out); + close(in); } } + if (preserveLastModified && dest instanceof Touchable) { + setLastModified((Touchable) dest, source.getLastModified()); + } } /** @@ -665,7 +733,19 @@ public class FileUtils { * if this is -1, the current time is used. */ public void setFileLastModified(File file, long time) { - file.setLastModified((time < 0) ? System.currentTimeMillis() : time); + setLastModified(new FileResource(file), time); + } + + /** + * Set the last modified time of an object implementing + * org.apache.tools.ant.types.resources.Touchable . + * + * @param t the Touchable whose modified time is to be set. + * @param time the time to which the last modified time is to be set. + * if this is -1, the current time is used. + */ + public void setLastModified(Touchable t, long time) { + t.touch((time < 0) ? System.currentTimeMillis() : time); } /** @@ -987,62 +1067,108 @@ public class FileUtils { * @since Ant 1.6.3 */ public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException { - if (f1.exists() != f2.exists()) { + return contentEquals(new FileResource(f1), new FileResource(f2), textfile); + } + + /** + * Compares the contents of two Resources. + * + * @param r1 the Resource whose content is to be compared. + * @param r2 the other Resource whose content is to be compared. + * @param text true if the content is to be treated as text and + * differences in kind of line break are to be ignored. + * + * @return true if the content of the Resources is the same. + * + * @throws IOException if the Resources cannot be read. + * @since Ant 1.6.3 + */ + public boolean contentEquals(Resource r1, Resource r2, boolean text) throws IOException { + if (r1.isExists() != r2.isExists()) { return false; } - if (!f1.exists()) { + if (!r1.isExists()) { // two not existing files are equal return true; } - // should the following two be switched? If f1 and f2 refer to the same file, + // should the following two be switched? If r1 and r2 refer to the same file, // isn't their content equal regardless of whether that file is a directory? - if (f1.isDirectory() || f2.isDirectory()) { + if (r1.isDirectory() || r2.isDirectory()) { // don't want to compare directory contents for now return false; } - if (fileNameEquals(f1, f2)) { - // same filename => true + if (r1.equals(r2)) { return true; } - return textfile ? textEquals(f1, f2) : binaryEquals(f1, f2); + if (!text && r1.getSize() != r2.getSize()) { + return false; + } + return compareContent(r1, r2, text) == 0; } /** - * Binary compares the contents of two files. + * Compare the content of two Resources. A nonexistent Resource's + * content is "less than" that of an existing Resource; a directory-type + * Resource's content is "less than" that of a file-type Resource. + * @param r1 the Resource whose content is to be compared. + * @param r2 the other Resource whose content is to be compared. + * @param text true if the content is to be treated as text and + * differences in kind of line break are to be ignored. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + * @throws IOException if the Resources cannot be read. + */ + public int compareContent(Resource r1, Resource r2, boolean text) throws IOException { + if (r1.equals(r2)) { + return 0; + } + boolean e1 = r1.isExists(); + boolean e2 = r2.isExists(); + if (!(e1 || e2)) { + return 0; + } + if (e1 != e2) { + return e1 ? 1 : -1; + } + boolean d1 = r1.isDirectory(); + boolean d2 = r2.isDirectory(); + if (d1 && d2) { + return 0; + } + if (d1 || d2) { + return d1 ? -1 : 1; + } + return text ? textCompare(r1, r2) : binaryCompare(r1, r2); + } + + /** + * Binary compares the contents of two Resources. *

* simple but sub-optimal comparision algorithm. written for working * rather than fast. Better would be a block read into buffers followed * by long comparisions apart from the final 1-7 bytes. *

* - * @param f1 the file whose content is to be compared. - * @param f2 the other file whose content is to be compared. - * @return true if the content of the files is the same. - * @throws IOException if the files cannot be read. + * @param r1 the Resource whose content is to be compared. + * @param r2 the other Resource whose content is to be compared. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + * @throws IOException if the Resources cannot be read. */ - private boolean binaryEquals(File f1, File f2) throws IOException { - if (f1.length() != f2.length()) { - // different size =>false - return false; - } - + private int binaryCompare(Resource r1, Resource r2) throws IOException { InputStream in1 = null; InputStream in2 = null; try { - in1 = new BufferedInputStream(new FileInputStream(f1)); - in2 = new BufferedInputStream(new FileInputStream(f2)); + in1 = new BufferedInputStream(r1.getInputStream()); + in2 = new BufferedInputStream(r2.getInputStream()); - int expectedByte = in1.read(); - while (expectedByte != -1) { - if (expectedByte != in2.read()) { - return false; + for (int b1 = in1.read(); b1 != -1; b1 = in1.read()) { + int b2 = in2.read(); + if (b1 != b2) { + return b1 > b2 ? 1 : -1; } - expectedByte = in1.read(); } - if (in2.read() != -1) { - return false; - } - return true; + return in2.read() == -1 ? 0 : -1; } finally { close(in1); close(in2); @@ -1050,33 +1176,30 @@ public class FileUtils { } /** - * Text compares the contents of two files. - * + * Text compares the contents of two Resources. * Ignores different kinds of line endings. - * - * @param f1 the file whose content is to be compared. - * @param f2 the other file whose content is to be compared. - * @return true if the content of the files is the same. - * @throws IOException if the files cannot be read. + * @param r1 the Resource whose content is to be compared. + * @param r2 the other Resource whose content is to be compared. + * @return a negative integer, zero, or a positive integer as the first + * argument is less than, equal to, or greater than the second. + * @throws IOException if the Resources cannot be read. */ - private boolean textEquals(File f1, File f2) throws IOException { + private int textCompare(Resource r1, Resource r2) throws IOException { BufferedReader in1 = null; BufferedReader in2 = null; try { - in1 = new BufferedReader(new FileReader(f1)); - in2 = new BufferedReader(new FileReader(f2)); + in1 = new BufferedReader(new InputStreamReader(r1.getInputStream())); + in2 = new BufferedReader(new InputStreamReader(r2.getInputStream())); String expected = in1.readLine(); while (expected != null) { - if (!expected.equals(in2.readLine())) { - return false; + String actual = in2.readLine(); + if (!expected.equals(actual)) { + return expected.compareTo(actual); } expected = in1.readLine(); } - if (in2.readLine() != null) { - return false; - } - return true; + return in2.readLine() == null ? 0 : -1; } finally { close(in1); close(in2); @@ -1384,7 +1507,6 @@ public class FileUtils { return isUpToDate(sourceTime, destTime, granularity); } - /** * Returns true if the source is older than the dest. * @param source source file (should be the older). diff --git a/src/main/org/apache/tools/ant/util/PropertyOutputStream.java b/src/main/org/apache/tools/ant/util/PropertyOutputStream.java new file mode 100755 index 000000000..5aa49e1dd --- /dev/null +++ b/src/main/org/apache/tools/ant/util/PropertyOutputStream.java @@ -0,0 +1,69 @@ +/* + * 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.util; + +import java.io.IOException; +import java.io.ByteArrayOutputStream; + +import org.apache.tools.ant.Project; + +/** + * Exception thrown when an attempt is made to get an OutputStream + * from an immutable Resource. + * @since Ant 1.7 + */ +public class PropertyOutputStream extends ByteArrayOutputStream { + private Project project; + private String property; + private boolean trim; + + /** + * Construct a new PropertyOutputStream for the specified Project + * and property name, trimming the property value. + * @param p the associated Ant Project. + * @param s the String property name. + */ + public PropertyOutputStream(Project p, String s) { + this(p, s, true); + } + + /** + * Construct a new PropertyOutputStream for + * the specified Project, property name, and trim mode. + * @param p the associated Ant Project. + * @param s the String property name. + * @param b the boolean trim mode. + */ + public PropertyOutputStream(Project p, String s, boolean b) { + project = p; + property = s; + trim = b; + } + + /** + * Close the PropertyOutputStream, storing the property. + */ + public void close() { + if (project != null && property != null) { + String s = new String(toByteArray()); + project.setNewProperty(property, trim ? s.trim() : s); + } + } + +} + diff --git a/src/main/org/apache/tools/zip/ZipFile.java b/src/main/org/apache/tools/zip/ZipFile.java index cf3638a54..5605dfc19 100644 --- a/src/main/org/apache/tools/zip/ZipFile.java +++ b/src/main/org/apache/tools/zip/ZipFile.java @@ -370,27 +370,29 @@ public class ZipFile { */ private void positionAtCentralDirectory() throws IOException { - long off = archive.length() - MIN_EOCD_SIZE; - archive.seek(off); - byte[] sig = ZipOutputStream.EOCD_SIG; - int curr = archive.read(); boolean found = false; - while (curr != -1) { - if (curr == sig[0]) { - curr = archive.read(); - if (curr == sig[1]) { + long off = archive.length() - MIN_EOCD_SIZE; + if (off >= 0) { + archive.seek(off); + byte[] sig = ZipOutputStream.EOCD_SIG; + int curr = archive.read(); + while (curr != -1) { + if (curr == sig[0]) { curr = archive.read(); - if (curr == sig[2]) { + if (curr == sig[1]) { curr = archive.read(); - if (curr == sig[3]) { - found = true; - break; + if (curr == sig[2]) { + curr = archive.read(); + if (curr == sig[3]) { + found = true; + break; + } } } } + archive.seek(--off); + curr = archive.read(); } - archive.seek(--off); - curr = archive.read(); } if (!found) { throw new ZipException("archive is not a ZIP archive"); diff --git a/src/resources/org/apache/tools/ant/types/resources/comparators/antlib.xml b/src/resources/org/apache/tools/ant/types/resources/comparators/antlib.xml new file mode 100755 index 000000000..be4ec8d7f --- /dev/null +++ b/src/resources/org/apache/tools/ant/types/resources/comparators/antlib.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/src/resources/org/apache/tools/ant/types/resources/selectors/antlib.xml b/src/resources/org/apache/tools/ant/types/resources/selectors/antlib.xml new file mode 100755 index 000000000..5c1654c11 --- /dev/null +++ b/src/resources/org/apache/tools/ant/types/resources/selectors/antlib.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + diff --git a/src/testcases/org/apache/tools/ant/taskdefs/ConcatTest.java b/src/testcases/org/apache/tools/ant/taskdefs/ConcatTest.java index 5d8b5a6e7..c74264c7e 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/ConcatTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/ConcatTest.java @@ -275,4 +275,9 @@ public class ConcatTest File f2 = getProject().resolveFile("concat.utf8"); assertTrue(FILE_UTILS.contentEquals(f1, f2)); } + + public void testResources() { + executeTarget("testResources"); + } + } diff --git a/src/testcases/org/apache/tools/ant/types/ResourceCollectionsTest.java b/src/testcases/org/apache/tools/ant/types/ResourceCollectionsTest.java new file mode 100755 index 000000000..96ff76d0e --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/ResourceCollectionsTest.java @@ -0,0 +1,136 @@ +/* + * 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; + +import org.apache.tools.ant.BuildFileTest; + +public class ResourceCollectionsTest extends BuildFileTest { + + public ResourceCollectionsTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/types/resources/build.xml"); + } + + public void tearDown() { + executeTarget("tearDown"); + } + + public void testdifference() { + executeTarget("testdifference"); + } + + public void testdirset() { + executeTarget("testdirset"); + } + + public void testfile() { + executeTarget("testfile"); + } + + public void testfilelist() { + executeTarget("testfilelist"); + } + + public void testfiles1() { + executeTarget("testfiles1"); + } + + public void testfiles2() { + executeTarget("testfiles2"); + } + + public void testfiles3() { + executeTarget("testfiles3"); + } + + public void testfileset() { + executeTarget("testfileset"); + } + + public void testfileurl() { + executeTarget("testfileurl"); + } + + public void testfileurlref() { + executeTarget("testfileurlref"); + } + + public void testhttpurl1() { + executeTarget("testhttpurl1"); + } + + public void testhttpurl2() { + executeTarget("testhttpurl2"); + } + + public void testintersect() { + executeTarget("testintersect"); + } + + public void testjarurl() { + executeTarget("testjarurl"); + } + + public void testnestedresources() { + executeTarget("testnestedresources"); + } + + public void testpath() { + executeTarget("testpath"); + } + + public void testpropertyset() { + executeTarget("testpropertyset"); + } + + public void testresource() { + executeTarget("testresource"); + } + + public void testresourcesref() { + executeTarget("testresourcesref"); + } + + public void testresourceurl() { + executeTarget("testresourceurl"); + } + + public void teststring1() { + executeTarget("teststring1"); + } + + public void teststring2() { + executeTarget("teststring2"); + } + + public void testunion() { + executeTarget("testunion"); + } + + public void testzipentry() { + executeTarget("testzipentry"); + } + + public void testzipfileset() { + executeTarget("testzipfileset"); + } + +} diff --git a/src/testcases/org/apache/tools/ant/types/ResourceComparatorsTest.java b/src/testcases/org/apache/tools/ant/types/ResourceComparatorsTest.java new file mode 100755 index 000000000..5692f9aeb --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/ResourceComparatorsTest.java @@ -0,0 +1,100 @@ +/* + * 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; + +import org.apache.tools.ant.BuildFileTest; + +public class ResourceComparatorsTest extends BuildFileTest { + + public ResourceComparatorsTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/types/resources/comparators/build.xml"); + } + + public void tearDown() { + executeTarget("tearDown"); + } + + public void testcompoundsort1() { + executeTarget("testcompoundsort1"); + } + + public void testcompoundsort2() { + executeTarget("testcompoundsort2"); + } + + public void testcontent() { + executeTarget("testcontent"); + } + + public void testexists() { + executeTarget("testexists"); + } + + public void testdate() { + executeTarget("testdate"); + } + + public void testname() { + executeTarget("testname"); + } + + public void testrvcontent() { + executeTarget("testrvcontent"); + } + + public void testrvdefault() { + executeTarget("testrvdefault"); + } + + public void testrvexists() { + executeTarget("testrvexists"); + } + + public void testrvdate() { + executeTarget("testrvdate"); + } + + public void testrvname() { + executeTarget("testrvname"); + } + + public void testrvsize() { + executeTarget("testrvsize"); + } + + public void testrvtype() { + executeTarget("testrvtype"); + } + + public void testsize() { + executeTarget("testsize"); + } + + public void testsortdefault() { + executeTarget("testsortdefault"); + } + + public void testtype() { + executeTarget("testtype"); + } + +} diff --git a/src/testcases/org/apache/tools/ant/types/ResourceOutputTest.java b/src/testcases/org/apache/tools/ant/types/ResourceOutputTest.java new file mode 100755 index 000000000..9ac58c30f --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/ResourceOutputTest.java @@ -0,0 +1,153 @@ +/* + * 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; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.UnknownServiceException; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildFileTest; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.Zip; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.resources.URLResource; +import org.apache.tools.ant.types.resources.ZipResource; +import org.apache.tools.ant.types.resources.FileResource; +import org.apache.tools.ant.types.resources.StringResource; +import org.apache.tools.ant.types.resources.PropertyResource; +import org.apache.tools.ant.types.resources.ImmutableResourceException; +import org.apache.tools.ant.util.FileUtils; + +public class ResourceOutputTest extends BuildFileTest { + + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private static final File basedir = new File(System.getProperty("root"), + "src/etc/testcases/types/resources"); + + public ResourceOutputTest(String name) { + super(name); + } + + public void setUp() { + project = new Project(); + project.init(); + project.setUserProperty("basedir" , basedir.getAbsolutePath()); + } + + public void testresourceoutput() { + try { + testoutputbe(new Resource("foo")); + fail("should have caught UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + } + } + + public void teststringoutput1() { + StringResource r = new StringResource(); + testoutputbe(r); + assertEquals("foo", r.getValue()); + } + + public void teststringoutput2() { + StringResource r = new StringResource("bar"); + try { + testoutput(r); + fail("should have caught ImmutableResourceException"); + } catch (ImmutableResourceException e) { + } catch (IOException e) { + fail("caught some other IOException: " + e); + } + assertEquals("bar", r.getValue()); + } + + public void testpropertyoutput1() { + PropertyResource r = new PropertyResource(getProject(), "bar"); + testoutputbe(r); + assertPropertyEquals("bar", "foo"); + } + + public void testpropertyoutput2() { + getProject().setNewProperty("bar", "bar"); + PropertyResource r = new PropertyResource(getProject(), "bar"); + try { + testoutput(r); + fail("should have caught ImmutableResourceException"); + } catch (ImmutableResourceException e) { + } catch (IOException e) { + fail("caught some other IOException: " + e); + } + assertPropertyEquals("bar", "bar"); + } + + public void testurloutput() { + File f = getProject().resolveFile("testurloutput"); + try { + FILE_UTILS.createNewFile(f); + testoutput(new URLResource(f)); + fail("should have caught UnknownServiceException"); + } catch (UnknownServiceException e) { + } catch (IOException e) { + e.printStackTrace(System.err); + fail("caught some other IOException: " + e); + } finally { + if (!f.delete()) { + f.deleteOnExit(); + } + } + } + + public void testzipentryoutput() { + Zip z = new Zip(); + z.setProject(getProject()); + Zip.WhenEmpty create = new Zip.WhenEmpty(); + create.setValue("create"); + z.setWhenempty(create); + z.setBasedir(basedir); + z.setExcludes("**/*"); + File f = getProject().resolveFile("foo"); + z.setDestFile(f); + z.execute(); + ZipResource r = new ZipResource(); + r.setZipfile(f); + r.setName("foo"); + try { + testoutputbe(r); + fail("should have caught UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + } finally { + if (!f.delete()) { + f.deleteOnExit(); + } + } + } + + private void testoutputbe(Resource dest) { + try { + testoutput(dest); + } catch (IOException e) { + throw new BuildException(e); + } + } + + private void testoutput(Resource dest) throws IOException { + FILE_UTILS.copyResource(new StringResource("foo"), dest, null); + } + +} diff --git a/src/testcases/org/apache/tools/ant/types/ResourceSelectorsTest.java b/src/testcases/org/apache/tools/ant/types/ResourceSelectorsTest.java new file mode 100755 index 000000000..51b0781c8 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/ResourceSelectorsTest.java @@ -0,0 +1,100 @@ +/* + * 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; + +import org.apache.tools.ant.BuildFileTest; + +public class ResourceSelectorsTest extends BuildFileTest { + + public ResourceSelectorsTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/types/resources/selectors/build.xml"); + } + + public void testname1() { + executeTarget("testname1"); + } + + public void testname2() { + executeTarget("testname2"); + } + + public void testexists() { + executeTarget("testexists"); + } + + public void testinstanceoftype1() { + executeTarget("testinstanceoftype1"); + } + + public void testinstanceoftype2() { + executeTarget("testinstanceoftype2"); + } + + public void testinstanceofclass() { + executeTarget("testinstanceofclass"); + } + + public void testtype() { + executeTarget("testtype"); + } + + public void testdate() { + executeTarget("testdate"); + } + + public void testsize() { + executeTarget("testsize"); + } + + public void testand() { + executeTarget("testand"); + } + + public void testor() { + executeTarget("testor"); + } + + public void testnot() { + executeTarget("testnot"); + } + + public void testnone() { + executeTarget("testnone"); + } + + public void testmajority1() { + executeTarget("testmajority1"); + } + + public void testmajority2() { + executeTarget("testmajority2"); + } + + public void testmajority3() { + executeTarget("testmajority3"); + } + + public void testmajority4() { + executeTarget("testmajority4"); + } + +} diff --git a/src/testcases/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java b/src/testcases/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java index b52e40ff2..89f695f59 100644 --- a/src/testcases/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java +++ b/src/testcases/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java @@ -172,4 +172,9 @@ public class ClassFileSetTest extends BuildFileTest { assertTrue("Result did not contain test" + File.separator + "ContainsOnlyInner.class", files.containsKey("test" + File.separator + "MethodParam.class")); } + + public void testResourceCollection() { + executeTarget("testresourcecollection"); + } + }