diff --git a/proposal/myrmidon/ant1compat.xml b/proposal/myrmidon/ant1compat.xml index da4703f4d..894d444d9 100644 --- a/proposal/myrmidon/ant1compat.xml +++ b/proposal/myrmidon/ant1compat.xml @@ -1,7 +1,7 @@ - + @@ -10,7 +10,7 @@ - + @@ -18,7 +18,8 @@ - + @@ -31,11 +32,11 @@ - + - + @@ -57,16 +58,17 @@ - + - - + + + - @@ -79,7 +81,7 @@ - + diff --git a/proposal/myrmidon/build.xml b/proposal/myrmidon/build.xml index 403340475..c25f4701c 100644 --- a/proposal/myrmidon/build.xml +++ b/proposal/myrmidon/build.xml @@ -621,7 +621,10 @@ Legal: - + + + + diff --git a/proposal/myrmidon/src/ant1compat/README.txt b/proposal/myrmidon/src/ant1compat/README.txt index 52454358c..69a20a74e 100644 --- a/proposal/myrmidon/src/ant1compat/README.txt +++ b/proposal/myrmidon/src/ant1compat/README.txt @@ -56,5 +56,5 @@ TODO to register tasks? (similar for DataTypes) * Get a version of and working * Test heaps more tasks -* Fix problem with classloaders and +* Check that "if" and "unless" conversions are working. diff --git a/proposal/myrmidon/src/ant1compat/ant-descriptor.xml b/proposal/myrmidon/src/ant1compat/ant-descriptor.xml index 9c65710b2..545ff7b33 100644 --- a/proposal/myrmidon/src/ant1compat/ant-descriptor.xml +++ b/proposal/myrmidon/src/ant1compat/ant-descriptor.xml @@ -6,11 +6,21 @@ classname="org.apache.tools.ant.Ant1CompatTypeInstanceTask" /> + + + @@ -58,8 +68,6 @@ classname="org.apache.tools.ant.taskdefs.Property" /> - - null. - // * @param value The new value of the property. - // * Must not be null. - // */ - // public void setProperty( String name, String value ) - // { - // if( null != getProperty( name ) ) - // { - // log( "Overriding previous definition of property " + name, - // MSG_VERBOSE ); - // } - // - // doSetProperty( name, value ); - // } - // - // /** - // * Sets a property if no value currently exists. If the property - // * exists already, a message is logged and the method returns with - // * no other effect. - // * - // * @param name The name of property to set. - // * Must not be null. - // * @param value The new value of the property. - // * Must not be null. - // * @since 1.5 - // */ - // public void setNewProperty( String name, String value ) - // { - // if( null != getProperty( name ) ) - // { - // log( "Override ignored for property " + name, MSG_VERBOSE ); - // return; - // } - // log( "Setting project property: " + name + " -> " + - // value, MSG_DEBUG ); - // doSetProperty( name, value ); - // } - // - // private void doSetProperty( String name, String value ) - // { - // try - // { - // m_context.setProperty( name, value ); - // } - // catch( TaskException e ) - // { - // throw new BuildException( e ); - // } - // } - // - // /** - // * Returns the value of a property, if it is set. - // * - // * @param name The name of the property. - // * May be null, in which case - // * the return value is also null. - // * @return the property value, or null for no match - // * or if a null name is provided. - // */ - // public String getProperty( String name ) - // { - // if( name == null ) - // { - // return null; - // } - // Object value = m_context.getProperty( name ); - // if( value == null ) - // { - // return null; - // } - // return String.valueOf( value ); - // } - // - // /** - // * Returns a copy of the properties table. - // * @return a hashtable containing all properties - // * (including user properties). - // */ - // public Hashtable getProperties() - // { - // Map properties = m_context.getProperties(); - // Hashtable propertiesCopy = new Hashtable(); - // - // Iterator iterator = properties.keySet().iterator(); - // while( iterator.hasNext() ) - // { - // String key = (String)iterator.next(); - // String value = (String)properties.get( key ); - // - // propertiesCopy.put( key, value ); - // - // } - // - // return propertiesCopy; - // } - } diff --git a/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/LoaderUtils.java b/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/LoaderUtils.java new file mode 100644 index 000000000..0b8c46648 --- /dev/null +++ b/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/LoaderUtils.java @@ -0,0 +1,286 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.tools.ant; +import java.io.BufferedReader; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; + +/** + * LoaderUtils is a utility class with methods for configuring a class + * loader from a URL. + * + * @author Conor MacNeill + * @created 9 January 2002 + */ +public class LoaderUtils { + + /** + * This is the file that is consulted on remote systems to specify + * available jars + */ + public static final String LIST_FILE = "file.list"; + + + /** + * Get the URLs of a set of libraries in the given location + * + * @param location the location to be searched + * @param defaultFile default file if none can be found + * @return an array of URLs for the relevant jars + * @exception MalformedURLException the URLs cannot be created + */ + public static URL[] getLocationURLs(URL location, String defaultFile) + throws MalformedURLException { + return getLocationURLs(location, defaultFile, new String[]{".jar"}); + } + + /** + * Get the URLs of a set of libraries in the given location + * + * @param location the location to be searched + * @param extensions array of allowable file extensions + * @param defaultFile default file if none can be found + * @return an array of URLs for the relevant jars + * @exception MalformedURLException if the URL to the jars could not be + * formed + */ + public static URL[] getLocationURLs(URL location, String defaultFile, + String[] extensions) + throws MalformedURLException { + URL[] urls = null; + if (location.getProtocol().equals("file")) { + // URL is local filesystem. + urls = getLocalURLs(new File(location.getFile()), extensions); + } else { + // URL is remote - try to read a file with the list of jars + URL jarListURL = new URL(location, LIST_FILE); + BufferedReader reader = null; + List jarList = new ArrayList(); + try { + InputStreamReader isr + = new InputStreamReader(jarListURL.openStream()); + reader = new BufferedReader(isr); + String line = null; + while ((line = reader.readLine().trim()) != null) { + for (int i = 0; i < extensions.length; ++i) { + if (line.endsWith(extensions[i])) { + jarList.add(new URL(location, line)); + break; + } + } + } + urls = (URL[])jarList.toArray(new URL[0]); + } catch (IOException e) { + // use the default location + if (defaultFile != null) { + urls = new URL[]{new URL(location, defaultFile)}; + } + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + } + } + } + } + + return urls; + } + + /** + * Get the classpath from a classloader. This can only extract path + * components from the loaders which are instances of URLClassLoaders + * + * @param loader the loader whose path is required + * @return the loader's configuration expressed as a classpath + */ + public static String getClasspath(ClassLoader loader) { + StringBuffer pathBuffer = null; + if (loader instanceof URLClassLoader) { + URLClassLoader urlLoader = (URLClassLoader)loader; + URL[] urls = urlLoader.getURLs(); + for (int i = 0; i < urls.length; ++i) { + if (!urls[i].getProtocol().equals("file")) { + continue; + } + String pathElement = urls[i].getFile(); + if (pathBuffer == null) { + pathBuffer = new StringBuffer(pathElement); + } else { + pathBuffer.append(File.pathSeparatorChar); + pathBuffer.append(pathElement); + } + } + } + String path = pathBuffer == null ? "" : pathBuffer.toString(); + ClassLoader parentLoader = loader.getParent(); + if (parentLoader != null) { + String parentPath = getClasspath(parentLoader); + if (parentPath.length() != 0) { + path = parentPath + File.pathSeparator + path; + } + } + + return path; + } + + + /** + * Debug method to dump a class loader hierarchy to a PrintStream + * URLClassLoaders dump their URLs + * + * @param loader the class loaders whose configuration is dumped + * @param ps PrintStream to which info is sent + */ + public static void dumpLoader(PrintStream ps, ClassLoader loader) { + if (loader instanceof URLClassLoader) { + URLClassLoader urlLoader = (URLClassLoader)loader; + URL[] urls = urlLoader.getURLs(); + if (urls.length == 0) { + ps.println(" No URLs"); + } else { + for (int i = 0; i < urls.length; ++i) { + ps.println(" URL: " + urls[i]); + } + } + } else { + ps.println("Class Loader: " + loader.getClass().getName()); + } + ps.println(); + + ClassLoader parentLoader = loader.getParent(); + if (parentLoader != null) { + ps.println("Parent Loader:"); + dumpLoader(ps, parentLoader); + } + } + + + /** + * Get an array of URLs for each file in the filesystem. If the given + * location is a directory, it is searched for files of the given + * extension. If it is a file, it is returned as a URL if it matches the + * given extension list. + * + * @param location the location within the local filesystem to be + * searched + * @param extensions an array of file extensions to be considered in the + * search + * @return an array of URLs for the file found in the directory. + * @exception MalformedURLException if the URLs to the jars cannot be + * formed + */ + private static URL[] getLocalURLs(File location, + final String[] extensions) + throws MalformedURLException { + URL[] urls = new URL[0]; + + if (!location.exists()) { + return urls; + } + + if (!location.isDirectory()) { + String path = location.getPath(); + for (int i = 0; i < extensions.length; ++i) { + if (path.endsWith(extensions[i])) { + urls[0] = location.toURL(); + break; + } + } + return urls; + } + + File[] jars = location.listFiles( + new FilenameFilter() { + public boolean accept(File dir, String name) { + for (int i = 0; i < extensions.length; ++i) { + if (name.endsWith(extensions[i])) { + return true; + } + } + return false; + } + }); + urls = new URL[jars.length]; + for (int i = 0; i < jars.length; ++i) { + urls[i] = jars[i].toURL(); + } + return urls; + } + + /** + * Set the context loader of the current thread and returns the existing + * classloader + * + * @param newLoader the new context loader + * @return the old context loader + */ + public static ClassLoader setContextLoader(ClassLoader newLoader) { + Thread thread = Thread.currentThread(); + ClassLoader currentLoader = thread.getContextClassLoader(); + thread.setContextClassLoader(newLoader); + return currentLoader; + } + +} + diff --git a/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/Task.java b/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/Task.java index ac013cad0..6620e74f8 100644 --- a/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/Task.java +++ b/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/Task.java @@ -27,7 +27,7 @@ import org.apache.myrmidon.api.TaskException; public class Task extends OriginalAnt1Task implements org.apache.myrmidon.api.Task, Configurable { - private TaskContext m_context; + protected TaskContext m_context; /** * Specify the context in which the task operates in. @@ -62,6 +62,7 @@ public class Task extends OriginalAnt1Task public void configure( Configuration configuration ) throws ConfigurationException { configure( this, configuration ); + this.init(); } protected void configure( Object target, Configuration configuration ) throws ConfigurationException @@ -115,30 +116,6 @@ public class Task extends OriginalAnt1Task helper.storeElement( project, target, nestedElement, name ); } - /* - task.setLocation(new Location(helperImpl.buildFile.toString(), helperImpl.locator.getLineNumber(), - helperImpl.locator.getColumnNumber())); - String id = attr.getValue("id"); - if (id != null) { - project.addReference(id, target); - } - - // Top level tasks don't have associated targets - if (target != null) { - task.setOwningTarget(target); - container.addTask(task); - task.init(); - wrapper = task.getRuntimeConfigurableWrapper(); - wrapper.setAttributes(attrs); - if (parentWrapper != null) { - parentWrapper.addChild(wrapper); - } - } else { - task.init(); - configure(task, attrs, helperImpl.project); - } - */ - } protected String getAnt1Name( String fullName ) diff --git a/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/types/Path.java b/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/types/Path.java new file mode 100644 index 000000000..a63aa0d3f --- /dev/null +++ b/proposal/myrmidon/src/ant1compat/org/apache/tools/ant/types/Path.java @@ -0,0 +1,625 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.types; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.PathTokenizer; +import org.apache.tools.ant.LoaderUtils; + +import java.io.File; + +import java.util.Enumeration; +import java.util.Locale; +import java.util.Stack; +import java.util.Vector; + + + +/** + * *********************************************************************** + * Ant1Compatibility Layer version of Path, hacked to provide Ant1 runtime + * files in System Classpath. + * *********************************************************************** + * + * This object represents a path as used by CLASSPATH or PATH + * environment variable. + *

+ * + * <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 implemention 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. + * + * @author Thomas.Haas@softwired-inc.com + * @author Stefan Bodewig + */ + +public class Path extends DataType implements Cloneable { + + private Vector elements; + + + public static Path systemClasspath = + new Path(null, System.getProperty("java.class.path")); + + + //Modified from original source. + //Append Ant1 codebase to systemclasspath. + // ------------------Modified-------------------------------- + static + { + String classpath = LoaderUtils.getClasspath( Path.class.getClassLoader() ); + systemClasspath.append( new Path( null, classpath ) ); + } + //-----------------End Modified------------------------------ + + + /** + * Helper class, holds the nested <pathelement> 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 setXXX(Path p) + * 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 + * null 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. + * + *

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

+ */ + public void setRefid(Reference r) throws BuildException { + if (!elements.isEmpty()) { + throw tooManyAttributes(); + } + elements.addElement(r); + super.setRefid(r); + } + + /** + * Creates the nested <pathelement> element. + */ + public PathElement createPathElement() throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + PathElement pe = new PathElement(); + elements.addElement(pe); + return pe; + } + + /** + * Adds a nested <fileset> element. + */ + public void addFileset(FileSet fs) throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + elements.addElement(fs); + checked = false; + } + + /** + * Creates a nested <path> element. + */ + public Path createPath() throws BuildException { + if (isReference()) { + throw noChildrenAllowed(); + } + Path p = new Path(getProject()); + elements.addElement(p); + checked = 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"); + } + for (int j=0; jAssume the filename is absolute if project is null.

+ */ + 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); + } + } + + /** + * 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); + + } else if (order.equals("first")) { + // first: developer could use a little help + result.addExisting(Path.systemClasspath); + 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); + } + + + return result; + + } + + /** + * Add the Java Runtime classes to this Path instance. + */ + public void addJavaRuntime() { + 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("Kaffe".equals(System.getProperty("java.vm.name"))) { + FileSet kaffeJarFiles = new FileSet(); + kaffeJarFiles.setDir(new File(System.getProperty("java.home") + + File.separator + "share" + + File.separator + "kaffe")); + + kaffeJarFiles.setIncludes("*.jar"); + addFileset(kaffeJarFiles); + } + else if (Project.getJavaVersion() == Project.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")); + + // 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