- /*
- * Copyright 2000-2004 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.util.Enumeration;
- import java.util.Locale;
- import java.util.Stack;
- import java.util.Vector;
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.DirectoryScanner;
- import org.apache.tools.ant.PathTokenizer;
- import org.apache.tools.ant.Project;
- import org.apache.tools.ant.util.JavaEnvUtils;
-
-
-
- /**
- * This object represents a path as used by CLASSPATH or PATH
- * environment variable.
- * <p>
- * <code>
- * <sometask><br>
- * <somepath><br>
- * <pathelement location="/path/to/file.jar" /><br>
- * <pathelement path="/path/to/file2.jar:/path/to/class2;/path/to/class3" /><br>
- * <pathelement location="/path/to/file3.jar" /><br>
- * <pathelement location="/path/to/file4.jar" /><br>
- * </somepath><br>
- * </sometask><br>
- * </code>
- * <p>
- * The object implemention <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>
- *
- * 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.
- *
- */
-
- public class Path extends DataType implements Cloneable {
-
- private Vector elements;
-
- /** The system classspath as a Path object */
- public static Path systemClasspath =
- new Path(null, System.getProperty("java.class.path"));
-
-
- /**
- * The system bootclassspath 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 <code><pathelement></code> values.
- */
- public class PathElement {
- private String[] parts;
-
- public void setLocation(File loc) {
- parts = new String[] {translateFile(loc.getAbsolutePath())};
- }
-
- public void setPath(String path) {
- parts = Path.translatePath(getProject(), path);
- }
-
- public String[] getParts() {
- return parts;
- }
- }
-
- /**
- * Invoked by IntrospectionHelper for <code>setXXX(Path p)</code>
- * attribute setters.
- */
- public Path(Project p, String path) {
- this(p);
- createPathElement().setPath(path);
- }
-
- public Path(Project project) {
- setProject(project);
- elements = new Vector();
- }
-
- /**
- * Adds a element definition to the path.
- * @param location the location of the element to add (must not be
- * <code>null</code> nor empty.
- */
- public void setLocation(File location) throws BuildException {
- if (isReference()) {
- throw tooManyAttributes();
- }
- createPathElement().setLocation(location);
- }
-
-
- /**
- * Parses a path definition and creates single PathElements.
- * @param path the path definition.
- */
- public void setPath(String path) throws BuildException {
- if (isReference()) {
- throw tooManyAttributes();
- }
- createPathElement().setPath(path);
- }
-
- /**
- * 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>
- */
- public void setRefid(Reference r) throws BuildException {
- if (!elements.isEmpty()) {
- throw tooManyAttributes();
- }
- elements.addElement(r);
- super.setRefid(r);
- }
-
- /**
- * Creates the nested <code><pathelement></code> element.
- */
- public PathElement createPathElement() throws BuildException {
- if (isReference()) {
- throw noChildrenAllowed();
- }
- PathElement pe = new PathElement();
- elements.addElement(pe);
- return pe;
- }
-
- /**
- * Adds a nested <code><fileset></code> element.
- */
- public void addFileset(FileSet fs) throws BuildException {
- if (isReference()) {
- throw noChildrenAllowed();
- }
- elements.addElement(fs);
- setChecked(false);
- }
-
- /**
- * Adds a nested <code><filelist></code> element.
- */
- public void addFilelist(FileList fl) throws BuildException {
- if (isReference()) {
- throw noChildrenAllowed();
- }
- elements.addElement(fl);
- setChecked(false);
- }
-
- /**
- * Adds a nested <code><dirset></code> element.
- */
- public void addDirset(DirSet dset) throws BuildException {
- if (isReference()) {
- throw noChildrenAllowed();
- }
- elements.addElement(dset);
- setChecked(false);
- }
-
- /**
- * Adds a nested path
- * @since Ant 1.6
- */
- public void add(Path path) throws BuildException {
- if (isReference()) {
- throw noChildrenAllowed();
- }
- elements.addElement(path);
- setChecked(false);
-
- }
-
- /**
- * Creates a nested <code><path></code> element.
- */
- public Path createPath() throws BuildException {
- if (isReference()) {
- throw noChildrenAllowed();
- }
- Path p = new Path(getProject());
- elements.addElement(p);
- setChecked(false);
- return p;
- }
-
- /**
- * Append the contents of the other Path instance to this.
- */
- public void append(Path other) {
- 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]);
- }
- }
- }
-
- /**
- * 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
- *
- * @param source
- * @param tryUserDir
- */
- public void addExisting(Path source, boolean tryUserDir) {
- String[] list = source.list();
- File userDir = (tryUserDir) ? new File(System.getProperty("user.dir"))
- : null;
-
- for (int i = 0; i < list.length; i++) {
- File f = null;
- if (getProject() != null) {
- f = getProject().resolveFile(list[i]);
- } else {
- f = new File(list[i]);
- }
- // probably not the best choice, but it solves the problem of
- // relative paths in CLASSPATH
- if (tryUserDir && !f.exists()) {
- f = new File(userDir, list[i]);
- }
- if (f.exists()) {
- setLocation(f);
- } else {
- log("dropping " + f + " from path as it doesn't exist",
- Project.MSG_VERBOSE);
- }
- }
- }
-
- /**
- * 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);
- }
- }
-
- 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 <pathelement>");
- }
- for (int j = 0; j < parts.length; j++) {
- addUnlessPresent(result, parts[j]);
- }
- } else if (o instanceof Path) {
- Path p = (Path) o;
- 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;
- DirectoryScanner ds = dset.getDirectoryScanner(getProject());
- String[] s = ds.getIncludedDirectories();
- File dir = dset.getDir(getProject());
- addUnlessPresent(result, dir, s);
- } else if (o instanceof FileSet) {
- FileSet fs = (FileSet) o;
- DirectoryScanner ds = fs.getDirectoryScanner(getProject());
- String[] s = ds.getIncludedFiles();
- File dir = fs.getDir(getProject());
- addUnlessPresent(result, dir, s);
- } else if (o instanceof FileList) {
- FileList fl = (FileList) o;
- String[] s = fl.getFiles(getProject());
- File dir = fl.getDir(getProject());
- addUnlessPresent(result, dir, s);
- }
- }
- 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();
- }
-
- /**
- * Splits a PATH (with : or ; as separators) into its parts.
- */
- public static String[] translatePath(Project project, String source) {
- final Vector result = new Vector();
- if (source == null) {
- return new String[0];
- }
-
- PathTokenizer tok = new PathTokenizer(source);
- StringBuffer element = new StringBuffer();
- while (tok.hasMoreTokens()) {
- String pathElement = tok.nextToken();
- try {
- element.append(resolveFile(project, pathElement));
- } 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.addElement(element.toString());
- element = new StringBuffer();
- }
- String[] res = new String[result.size()];
- result.copyInto(res);
- return res;
- }
-
- /**
- * Returns its argument with all file separator characters
- * replaced so that they match the local OS conventions.
- */
- 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 all occurrences of / or \ to correct separator of the
- * current platform and returns whether it had to do any
- * replacements.
- */
- protected static boolean translateFileSep(StringBuffer buffer, int pos) {
- if (buffer.charAt(pos) == '/' || buffer.charAt(pos) == '\\') {
- buffer.setCharAt(pos, File.separatorChar);
- return true;
- }
- return false;
- }
-
- /**
- * How many parts does this Path instance consist of.
- */
- public int size() {
- return list().length;
- }
-
- /**
- * Return a Path that holds the same elements as this instance.
- */
- 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.
- */
- 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.
- *
- * <p>Assume the filename is absolute if project is null.</p>
- */
- private static String resolveFile(Project project, String relativeName) {
- if (project != null) {
- File f = project.resolveFile(relativeName);
- return f.getAbsolutePath();
- }
- return 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
- * default value.
- */
- 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.
- */
- public Path concatSystemClasspath(String defValue) {
-
- Path result = new Path(getProject());
-
- String order = defValue;
- if (getProject() != null) {
- String o = getProject().getProperty("build.sysclasspath");
- if (o != null) {
- order = o;
- }
- }
-
- if (order.equals("only")) {
- // only: the developer knows what (s)he is doing
- result.addExisting(Path.systemClasspath, true);
-
- } else if (order.equals("first")) {
- // first: developer could use a little help
- result.addExisting(Path.systemClasspath, true);
- result.addExisting(this);
-
- } else if (order.equals("ignore")) {
- // ignore: don't trust anyone
- result.addExisting(this);
-
- } else {
- // last: don't trust the developer
- if (!order.equals("last")) {
- log("invalid value for build.sysclasspath: " + order,
- Project.MSG_WARN);
- }
-
- result.addExisting(this);
- result.addExisting(Path.systemClasspath, true);
- }
-
-
- return result;
-
- }
-
- /**
- * Add the Java Runtime classes to this Path instance.
- */
- public void addJavaRuntime() {
- if ("Kaffe".equals(System.getProperty("java.vm.name"))) {
- // newer versions of Kaffe (1.1.1+) won't have this,
- // but this will be sorted by FileSet anyway.
- File kaffeShare = new File(System.getProperty("java.home")
- + 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.US).indexOf("microsoft") >= 0) {
- // Pull in *.zip from packages directory
- FileSet msZipFiles = new FileSet();
- msZipFiles.setDir(new File(System.getProperty("java.home")
- + File.separator + "Packages"));
- msZipFiles.setIncludes("*.ZIP");
- addFileset(msZipFiles);
- } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + "lib"
- + File.separator
- + "classes.zip"));
- } else {
- // JDK > 1.1 seems to set java.home to the JRE directory.
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + "lib"
- + File.separator + "rt.jar"));
- // Just keep the old version as well and let addExisting
- // sort it out.
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + "jre"
- + File.separator + "lib"
- + File.separator + "rt.jar"));
-
- // Sun's and Apple's 1.4 have JCE and JSSE in separate jars.
- String[] secJars = {"jce", "jsse"};
- for (int i = 0; i < secJars.length; i++) {
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + "lib"
- + File.separator + secJars[i] + ".jar"));
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + ".."
- + File.separator + "Classes"
- + File.separator + secJars[i] + ".jar"));
- }
-
- // IBM's 1.4 has rt.jar split into 4 smaller jars and a combined
- // JCE/JSSE in security.jar.
- String[] ibmJars
- = {"core", "graphics", "security", "server", "xml"};
- for (int i = 0; i < ibmJars.length; i++) {
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + "lib"
- + File.separator + ibmJars[i] + ".jar"));
- }
-
- // Added for MacOS X
- addExisting(new Path(null,
- System.getProperty("java.home")
- + File.separator + ".."
- + File.separator + "Classes"
- + File.separator + "classes.jar"));
- addExisting(new Path(null,
- System.getProperty("java.home")
- + 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.
- * @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;
- }
- }
-
- String[] dirs = extdirs.list();
- for (int i = 0; i < dirs.length; i++) {
- File dir = getProject().resolveFile(dirs[i]);
- if (dir.exists() && dir.isDirectory()) {
- FileSet fs = new FileSet();
- fs.setDir(dir);
- fs.setIncludes("*");
- addFileset(fs);
- }
- }
- }
- }