/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://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.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.PathTokenizer;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.resources.FileResourceIterator;
import org.apache.tools.ant.types.resources.Union;
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. A path might also be described as a collection
of unique filesystem resources.
<sometask>
<somepath>
<pathelement location="/path/to/file.jar"/>
<pathelement path="/path/to/file2.jar:/path/to/class2;/path/to/class3"/>
<pathelement location="/path/to/file3.jar"/>
<pathelement location="/path/to/file4.jar"/>
</somepath>
</sometask>
The object implementation sometask
must provide a method called
createSomepath
which returns an instance of Path
.
Nested path definitions are handled by the Path object and must be labeled
pathelement
.
The path element takes a parameter path
which will be parsed
and split into single elements. It will usually be used
to define a path from an environment variable.
/**
* This object represents a path as used by CLASSPATH or PATH
* environment variable. A path might also be described as a collection
* of unique filesystem resources.
* <pre>
* <sometask>
* <somepath>
* <pathelement location="/path/to/file.jar"/>
* <pathelement path="/path/to/file2.jar:/path/to/class2;/path/to/class3"/>
* <pathelement location="/path/to/file3.jar"/>
* <pathelement location="/path/to/file4.jar"/>
* </somepath>
* </sometask>
* </pre>
* <p>
* The object implementation <code>sometask</code> must provide a method called
* <code>createSomepath</code> which returns an instance of <code>Path</code>.
* Nested path definitions are handled by the Path object and must be labeled
* <code>pathelement</code>.
* </p>
* <p>
* The path element takes a parameter <code>path</code> which will be parsed
* and split into single elements. It will usually be used
* to define a path from an environment variable.
* </p>
*/
public class Path extends DataType implements Cloneable, ResourceCollection {
// CheckStyle:VisibilityModifier OFF - bc
// non-final as some IDE integrations (at least Eclipse) want to override it
The system classpath as a Path object /** The system classpath as a Path object */
public static Path systemClasspath = //NOSONAR
new Path(null, System.getProperty("java.class.path"));
The system bootclasspath as a Path object.
Since: Ant 1.6.2
/**
* The system bootclasspath as a Path object.
*
* @since Ant 1.6.2
*/
public static final Path systemBootClasspath =
new Path(null, System.getProperty("sun.boot.class.path"));
// CheckStyle:VisibilityModifier OFF - bc
Helper class, holds the nested <pathelement>
values.
/**
* Helper class, holds the nested <code><pathelement></code> values.
*/
public class PathElement implements ResourceCollection {
private String[] parts;
Set the location.
Params: - loc – a
File
value
/**
* Set the location.
*
* @param loc a <code>File</code> value
*/
public void setLocation(File loc) {
parts = new String[] {translateFile(loc.getAbsolutePath())};
}
Set the path.
Params: - path – a
String
value
/**
* Set the path.
*
* @param path a <code>String</code> value
*/
public void setPath(String path) {
parts = Path.translatePath(getProject(), path);
}
Return the converted pathelements.
Returns: a String[]
value
/**
* Return the converted pathelements.
*
* @return a <code>String[]</code> value
*/
public String[] getParts() {
return parts;
}
Create an iterator.
Returns: an iterator.
/**
* Create an iterator.
* @return an iterator.
*/
@Override
public Iterator<Resource> iterator() {
return new FileResourceIterator(getProject(), null, parts);
}
Check if this resource is only for filesystems.
Returns: true.
/**
* Check if this resource is only for filesystems.
* @return true.
*/
@Override
public boolean isFilesystemOnly() {
return true;
}
Get the number of resources.
Returns: the number of parts.
/**
* Get the number of resources.
* @return the number of parts.
*/
@Override
public int size() {
return parts == null ? 0 : parts.length;
}
}
private Boolean preserveBC;
private Union union = null;
private boolean cache = false;
Invoked by IntrospectionHelper for setXXX(Path p)
attribute setters.
Params: - p – the
Project
for this path. - path – the
String
path definition.
/**
* Invoked by IntrospectionHelper for <code>setXXX(Path p)</code>
* attribute setters.
* @param p the <code>Project</code> for this path.
* @param path the <code>String</code> path definition.
*/
public Path(Project p, String path) {
this(p);
createPathElement().setPath(path);
}
Construct an empty Path
.
Params: - project – the
Project
for this path.
/**
* Construct an empty <code>Path</code>.
* @param project the <code>Project</code> for this path.
*/
public Path(Project project) {
setProject(project);
}
Adds a element definition to the path.
Params: - location – the location of the element to add (must not be
null
nor empty.
Throws: - BuildException – on error
/**
* Adds a element definition to the path.
* @param location the location of the element to add (must not be
* <code>null</code> nor empty.
* @throws BuildException on error
*/
public void setLocation(File location) throws BuildException {
checkAttributesAllowed();
createPathElement().setLocation(location);
}
Parses a path definition and creates single PathElements.
Params: - path – the
String
path definition.
Throws: - BuildException – on error
/**
* Parses a path definition and creates single PathElements.
* @param path the <code>String</code> path definition.
* @throws BuildException on error
*/
public void setPath(String path) throws BuildException {
checkAttributesAllowed();
createPathElement().setPath(path);
}
Makes this instance in effect a reference to another Path instance.
You must not set another attribute or nest elements inside
this element if you make it a reference.
Params: - r – the reference to another Path
Throws: - BuildException – on error
/**
* Makes this instance in effect a reference to another Path instance.
*
* <p>You must not set another attribute or nest elements inside
* this element if you make it a reference.</p>
* @param r the reference to another Path
* @throws BuildException on error
*/
@Override
public void setRefid(Reference r) throws BuildException {
if (union != null) {
throw tooManyAttributes();
}
super.setRefid(r);
}
Creates the nested <pathelement>
element.
Throws: - BuildException – on error
Returns: the PathElement
to be configured
/**
* Creates the nested <code><pathelement></code> element.
* @return the <code>PathElement</code> to be configured
* @throws BuildException on error
*/
public PathElement createPathElement() throws BuildException {
if (isReference()) {
throw noChildrenAllowed();
}
PathElement pe = new PathElement();
add(pe);
return pe;
}
Adds a nested <fileset>
element.
Params: - fs – a
FileSet
to be added to the path
Throws: - BuildException – on error
/**
* Adds a nested <code><fileset></code> element.
* @param fs a <code>FileSet</code> to be added to the path
* @throws BuildException on error
*/
public void addFileset(FileSet fs) throws BuildException {
if (fs.getProject() == null) {
fs.setProject(getProject());
}
add(fs);
}
Adds a nested <filelist>
element.
Params: - fl – a
FileList
to be added to the path
Throws: - BuildException – on error
/**
* Adds a nested <code><filelist></code> element.
* @param fl a <code>FileList</code> to be added to the path
* @throws BuildException on error
*/
public void addFilelist(FileList fl) throws BuildException {
if (fl.getProject() == null) {
fl.setProject(getProject());
}
add(fl);
}
Adds a nested <dirset>
element.
Params: - dset – a
DirSet
to be added to the path
Throws: - BuildException – on error
/**
* Adds a nested <code><dirset></code> element.
* @param dset a <code>DirSet</code> to be added to the path
* @throws BuildException on error
*/
public void addDirset(DirSet dset) throws BuildException {
if (dset.getProject() == null) {
dset.setProject(getProject());
}
add(dset);
}
Adds a nested path
Params: - path – a
Path
to be added to the path
Throws: - BuildException – on error
Since: Ant 1.6
/**
* Adds a nested path
* @param path a <code>Path</code> to be added to the path
* @throws BuildException on error
* @since Ant 1.6
*/
public void add(Path path) throws BuildException {
if (path == this) {
throw circularReference();
}
if (path.getProject() == null) {
path.setProject(getProject());
}
add((ResourceCollection) path);
}
Add a nested ResourceCollection
.
Params: - c – the ResourceCollection to add.
Since: Ant 1.7
/**
* Add a nested <code>ResourceCollection</code>.
* @param c the ResourceCollection to add.
* @since Ant 1.7
*/
public void add(ResourceCollection c) {
checkChildrenAllowed();
if (c == null) {
return;
}
if (union == null) {
union = new Union();
union.setProject(getProject());
union.setCache(cache);
}
union.add(c);
setChecked(false);
}
Creates a nested <path>
element.
Throws: - BuildException – on error
Returns: a Path
to be configured
/**
* Creates a nested <code><path></code> element.
* @return a <code>Path</code> to be configured
* @throws BuildException on error
*/
public Path createPath() throws BuildException {
Path p = new Path(getProject());
add(p);
return p;
}
Append the contents of the other Path instance to this.
Params: - other – a
Path
to be added to the path
/**
* Append the contents of the other Path instance to this.
* @param other a <code>Path</code> to be added to the path
*/
public void append(Path other) {
if (other == null) {
return;
}
add(other);
}
Adds the components on the given path which exist to this
Path. Components that don't exist aren't added.
Params: - source – - source path whose components are examined for existence
/**
* Adds the components on the given path which exist to this
* Path. Components that don't exist aren't added.
*
* @param source - source path whose components are examined for existence
*/
public void addExisting(Path source) {
addExisting(source, false);
}
Same as addExisting, but support classpath behavior if tryUserDir
is true. Classpaths are relative to user dir, not the project base.
That used to break jspc test
Params: - source – the source path
- tryUserDir – if true try the user directory if the file is not present
/**
* Same as addExisting, but support classpath behavior if tryUserDir
* is true. Classpaths are relative to user dir, not the project base.
* That used to break jspc test
*
* @param source the source path
* @param tryUserDir if true try the user directory if the file is not present
*/
public void addExisting(Path source, boolean tryUserDir) {
File userDir = (tryUserDir) ? new File(System.getProperty("user.dir"))
: null;
for (String name : source.list()) {
File f = resolveFile(getProject(), name);
// probably not the best choice, but it solves the problem of
// relative paths in CLASSPATH
if (tryUserDir && !f.exists()) {
f = new File(userDir, name);
}
if (f.exists()) {
setLocation(f);
} else if (f.getParentFile() != null && f.getParentFile().exists()
&& containsWildcards(f.getName())) {
setLocation(f);
log("adding " + f
+ " which contains wildcards and may not do what you intend it to do depending on your OS or version of Java",
Project.MSG_VERBOSE);
} else {
log("dropping " + f + " from path as it doesn't exist",
Project.MSG_VERBOSE);
}
}
}
Whether to cache the current path.
Params: - b – boolean
Since: Ant 1.8.0
/**
* Whether to cache the current path.
* @param b boolean
* @since Ant 1.8.0
*/
public void setCache(boolean b) {
checkAttributesAllowed();
cache = b;
if (union != null) {
union.setCache(b);
}
}
Returns all path elements defined by this and nested path objects.
Returns: list of path elements.
/**
* Returns all path elements defined by this and nested path objects.
* @return list of path elements.
*/
public String[] list() {
if (isReference()) {
return getRef().list();
}
return assertFilesystemOnly(union) == null
? new String[0] : union.list();
}
Returns a textual representation of the path, which can be used as
CLASSPATH or PATH environment variable definition.
Returns: a textual representation of the path.
/**
* 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.
*/
@Override
public String toString() {
return isReference() ? getRef().toString()
: union == null ? "" : union.toString();
}
Splits a PATH (with : or ; as separators) into its parts.
Params: - project – the project to use
- source – a
String
value
Returns: an array of strings, one for each path element
/**
* Splits a PATH (with : or ; as separators) into its parts.
* @param project the project to use
* @param source a <code>String</code> value
* @return an array of strings, one for each path element
*/
public static String[] translatePath(Project project, String source) {
if (source == null) {
return new String[0];
}
final List<String> result = new ArrayList<>();
PathTokenizer tok = new PathTokenizer(source);
while (tok.hasMoreTokens()) {
StringBuffer element = new StringBuffer();
String pathElement = tok.nextToken();
try {
element.append(resolveFile(project, pathElement).getPath());
} catch (BuildException e) {
project.log("Dropping path element " + pathElement
+ " as it is not valid relative to the project",
Project.MSG_VERBOSE);
}
for (int i = 0; i < element.length(); i++) {
translateFileSep(element, i);
}
result.add(element.toString());
}
return result.toArray(new String[result.size()]);
}
Returns its argument with all file separator characters
replaced so that they match the local OS conventions.
Params: - source – the path to convert
Returns: the converted path
/**
* Returns its argument with all file separator characters
* replaced so that they match the local OS conventions.
* @param source the path to convert
* @return the converted path
*/
public static String translateFile(String source) {
if (source == null) {
return "";
}
final StringBuffer result = new StringBuffer(source);
for (int i = 0; i < result.length(); i++) {
translateFileSep(result, i);
}
return result.toString();
}
Translates occurrences at a position of / or \ to correct separator of the
current platform and returns whether it had to do a
replacement.
Params: - buffer – a buffer containing a string
- pos – the position in the string buffer to convert
Returns: true if the character was a / or \
/**
* Translates occurrences at a position of / or \ to correct separator of the
* current platform and returns whether it had to do a
* replacement.
* @param buffer a buffer containing a string
* @param pos the position in the string buffer to convert
* @return true if the character was a / or \
*/
protected static boolean translateFileSep(StringBuffer buffer, int pos) {
if (buffer.charAt(pos) == '/' || buffer.charAt(pos) == '\\') {
buffer.setCharAt(pos, File.separatorChar);
return true;
}
return false;
}
Fulfill the ResourceCollection contract.
Returns: number of elements as int.
/**
* Fulfill the ResourceCollection contract.
* @return number of elements as int.
*/
@Override
public synchronized int size() {
if (isReference()) {
return getRef().size();
}
dieOnCircularReference();
return union == null ? 0 : assertFilesystemOnly(union).size();
}
Clone this Path.
Returns: Path with shallowly cloned Resource children.
/**
* Clone this Path.
* @return Path with shallowly cloned Resource children.
*/
@Override
public Object clone() {
try {
Path result = (Path) super.clone();
result.union = union == null ? union : (Union) union.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new BuildException(e);
}
}
Overrides the version of DataType to recurse on all DataType
child elements that may have been added.
Params: - stk – the stack of data types to use (recursively).
- p – the project to use to dereference the references.
Throws: - BuildException – on error.
/**
* 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.
*/
@Override
protected synchronized void dieOnCircularReference(Stack<Object> stk, Project p)
throws BuildException {
if (isChecked()) {
return;
}
if (isReference()) {
super.dieOnCircularReference(stk, p);
} else {
if (union != null) {
pushAndInvokeCircularReferenceCheck(union, stk, p);
}
setChecked(true);
}
}
Resolve a filename with Project's help - if we know one that is.
/**
* Resolve a filename with Project's help - if we know one that is.
*/
private static File resolveFile(Project project, String relativeName) {
return FileUtils.getFileUtils().resolveFile(
(project == null) ? null : project.getBaseDir(), relativeName);
}
Concatenates the system class path in the order specified by
the ${build.sysclasspath} property - using "last" as
default value.
Returns: the concatenated path
/**
* Concatenates the system class path in the order specified by
* the ${build.sysclasspath} property - using "last" as
* default value.
* @return the concatenated path
*/
public Path concatSystemClasspath() {
return concatSystemClasspath("last");
}
Concatenates the system class path in the order specified by
the ${build.sysclasspath} property - using the supplied value
if ${build.sysclasspath} has not been set.
Params: - defValue – the order ("first", "last", "only")
Returns: the concatenated path
/**
* Concatenates the system class path in the order specified by
* the ${build.sysclasspath} property - using the supplied value
* if ${build.sysclasspath} has not been set.
* @param defValue the order ("first", "last", "only")
* @return the concatenated path
*/
public Path concatSystemClasspath(String defValue) {
return concatSpecialPath(defValue, Path.systemClasspath);
}
Concatenates the system boot class path in the order specified
by the ${build.sysclasspath} property - using the supplied
value if ${build.sysclasspath} has not been set.
Params: - defValue – the order ("first", "last", "only")
Returns: the concatenated path
/**
* Concatenates the system boot class path in the order specified
* by the ${build.sysclasspath} property - using the supplied
* value if ${build.sysclasspath} has not been set.
* @param defValue the order ("first", "last", "only")
* @return the concatenated path
*/
public Path concatSystemBootClasspath(String defValue) {
return concatSpecialPath(defValue, Path.systemBootClasspath);
}
Concatenates a class path in the order specified by the
${build.sysclasspath} property - using the supplied value if
${build.sysclasspath} has not been set.
/**
* Concatenates a class path in the order specified by the
* ${build.sysclasspath} property - using the supplied value if
* ${build.sysclasspath} has not been set.
*/
private Path concatSpecialPath(String defValue, Path p) {
Path result = new Path(getProject());
String order = defValue;
String o = getProject() != null
? getProject().getProperty(MagicNames.BUILD_SYSCLASSPATH)
: System.getProperty(MagicNames.BUILD_SYSCLASSPATH);
if (o != null) {
order = o;
}
if ("only".equals(order)) {
// only: the developer knows what (s)he is doing
result.addExisting(p, true);
} else if ("first".equals(order)) {
// first: developer could use a little help
result.addExisting(p, true);
result.addExisting(this);
} else if ("ignore".equals(order)) {
// ignore: don't trust anyone
result.addExisting(this);
} else {
// last: don't trust the developer
if (!"last".equals(order)) {
log("invalid value for " + MagicNames.BUILD_SYSCLASSPATH
+ ": " + order,
Project.MSG_WARN);
}
result.addExisting(this);
result.addExisting(p, true);
}
return result;
}
Add the Java Runtime classes to this Path instance.
/**
* Add the Java Runtime classes to this Path instance.
*/
public void addJavaRuntime() {
if (JavaEnvUtils.isKaffe()) {
// newer versions of Kaffe (1.1.1+) won't have this,
// but this will be sorted by FileSet anyway.
File kaffeShare = new File(JavaEnvUtils.getJavaHome()
+ File.separator + "share"
+ File.separator + "kaffe");
if (kaffeShare.isDirectory()) {
FileSet kaffeJarFiles = new FileSet();
kaffeJarFiles.setDir(kaffeShare);
kaffeJarFiles.setIncludes("*.jar");
addFileset(kaffeJarFiles);
}
} else if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) {
addExisting(systemBootClasspath);
}
if (System.getProperty("java.vendor").toLowerCase(Locale.ENGLISH).contains("microsoft")) {
// TODO is this code still necessary? is there any 1.2+ port?
// Pull in *.zip from packages directory
FileSet msZipFiles = new FileSet();
msZipFiles.setDir(new File(JavaEnvUtils.getJavaHome()
+ File.separator + "Packages"));
msZipFiles.setIncludes("*.ZIP");
addFileset(msZipFiles);
} else {
// JDK 1.2+ seems to set java.home to the JRE directory.
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + "lib" + File.separator + "rt.jar"));
// Just keep the old version as well and let addExisting
// sort it out.
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + "jre" + File.separator + "lib"
+ File.separator + "rt.jar"));
// Sun's and Apple's 1.4 have JCE and JSSE in separate jars.
for (String secJar : Arrays.asList("jce", "jsse")) {
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + "lib"
+ File.separator + secJar + ".jar"));
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + ".." + File.separator + "Classes"
+ File.separator + secJar + ".jar"));
}
// IBM's 1.4 has rt.jar split into 4 smaller jars and a combined
// JCE/JSSE in security.jar.
for (String ibmJar : Arrays.asList("core", "graphics", "security", "server", "xml")) {
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + "lib" + File.separator + ibmJar + ".jar"));
}
// Added for MacOS X
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + ".." + File.separator + "Classes"
+ File.separator + "classes.jar"));
addExisting(new Path(null, JavaEnvUtils.getJavaHome()
+ File.separator + ".." + File.separator + "Classes"
+ File.separator + "ui.jar"));
}
}
Emulation of extdirs feature in Java >= 1.2.
This method adds all files in the given
directories (but not in sub-directories!) to the classpath,
so that you don't have to specify them all one by one.
Params: - extdirs – - Path to append files to
/**
* Emulation of extdirs feature in Java >= 1.2.
* This method adds all files in the given
* directories (but not in sub-directories!) to the classpath,
* so that you don't have to specify them all one by one.
* @param extdirs - Path to append files to
*/
public void addExtdirs(Path extdirs) {
if (extdirs == null) {
String extProp = System.getProperty("java.ext.dirs");
if (extProp != null) {
extdirs = new Path(getProject(), extProp);
} else {
return;
}
}
for (String d : extdirs.list()) {
File dir = resolveFile(getProject(), d);
if (dir.exists() && dir.isDirectory()) {
FileSet fs = new FileSet();
fs.setDir(dir);
fs.setIncludes("*");
addFileset(fs);
}
}
}
Fulfill the ResourceCollection contract. The Iterator returned
will throw ConcurrentModificationExceptions if ResourceCollections
are added to this container while the Iterator is in use.
Returns: a "fail-fast" Iterator.
/**
* 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.
*/
@Override
public final synchronized Iterator<Resource> iterator() {
if (isReference()) {
return getRef().iterator();
}
dieOnCircularReference();
if (getPreserveBC()) {
return new FileResourceIterator(getProject(), null, list());
}
return union == null ? Collections.<Resource> emptySet().iterator()
: assertFilesystemOnly(union).iterator();
}
Fulfill the ResourceCollection contract.
Returns: whether this is a filesystem-only resource collection.
/**
* Fulfill the ResourceCollection contract.
* @return whether this is a filesystem-only resource collection.
*/
@Override
public synchronized boolean isFilesystemOnly() {
if (isReference()) {
return getRef().isFilesystemOnly();
}
dieOnCircularReference();
assertFilesystemOnly(union);
return true;
}
Verify the specified ResourceCollection is filesystem-only.
Params: - rc – the ResourceCollection to check.
Throws: - BuildException – if
rc
is not filesystem-only.
Returns: the passed in ResourceCollection.
/**
* Verify the specified ResourceCollection is filesystem-only.
* @param rc the ResourceCollection to check.
* @throws BuildException if <code>rc</code> is not filesystem-only.
* @return the passed in ResourceCollection.
*/
protected ResourceCollection assertFilesystemOnly(ResourceCollection rc) {
if (rc != null && !(rc.isFilesystemOnly())) {
throw new BuildException("%s allows only filesystem resources.",
getDataTypeName());
}
return rc;
}
Helps determine whether to preserve BC by calling list()
on subclasses.
The default behavior of this method is to return true
for any subclass
that implements list()
; this can, of course, be avoided by overriding
this method to return false
. It is not expected that the result of this
method should change over time, thus it is called only once.
Returns: true
if iterator()
should delegate to list()
.
/**
* Helps determine whether to preserve BC by calling <code>list()</code> on subclasses.
* The default behavior of this method is to return <code>true</code> for any subclass
* that implements <code>list()</code>; this can, of course, be avoided by overriding
* this method to return <code>false</code>. It is not expected that the result of this
* method should change over time, thus it is called only once.
* @return <code>true</code> if <code>iterator()</code> should delegate to <code>list()</code>.
*/
protected boolean delegateIteratorToList() {
if (getClass().equals(Path.class)) {
return false;
}
try {
Method listMethod = getClass().getMethod("list");
return !listMethod.getDeclaringClass().equals(Path.class);
} catch (Exception e) {
//shouldn't happen, but
return false;
}
}
private synchronized boolean getPreserveBC() {
if (preserveBC == null) {
preserveBC = delegateIteratorToList() ? Boolean.TRUE : Boolean.FALSE;
}
return preserveBC;
}
Does the given file name contain wildcards?
Since: Ant 1.8.2
/**
* Does the given file name contain wildcards?
* @since Ant 1.8.2
*/
private static boolean containsWildcards(String path) {
return path != null && (path.contains("*") || path.contains("?"));
}
private Path getRef() {
return getCheckedRef(Path.class);
}
}