ehatcher 02/02/10 19:39:00
Modified: proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs
Antjar.java Antlib.java
proposal/sandbox/antlib/docs/manual/CoreTasks antjar.html
antlib.html
Added: proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs
Ant.java
proposal/sandbox/antlib build.xml
proposal/sandbox/antlib/src/main/org/apache/tools/ant
Project.java RoleAdapter.java SymbolTable.java
TaskAdapter.java
Log:
upon Jose Alberto's request, updates to antlib
Revision Changes Path
1.2 +1 -140
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java
Index: Antjar.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antjar.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Antjar.java 27 Nov 2001 06:53:22 -0000 1.1
+++ Antjar.java 11 Feb 2002 03:39:00 -0000 1.2
@@ -107,9 +107,6 @@
throw new BuildException("Deployment descriptor: " +
libraryDescriptor + " does not exist.");
}
- //check
- validateDescriptor();
-
// Create a ZipFileSet for this file, and pass it up.
ZipFileSet fs = new ZipFileSet();
fs.setDir(new File(libraryDescriptor.getParent()));
@@ -130,7 +127,7 @@
throws IOException, BuildException {
// If no antxml file is specified, it's an error.
if (libraryDescriptor == null) {
- throw new BuildException("webxml attribute is required",
location);
+ throw new BuildException("antxml attribute is required",
location);
}
super.initZipOutputStream(zOut);
@@ -177,140 +174,4 @@
super.cleanUp();
}
-
- /**
- * validate the descriptor against the DTD
- *
- * @exception BuildException failure to validate
- */
- protected void validateDescriptor()
- throws BuildException {
- SAXParserFactory saxFactory = SAXParserFactory.newInstance();
- saxFactory.setValidating(true);
- InputStream is = null;
- try {
- SAXParser saxParser = saxFactory.newSAXParser();
- Parser parser = saxParser.getParser();
- is = new FileInputStream(libraryDescriptor);
- InputSource inputSource = new InputSource(is);
- inputSource.setSystemId("file:" + libraryDescriptor);
- project.log("Validating library descriptor: " +
libraryDescriptor,
- Project.MSG_VERBOSE);
- saxParser.parse(inputSource, new AntLibraryValidator());
- }
- catch (ParserConfigurationException exc) {
- throw new BuildException("Parser has not been configured
correctly", exc);
- }
- catch (SAXParseException exc) {
- Location location =
- new Location(libraryDescriptor.toString(),
- exc.getLineNumber(), exc.getColumnNumber());
-
- Throwable t = exc.getException();
- if (t instanceof BuildException) {
- BuildException be = (BuildException) t;
- if (be.getLocation() == Location.UNKNOWN_LOCATION) {
- be.setLocation(location);
- }
- throw be;
- }
-
- throw new BuildException(exc.getMessage(), t, location);
- }
- catch (SAXException exc) {
- Throwable t = exc.getException();
- if (t instanceof BuildException) {
- throw (BuildException) t;
- }
- throw new BuildException(exc.getMessage(), t);
- }
- catch (IOException exc) {
- throw new BuildException("Error reading library descriptor",
exc);
- }
- finally {
- if (is != null) {
- try {
- is.close();
- }
- catch (IOException ioe) {
- // ignore this
- }
- }
- }
- }
-
-
- /**
- * Parses the document describing the content of the library.
- */
- private class AntLibraryValidator extends HandlerBase {
-
- /**
- * flag to track whether the DOCTYPE was hit in the prolog
- */
- private boolean doctypePresent = false;
-
- /**
- * doc locator
- */
- private Locator locator = null;
-
- /**
- * Sets the DocumentLocator attribute of the AntLibraryValidator
- * object
- *
- * @param locator The new DocumentLocator value
- */
- public void setDocumentLocator(Locator locator) {
- this.locator = locator;
- }
-
- /**
- * SAX callback handler
- *
- * @param tag XML tag
- * @param attrs attributes
- * @exception SAXParseException parse trouble
- */
- public void startElement(String tag, AttributeList attrs)
- throws SAXParseException {
- // By the time an element is found
- // the DOCTYPE should have been found.
- if (!doctypePresent) {
- String msg = "Missing DOCTYPE declaration or wrong SYSTEM
ID";
- throw new SAXParseException(msg, locator);
- }
- }
-
- /**
- * Recognizes the DTD declaration for antlib and returns the
corresponding
- * DTD definition from a resource. <P>
- *
- * To allow for future versions of the DTD format it will search
- * for any DTDs of the form "Antlib-V.*\.dtd".
- *
- * @param publicId public ID (ignored)
- * @param systemId system ID (matched against)
- * @return local DTD instance
- */
- public InputSource resolveEntity(String publicId,
- String systemId) {
-
- log("Looking for entity with PublicID=" + publicId +
- " and SystemId=" + systemId, Project.MSG_VERBOSE);
- if (Antlib.matchDtdId(systemId)) {
- String resId =
- systemId.substring(Antlib.ANTLIB_DTD_URL.length());
- InputSource is =
- new
InputSource(this.getClass().getResourceAsStream(resId));
-
- is.setSystemId(systemId);
- doctypePresent = true;
- return is;
- }
- return null;
- }
- //end inner class AntLibraryValidator
- }
}
-
1.2 +140 -132
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java
Index: Antlib.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Antlib.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Antlib.java 27 Nov 2001 06:53:22 -0000 1.1
+++ Antlib.java 11 Feb 2002 03:39:00 -0000 1.2
@@ -76,9 +76,11 @@
* @since ant1.5
*/
public class Antlib extends Task {
- /*
- * implements DeclaringTask
+ /**
+ * The named classloader to use.
+ * Defaults to the default classLoader.
*/
+ private String loaderId = "";
/**
* library attribute
@@ -177,6 +179,15 @@
this.file = file;
}
+ /**
+ * Set the ClassLoader to use for this library.
+ *
+ * @param id the id for the ClassLoader to use,
+ * if other than the default.
+ */
+ public void setLoaderid(String id) {
+ this.loaderId = id;
+ }
/**
* Set whether to override any existing definitions.
@@ -189,8 +200,9 @@
/**
- * Set whether to use a new classloader or not. Default is
<code>false</code>
- * . This property is mostly used by the core when loading core tasks.
+ * Set whether to use a new classloader or not.
+ * Default is <code>false</code>.
+ * This property is mostly used by the core when loading core tasks.
*
* @param useCurrentClassloader if true the current classloader will
* be used to load the definitions.
@@ -264,7 +276,7 @@
String msg = "You cannot specify both file and library.";
throw new BuildException(msg, location);
}
- // For the time being libraries live in $ANT_HOME/lib.
+ // For the time being libraries live in $ANT_HOME/antlib.
// The idea being that we would not load all the jars there
anymore
String home = project.getProperty("ant.home");
@@ -272,7 +284,7 @@
throw new BuildException("ANT_HOME not set as required.");
}
- realFile = new File(new File(home, "lib"), library);
+ realFile = new File(new File(home, "antlib"), library);
}
else if (file == null) {
String msg = "Must specify either library or file attribute.";
@@ -406,8 +418,7 @@
if (classpath != null) {
clspath.append(classpath);
}
- AntClassLoader al = new AntClassLoader(project, clspath, true);
- return al;
+ return project.getSymbols().addToLoader(loaderId, clspath);
}
@@ -474,30 +485,6 @@
/**
- * get a DTD URI from url, prefix and extension
- *
- * @return URI for this dtd version
- */
- public static String dtdVersion() {
- return ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX +
- ANTLIB_DTD_VERSION + ANTLIB_DTD_EXT;
- }
-
-
- /**
- * compare system ID with the dtd string
- * -ignoring any version number
- * @param systemId Description of Parameter
- * @return true if this is a an ant library descriptor
- */
- public static boolean matchDtdId(String systemId) {
- return (systemId != null &&
- systemId.startsWith(ANTLIB_DTD_URL + ANTLIB_DTD_PREFIX) &&
- systemId.endsWith(ANTLIB_DTD_EXT));
- }
-
-
- /**
* Parses the document describing the content of the
* library. An inner class for access to Project.log
*/
@@ -516,6 +503,14 @@
*/
private Locator locator = null;
+ private int level = 0;
+
+ private SymbolTable symbols = null;
+
+ private String name = null;
+ private String className = null;
+ private String adapter = null;
+
/**
* Constructor for the AntLibraryHandler object
*
@@ -525,9 +520,9 @@
AntLibraryHandler(ClassLoader classloader, Properties als) {
this.classloader = classloader;
this.aliasMap = als;
+ this.symbols = project.getSymbols();
}
-
/**
* Sets the DocumentLocator attribute of the AntLibraryHandler
* object
@@ -538,6 +533,35 @@
this.locator = locator;
}
+ private void parseAttributes(String tag, AttributeList attrs)
+ throws SAXParseException {
+ name = null;
+ className = null;
+ adapter = null;
+
+ for (int i = 0, last = attrs.getLength(); i < last; i++) {
+ String key = attrs.getName(i);
+ String value = attrs.getValue(i);
+
+ if (key.equals("name")) {
+ name = value;
+ }
+ else if (key.equals("class")) {
+ className = value;
+ }
+ else if ("role".equals(tag) && key.equals("adapter")) {
+ adapter = value;
+ }
+ else {
+ throw new SAXParseException("Unexpected attribute \""
+ + key + "\"", locator);
+ }
+ }
+ if (name == null || className == null) {
+ String msg = "Underspecified " + tag + " declaration.";
+ throw new SAXParseException(msg, locator);
+ }
+ }
/**
* SAX callback handler
@@ -548,121 +572,105 @@
*/
public void startElement(String tag, AttributeList attrs)
throws SAXParseException {
+ level ++;
if ("antlib".equals(tag)) {
+ if (level > 1) {
+ throw new SAXParseException("Unexpected element: " + tag,
+ locator);
+ }
// No attributes to worry about
return;
}
- if ("task".equals(tag) || "type".equals(tag)) {
- String name = null;
- String className = null;
-
- for (int i = 0, last = attrs.getLength(); i < last; i++) {
- String key = attrs.getName(i);
- String value = attrs.getValue(i);
-
- if (key.equals("name")) {
- name = value;
- }
- else if (key.equals("class")) {
- className = value;
- }
- else {
- throw new SAXParseException("Unexpected attribute \""
- + key + "\"", locator);
- }
- }
- if (name == null || className == null) {
- String msg = "Underspecified " + tag + " declaration.";
- throw new SAXParseException(msg, locator);
- }
-
- try {
- //check for name alias
- String alias = aliasMap.getProperty(name);
- if (alias != null) {
- name = alias;
- }
- //catch an attempted override of an existing name
- if (!override && inUse(name)) {
- String msg = "Cannot override " + tag + ": " + name;
- log(msg, Project.MSG_WARN);
- return;
- }
-
- //load the named class
- Class cls;
- if(classloader==null) {
- cls=Class.forName(className);
- }
- else {
- cls=classloader.loadClass(className);
- }
-
- //register it as a task or a datatype
- if (tag.equals("task")) {
- project.addTaskDefinition(name, cls);
- }
- else {
- project.addDataTypeDefinition(name, cls);
- }
- }
- catch (ClassNotFoundException cnfe) {
- String msg = "Class " + className +
- " cannot be found";
- throw new SAXParseException(msg, locator, cnfe);
- }
- catch (NoClassDefFoundError ncdfe) {
- String msg = "Class " + className +
- " cannot be found";
- throw new SAXParseException(msg, locator);
- }
- }
- else {
- throw new SAXParseException("Unexpected element \"" +
- tag + "\"",
- locator);
- }
- }
-
+ if (level == 1) {
+ throw new SAXParseException("Missing antlib root element",
+ locator);
+ }
+
+ // Must have the two attributes declared
+ parseAttributes(tag, attrs);
+
+ try {
+ if ("role".equals(tag)) {
+ if (isRoleInUse(name)) {
+ String msg = "Cannot override role: " + name;
+ log(msg, Project.MSG_WARN);
+ return;
+ }
+ // Defining a new role
+ symbols.addRole(name, loadClass(className),
+ (adapter == null?
+ null : loadClass(adapter)));
+ return;
+ }
+
+ // Defining a new element kind
+ //check for name alias
+ String alias = aliasMap.getProperty(name);
+ if (alias != null) {
+ name = alias;
+ }
+ //catch an attempted override of an existing name
+ if (!override && isInUse(tag, name)) {
+ String msg = "Cannot override " + tag + ": " + name;
+ log(msg, Project.MSG_WARN);
+ return;
+ }
+ symbols.add(tag, name, loadClass(className));
+ }
+ catch(BuildException be) {
+ throw new SAXParseException(be.getMessage(), locator, be);
+ }
+ }
+
+ public void endElement(String tag) {
+ level--;
+ }
+
+ private Class loadClass(String className)
+ throws SAXParseException {
+ try {
+ //load the named class
+ Class cls;
+ if(classloader==null) {
+ cls=Class.forName(className);
+ }
+ else {
+ cls=classloader.loadClass(className);
+ }
+ return cls;
+ }
+ catch (ClassNotFoundException cnfe) {
+ String msg = "Class " + className +
+ " cannot be found";
+ throw new SAXParseException(msg, locator, cnfe);
+ }
+ catch (NoClassDefFoundError ncdfe) {
+ String msg = "Class " + className +
+ " cannot be found";
+ throw new SAXParseException(msg, locator);
+ }
+ }
/**
- * test for a name being in use already
+ * test for a name being in use already on this role
*
* @param name the name to test
* @return true if it is a task or a datatype
*/
- private boolean inUse(String name) {
- return (project.getTaskDefinitions().get(name) != null ||
- project.getDataTypeDefinitions().get(name) != null);
+ private boolean isInUse(String role, String name) {
+ return (symbols.get(role, name) != null);
}
-
/**
- * Recognizes the DTD declaration for antlib and returns the
corresponding
- * DTD definition from a resource. <P>
- *
- * To allow for future versions of the DTD format it will search
- * for any DTDs of the form "Antlib-V.*\.dtd".
+ * test for a role name being in use already
*
- * @param publicId public ID (ignored)
- * @param systemId system ID (matched against)
- * @return local DTD instance
+ * @param name the name to test
+ * @return true if it is a task or a datatype
*/
- public InputSource resolveEntity(String publicId,
- String systemId) {
-
- log("Looking for entiry with PublicID=" + publicId +
- " and SystemId=" + systemId, Project.MSG_VERBOSE);
- if (matchDtdId(systemId)) {
- String resId = systemId.substring(ANTLIB_DTD_URL.length());
- InputSource is =
- new
InputSource(this.getClass().getResourceAsStream(resId));
-
- is.setSystemId(systemId);
- return is;
- }
- return null;
+ private boolean isRoleInUse(String name) {
+ return (symbols.getRole(name) != null);
}
+
//end inner class AntLibraryHandler
}
1.1
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/taskdefs/Ant.java
Index: Ant.java
===================================================================
/*
* 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 [EMAIL PROTECTED]
*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant.taskdefs;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.util.FileUtils;
import java.io.File;
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* Call Ant in a sub-project
*
* <pre>
* <target name="foo" depends="init">
* <ant antfile="build.xml" target="bar" >
* <property name="property1" value="aaaaa" />
* <property name="foo" value="baz" />
* </ant></SPAN>
* </target></SPAN>
*
* <target name="bar" depends="init">
* <echo message="prop is ${property1} ${foo}" />
* </target>
* </pre>
*
*
* @author [EMAIL PROTECTED]
*/
public class Ant extends Task {
/** the basedir where is executed the build file */
private File dir = null;
/** the build.xml file (can be absolute) in this case dir will be ignored
*/
private String antFile = null;
/** the target to call if any */
private String target = null;
/** the output */
private String output = null;
/** should we inherit properties from the parent ? */
private boolean inheritAll = true;
/** should we inherit references from the parent ? */
private boolean inheritRefs = false;
/** the properties to pass to the new project */
private Vector properties = new Vector();
/** the references to pass to the new project */
private Vector references = new Vector();
/** the temporary project created to run the build file */
private Project newProject;
/**
* If true, inherit all properties from parent Project
* If false, inherit only userProperties and those defined
* inside the ant call itself
*/
public void setInheritAll(boolean value) {
inheritAll = value;
}
/**
* If true, inherit all references from parent Project
* If false, inherit only those defined
* inside the ant call itself
*/
public void setInheritRefs(boolean value) {
inheritRefs = value;
}
public void init() {
newProject = new Project(project);
newProject.setJavaVersionProperty();
// newProject.addTaskDefinition("property",
//
(Class)project.getTaskDefinitions().get("property"));
}
private void reinit() {
init();
final int count = properties.size();
for (int i = 0; i < count; i++) {
Property p = (Property) properties.elementAt(i);
Property newP = (Property) newProject.createTask("property");
newP.setName(p.getName());
if (p.getValue() != null) {
newP.setValue(p.getValue());
}
if (p.getFile() != null) {
newP.setFile(p.getFile());
}
if (p.getResource() != null) {
newP.setResource(p.getResource());
}
properties.setElementAt(newP, i);
}
}
private void initializeProject() {
Vector listeners = project.getBuildListeners();
final int count = listeners.size();
for (int i = 0; i < count; i++) {
newProject.addBuildListener((BuildListener)listeners.elementAt(i));
}
if (output != null) {
try {
PrintStream out = new PrintStream(new
FileOutputStream(output));
DefaultLogger logger = new DefaultLogger();
logger.setMessageOutputLevel(Project.MSG_INFO);
logger.setOutputPrintStream(out);
logger.setErrorPrintStream(out);
newProject.addBuildListener(logger);
}
catch( IOException ex ) {
log( "Ant: Can't set output to " + output );
}
}
// Hashtable taskdefs = project.getTaskDefinitions();
// Enumeration et = taskdefs.keys();
// while (et.hasMoreElements()) {
// String taskName = (String) et.nextElement();
// if (taskName.equals("property")) {
// // we have already added this taskdef in #init
// continue;
// }
// Class taskClass = (Class) taskdefs.get(taskName);
// newProject.addTaskDefinition(taskName, taskClass);
// }
// Hashtable typedefs = project.getDataTypeDefinitions();
// Enumeration e = typedefs.keys();
// while (e.hasMoreElements()) {
// String typeName = (String) e.nextElement();
// Class typeClass = (Class) typedefs.get(typeName);
// newProject.addDataTypeDefinition(typeName, typeClass);
// }
// set user-defined or all properties from calling project
Hashtable prop1;
if (inheritAll) {
prop1 = project.getProperties();
} else {
prop1 = project.getUserProperties();
// set Java built-in properties separately,
// b/c we won't inherit them.
newProject.setSystemProperties();
}
Enumeration e = prop1.keys();
while (e.hasMoreElements()) {
String arg = (String) e.nextElement();
if ("basedir".equals(arg) || "ant.file".equals(arg)) {
// basedir and ant.file get special treatment in execute()
continue;
}
String value = (String) prop1.get(arg);
if (inheritAll){
newProject.setProperty(arg, value);
} else {
newProject.setUserProperty(arg, value);
}
}
}
protected void handleOutput(String line) {
if (newProject != null) {
newProject.demuxOutput(line, false);
} else {
super.handleOutput(line);
}
}
protected void handleErrorOutput(String line) {
if (newProject != null) {
newProject.demuxOutput(line, true);
} else {
super.handleErrorOutput(line);
}
}
/**
* Do the execution.
*/
public void execute() throws BuildException {
try {
if (newProject == null) {
reinit();
}
if ( (dir == null) && (inheritAll) ) {
dir = project.getBaseDir();
}
initializeProject();
if (dir != null) {
newProject.setBaseDir(dir);
newProject.setUserProperty("basedir" , dir.getAbsolutePath());
} else {
dir = project.getBaseDir();
}
overrideProperties();
if (antFile == null) {
antFile = "build.xml";
}
File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
antFile = file.getAbsolutePath();
newProject.setUserProperty( "ant.file" , antFile );
ProjectHelper.configureProject(newProject, new File(antFile));
if (target == null) {
target = newProject.getDefaultTarget();
}
addReferences();
// Are we trying to call the target in which we are defined?
if (newProject.getBaseDir().equals(project.getBaseDir()) &&
newProject.getProperty("ant.file").equals(project.getProperty("ant.file")) &&
getOwningTarget() != null &&
target.equals(this.getOwningTarget().getName())) {
throw new BuildException("ant task calling its own parent
target");
}
newProject.executeTarget(target);
} finally {
// help the gc
newProject = null;
}
}
/**
* Override the properties in the new project with the one
* explicitly defined as nested elements here.
*/
private void overrideProperties() throws BuildException {
Enumeration e = properties.elements();
while (e.hasMoreElements()) {
Property p = (Property) e.nextElement();
p.setProject(newProject);
p.execute();
}
}
/**
* Add the references explicitly defined as nested elements to the
* new project. Also copy over all references that don't override
* existing references in the new project if inheritall has been
* requested.
*/
private void addReferences() throws BuildException {
Hashtable thisReferences = (Hashtable)
project.getReferences().clone();
Hashtable newReferences = newProject.getReferences();
Enumeration e;
if (references.size() > 0) {
for(e = references.elements(); e.hasMoreElements();) {
Reference ref = (Reference)e.nextElement();
String refid = ref.getRefId();
if (refid == null) {
throw new BuildException("the refid attribute is required
for reference elements");
}
if (!thisReferences.containsKey(refid)) {
log("Parent project doesn't contain any reference '"
+ refid + "'",
Project.MSG_WARN);
continue;
}
thisReferences.remove(refid);
String toRefid = ref.getToRefid();
if (toRefid == null) {
toRefid = refid;
}
copyReference(refid, toRefid);
}
}
// Now add all references that are not defined in the
// subproject, if inheritRefs is true
if (inheritRefs) {
for(e = thisReferences.keys(); e.hasMoreElements();) {
String key = (String)e.nextElement();
if (newReferences.containsKey(key)) {
continue;
}
copyReference(key, key);
}
}
}
/**
* Try to clone and reconfigure the object referenced by oldkey in
* the parent project and add it to the new project with the key
* newkey.
*
* <p>If we cannot clone it, copy the referenced object itself and
* keep our fingers crossed.</p>
*/
private void copyReference(String oldKey, String newKey) {
Object orig = project.getReference(oldKey);
Class c = orig.getClass();
Object copy = orig;
try {
Method cloneM = c.getMethod("clone", new Class[0]);
if (cloneM != null) {
copy = cloneM.invoke(orig, new Object[0]);
}
} catch (Exception e) {
// not Clonable
}
if (copy instanceof ProjectComponent) {
((ProjectComponent) copy).setProject(newProject);
} else {
try {
Method setProjectM =
c.getMethod( "setProject", new Class[] {Project.class});
if(setProjectM != null) {
setProjectM.invoke(copy, new Object[] {newProject});
}
} catch (NoSuchMethodException e) {
// ignore this if the class being referenced does not have
// a set project method.
} catch(Exception e2) {
String msg = "Error setting new project instance for
reference with id "
+ oldKey;
throw new BuildException(msg, e2, location);
}
}
newProject.addReference(newKey, copy);
}
/**
* ...
*/
public void setDir(File d) {
this.dir = d;
}
/**
* set the build file, it can be either absolute or relative.
* If it is absolute, <tt>dir</tt> will be ignored, if it is
* relative it will be resolved relative to <tt>dir</tt>.
*/
public void setAntfile(String s) {
// @note: it is a string and not a file to handle relative/absolute
// otherwise a relative file will be resolved based on the current
// basedir.
this.antFile = s;
}
/**
* set the target to execute. If none is defined it will
* execute the default target of the build file
*/
public void setTarget(String s) {
this.target = s;
}
public void setOutput(String s) {
this.output = s;
}
/** create a property to pass to the new project as a 'user property' */
public Property createProperty() {
if (newProject == null) {
reinit();
}
Property p = new Property(true);
p.setProject(newProject);
p.setTaskName("property");
properties.addElement( p );
return p;
}
/**
* create a reference element that identifies a data type that
* should be carried over to the new project.
*/
public void addReference(Reference r) {
references.addElement(r);
}
/**
* Helper class that implements the nested <reference>
* element of <ant> and <antcall>.
*/
public static class Reference
extends org.apache.tools.ant.types.Reference {
public Reference() {super();}
private String targetid=null;
public void setToRefid(String targetid) { this.targetid=targetid; }
public String getToRefid() { return targetid; }
}
}
1.2 +30 -22
jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antjar.html
Index: antjar.html
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antjar.html,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- antjar.html 27 Nov 2001 06:53:22 -0000 1.1
+++ antjar.html 11 Feb 2002 03:39:00 -0000 1.2
@@ -12,41 +12,50 @@
<p>An extension of the <a href="jar.html">Jar</a> task with special
treatment for the library descriptor file that should end up in the
<code>META-INF</code> directory of the Ant Archive.</p>
-<p>This task validates the provided library descriptor making certain
-it specifies the following SYSTEM ID:
-<b>"http://jakarta.apache.org/ant/AntlibV1_0.dtd"</b>.
-This DTD is defined as follows:</p>
+<p>
+Descriptors must follow the following rules, although there is no fix DTD
+for them:
<pre>
-<?xml version='1.0' encoding="UTF8" ?>
-
-<!--
-This file defines the XML format for ANT library descriptors.
-Descriptors must especify a DOCTYPE of
-"http://jakarta.apache.org/ant/Antlib-V1_0.dtd"
-as the SystemId for the document.
--->
<!-- Root element for the Antlib descriptor. -->
-<!ELEMENT antlib (task | type)* >
-<!ATTLIST antlib
- version CDATA #IMPLIED
->
+<!ELEMENT antlib (role | <i>rolename</i>)* >
-<!-- Declaration of tasks contained in the library. -->
-<!ELEMENT task EMPTY>
-<!ATTLIST task
+<!-- Declaration of roles contained in the library. -->
+<!ELEMENT role EMPTY>
+<!ATTLIST role
name CDATA #REQUIRED
class CDATA #REQUIRED
+ proxy CDATA #IMPLIED
>
<!-- Declaration of datatypes contained in the library -->
-<!ELEMENT type EMPTY>
-<!ATTLIST type
+<!ELEMENT <i>rolename</i> EMPTY>
+<!ATTLIST <i>rolename</i>
name CDATA #REQUIRED
class CDATA #REQUIRED
>
</pre>
+There are two predefined roles: <i><b>task</b></i> and
<i><b>datatype</b></i>.
+<p>
+<h4>Role definition</h4>
+The <b>name</b> of the role. This name is used when specifying
+elements for this role.
+<p>
+The <b>class</b> defining a role must be an interface containing a
+unique void method with only one argument whose type is the that of
+elements declared on the role.
+<p>
+The <b>proxy</b> defined in a role specifies a class that can be used
+to bridge between the type expected by the role and the type of
+elements declared for that role.
+<h4>Element definition</h4>
+Any element whose name is that of a role declares an element for that role.
+<p>
+The <b>name</b> defined the name of the element to use in the buildfile
+to specify the element being declared.
+<p>
+The <b>class</b> the class defining the element.
<h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -78,7 +87,6 @@
<p>Here is a sample <code>META-INF/antlib.xml</code>:</p>
<pre>
<?xml version="1.0" encoding="UTF8" ?>
-<!DOCTYPE antlib SYSTEM "http://jakarta.apache.org/ant/Antlib-V1_0.dtd"
>
<antlib version="1.0" >
<task name="case" class="org.apache.ant.contrib.Case" />
1.2 +39 -8
jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antlib.html
Index: antlib.html
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/sandbox/antlib/docs/manual/CoreTasks/antlib.html,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- antlib.html 27 Nov 2001 06:53:22 -0000 1.1
+++ antlib.html 11 Feb 2002 03:39:00 -0000 1.2
@@ -9,16 +9,38 @@
<h2><a name="antlib">AntLib</a></h2>
<h3>Description</h3>
-<p>Defines and loads any tasks and datatypes contained in an ANT library.</p>
+<p>Defines and loads elements contained in an ANT library.</p>
<p>It also allows the aliasing of the names being defined in order to avoid
collisions and provides means to override definitions with the ones defined
in the library.</p>
-Ant libraries can be loaded in the current classloader, which is more
efficient,
+Ant libraries are associated with ClassLoaders identified by the
+<tt>loaderid</tt> attribute. If no loader is specified a default loader
+will be used. Ant libraries specifying the same loader are loaded by the
+same ClassLoader as long as the libraries are defined on the same project.
+Classloaders with the same ID in a subproject have the corresponding
+classloader in the parent project as their parent classloader.
+<p>
+Ant libraries can be loaded in the current classloader,
+which is more efficient,
but requires the tasks to be in the path already (such as in the ant lib
directory) - set <tt>useCurrentClassloader</tt> to true to enable this.
It is also possible to add more libraries to the path, such as any
libraries the task is dependent on.
-
+<p>
+Ant libraries define objects of several types:
+<ol>
+<li> <b>Roles</b>: Define an interface to be implemented by elements
+(usually tasks) that accept subelements of the specified role.
+Roles may also define a proxy class which may be applied to an element
+in order to make it compatible with the role.
+</li>
+<li> <b>Tasks</b>: define elements that belong to the predefined
+role "task".
+<li> <b>Data types</b>: define elements that belong to the predefined role
+"datatype".
+<li> <b>Other role elements</b>: declare elements for other roles that
+have been previously defined.
+</ol>
<h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -33,11 +55,13 @@
</tr>
<tr>
<td valign="top">library</td>
- <td valign="top">The name of a library relative to ${ant.home}/lib.</td>
+ <td valign="top">The name of a library relative to
${ant.home}/antlib.</td>
</tr>
<tr>
<td valign="top">override</td>
- <td valign="top">Replace any existing definition with the same name.
("true"/"false"). When "false" already defined
tasks
+ <td valign="top">Replace any existing definition with the same name.
+ ("true"/"false").
+ When "false" already defined tasks
and datatytes take precedence over those in the library.
Default is "false" when omitted.</td>
<td align="center" valign="top">No</td>
@@ -59,12 +83,20 @@
</td>
<td valign="top" align="center">No</td>
</tr>
+ <tr>
+ <td valign="top">loaderid</td>
+ <td valign="top">The ID of the ClassLoader to use to load the classes
+ defined in this library. If omitted a default per project ClassLoader
+ will be used.
+ </td>
+ <td valign="top" align="center">No</td>
+ </tr>
</table>
<h3><a name="nested">Parameters specified as nested elements</a></h3>
<h4>alias</h4>
<p>Specifies the usage of a different name from that defined in the library
-descriptor.</p>
+descriptor. Applies only to element definitions (not role declarations).</p>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td valign="top"><b>Attribute</b></td>
@@ -86,9 +118,8 @@
descriptor. This is used to deal with name clashes </p>
<h4>classpath</h4>
-<h4>classpath</h4>
-A classpath of extra libraries to import to support this task.
+A classpath of extra libraries to import to support this library.
<h4>classpathref</h4>
A reference to an existing classpath.
1.1 jakarta-ant/proposal/sandbox/antlib/build.xml
Index: build.xml
===================================================================
<?xml version='1.0' ?>
<project name="antlib" default="all">
<property name='orig' location='../../..' />
<property name='orig-build' location='${orig}/build' />
<property name='orig-classes' location='${orig-build}/classes' />
<property name='build' location='build' />
<property name='dist' location='dist' />
<property name='classes' location='${build}/classes' />
<property name="debug" value="true" />
<property name="deprecation" value="false" />
<property name="optimize" value="true" />
<target name='init'>
<ant target='build' dir='${orig}' inheritAll='false' />
<mkdir dir='${classes}' />
<copy toDir='${classes}' preservelastmodified='true' >
<fileset dir='${orig-classes}'>
<include name='**' />
<exclude name='org/apache/tools/ant/Project.class' />
<exclude name='org/apache/tools/ant/TaskAdapter.class' />
<exclude name='org/apache/tools/ant/taskdefs/Ant.class' />
</fileset>
</copy>
</target>
<target name='all' depends='init, build' />
<target name='fullbuild' depends='init, compile'>
<ant target='internal_dist' dir='${orig}'>
<property name="build.dir" value="${build}"/>
<property name="dist.dir" value="${dist}"/>
</ant>
</target>
<target name='build' depends='init, compile'>
<ant target='dist-lite' dir='${orig}'>
<property name="build.dir" value="${build}"/>
<property name="dist.dir" value="${dist}"/>
</ant>
</target>
<target name='compile'>
<javac srcdir='src/main' destdir='${classes}'
debug="${debug}"
deprecation="${deprecation}"
optimize="${optimize}">
<include name='**/*.java'/>
</javac>
</target>
<target name='clean'>
<delete dir='${build}' />
</target>
<target name='cleanall' depends='clean'>
<delete dir='${dist}' />
</target>
</project>
1.1
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/Project.java
Index: Project.java
===================================================================
/*
* 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 [EMAIL PROTECTED]
*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Properties;
import java.util.Enumeration;
import java.util.Stack;
import java.lang.reflect.Modifier;
import org.apache.tools.ant.types.DataTypeAdapterTask;
import org.apache.tools.ant.types.FilterSet;
import org.apache.tools.ant.types.FilterSetCollection;
import org.apache.tools.ant.util.FileUtils;
/**
* Central representation of an Ant project. This class defines a
* Ant project with all of it's targets and tasks. It also provides
* the mechanism to kick off a build using a particular target name.
* <p>
* This class also encapsulates methods which allow Files to be refered
* to using abstract path names which are translated to native system
* file paths at runtime as well as defining various project properties.
*
* @author [EMAIL PROTECTED]
*/
public class Project {
public final static int MSG_ERR = 0;
public final static int MSG_WARN = 1;
public final static int MSG_INFO = 2;
public final static int MSG_VERBOSE = 3;
public final static int MSG_DEBUG = 4;
// private set of constants to represent the state
// of a DFS of the Target dependencies
private final static String VISITING = "VISITING";
private final static String VISITED = "VISITED";
private static String javaVersion;
public final static String JAVA_1_0 = "1.0";
public final static String JAVA_1_1 = "1.1";
public final static String JAVA_1_2 = "1.2";
public final static String JAVA_1_3 = "1.3";
public final static String JAVA_1_4 = "1.4";
public final static String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
public final static String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
private String name;
private String description;
private Hashtable properties = new Hashtable();
private Hashtable userProperties = new Hashtable();
private Hashtable references = new Hashtable();
private String defaultTarget;
// private Hashtable dataClassDefinitions = new Hashtable();
// private Hashtable taskClassDefinitions = new Hashtable();
private Hashtable createdTasks = new Hashtable();
private Hashtable targets = new Hashtable();
private FilterSet globalFilterSet = new FilterSet();
private FilterSetCollection globalFilters = new
FilterSetCollection(globalFilterSet);
private File baseDir;
private Vector listeners = new Vector();
/** The Ant core classloader - may be null if using system loader */
private ClassLoader coreLoader = null;
/** Records the latest task on a thread */
private Hashtable threadTasks = new Hashtable();
/** Store symbol tables */
private SymbolTable symbols;
static {
// Determine the Java version by looking at available classes
// java.lang.StrictMath was introduced in JDK 1.3
// java.lang.ThreadLocal was introduced in JDK 1.2
// java.lang.Void was introduced in JDK 1.1
// Count up version until a NoClassDefFoundError ends the try
try {
javaVersion = JAVA_1_0;
Class.forName("java.lang.Void");
javaVersion = JAVA_1_1;
Class.forName("java.lang.ThreadLocal");
javaVersion = JAVA_1_2;
Class.forName("java.lang.StrictMath");
javaVersion = JAVA_1_3;
Class.forName("java.lang.CharSequence");
javaVersion = JAVA_1_4;
} catch (ClassNotFoundException cnfe) {
// swallow as we've hit the max class version that
// we have
}
}
private FileUtils fileUtils;
/**
* create a new ant project
*/
public Project() {
fileUtils = FileUtils.newFileUtils();
symbols = new SymbolTable();
symbols.setProject(this);
}
/**
* create a new ant project that inherits from caler project
* @param p the calling project
*/
public Project(Project p) {
fileUtils = FileUtils.newFileUtils();
symbols = new SymbolTable(p);
symbols.setProject(this);
}
/**
* Initialise the project.
*
* This involves setting the default task definitions and loading the
* system properties.
*/
public void init() throws BuildException {
setJavaVersionProperty();
// Initialize simbol table just in case
symbols.addRole("task", TaskContainer.class, TaskAdapter.class);
symbols.addRole("datatype", TaskContainer.class,
DataTypeAdapterTask.class);
String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
try {
Properties props = new Properties();
InputStream in = this.getClass().getResourceAsStream(defs);
if (in == null) {
throw new BuildException("Can't load default task list");
}
props.load(in);
in.close();
Enumeration enum = props.propertyNames();
while (enum.hasMoreElements()) {
String key = (String) enum.nextElement();
String value = props.getProperty(key);
try {
Class taskClass = Class.forName(value);
addTaskDefinition(key, taskClass);
} catch (NoClassDefFoundError ncdfe) {
log("Could not load a dependent class (" +
ncdfe.getMessage() + ") for task " + key, MSG_DEBUG);
} catch (ClassNotFoundException cnfe) {
log("Could not load class ("
+ value + ") for task " + key, MSG_DEBUG);
}
}
} catch (IOException ioe) {
throw new BuildException("Can't load default task list");
}
String dataDefs = "/org/apache/tools/ant/types/defaults.properties";
try{
Properties props = new Properties();
InputStream in = this.getClass().getResourceAsStream(dataDefs);
if (in == null) {
throw new BuildException("Can't load default datatype list");
}
props.load(in);
in.close();
Enumeration enum = props.propertyNames();
while (enum.hasMoreElements()) {
String key = (String) enum.nextElement();
String value = props.getProperty(key);
try {
Class dataClass = Class.forName(value);
addDataTypeDefinition(key, dataClass);
} catch (NoClassDefFoundError ncdfe) {
// ignore...
} catch (ClassNotFoundException cnfe) {
// ignore...
}
}
} catch (IOException ioe) {
throw new BuildException("Can't load default datatype list");
}
setSystemProperties();
}
public void setCoreLoader(ClassLoader coreLoader) {
this.coreLoader = coreLoader;
}
public ClassLoader getCoreLoader() {
return coreLoader;
}
public void addBuildListener(BuildListener listener) {
listeners.addElement(listener);
}
public void removeBuildListener(BuildListener listener) {
listeners.removeElement(listener);
}
public Vector getBuildListeners() {
return listeners;
}
/**
* Get the symbols associated with this project.
*/
public SymbolTable getSymbols() {
return symbols;
}
/**
* Output a message to the log with the default log level
* of MSG_INFO
* @param msg text to log
*/
public void log(String msg) {
log(msg, MSG_INFO);
}
/**
* Output a message to the log with the given log level
* and an event scope of project
* @param msg text to log
* @param msgLevel level to log at
*/
public void log(String msg, int msgLevel) {
fireMessageLogged(this, msg, msgLevel);
}
/**
* Output a message to the log with the given log level
* and an event scope of a task
* @param task task to use in the log
* @param msg text to log
* @param msgLevel level to log at
*/
public void log(Task task, String msg, int msgLevel) {
fireMessageLogged(task, msg, msgLevel);
}
/**
* Output a message to the log with the given log level
* and an event scope of a target
* @param target target to use in the log
* @param msg text to log
* @param msgLevel level to log at
*/
public void log(Target target, String msg, int msgLevel) {
fireMessageLogged(target, msg, msgLevel);
}
public FilterSet getGlobalFilterSet() {
return globalFilterSet;
}
/**
* set a property. Any existing property of the same name
* is overwritten, unless it is a user property.
* @param name name of property
* @param value new value of the property
*/
public void setProperty(String name, String value) {
// command line properties take precedence
if (null != userProperties.get(name)) {
log("Override ignored for user property " + name, MSG_VERBOSE);
return;
}
if (null != properties.get(name)) {
log("Overriding previous definition of property " + name,
MSG_VERBOSE);
}
log("Setting project property: " + name + " -> " +
value, MSG_DEBUG);
properties.put(name, value);
}
/**
* set a property. An existing property of the same name
* will not be overwritten.
* @param name name of property
* @param value new value of the property
* @since 1.5
*/
public void setNewProperty(String name, String value) {
if (null != properties.get(name)) {
log("Override ignored for property " + name, MSG_VERBOSE);
return;
}
log("Setting project property: " + name + " -> " +
value, MSG_DEBUG);
properties.put(name, value);
}
/**
* set a user property, which can not be overwritten by
* set/unset property calls
* @see #setProperty(String,String)
*/
public void setUserProperty(String name, String value) {
log("Setting ro project property: " + name + " -> " +
value, MSG_DEBUG);
userProperties.put(name, value);
properties.put(name, value);
}
/**
* Allows Project and subclasses to set a property unless its
* already defined as a user property. There are a few cases
* internally to Project that need to do this currently.
*/
private void setPropertyInternal(String name, String value) {
if (null != userProperties.get(name)) {
return;
}
properties.put(name, value);
}
/**
* query a property.
* @param name the name of the property
* @return the property value, or null for no match
*/
public String getProperty(String name) {
if (name == null) {
return null;
}
String property = (String) properties.get(name);
return property;
}
/**
* Replace ${} style constructions in the given value with the
* string value of the corresponding data types.
*
* @param value the string to be scanned for property references.
*/
public String replaceProperties(String value)
throws BuildException {
return ProjectHelper.replaceProperties(this, value, properties);
}
/**
* query a user property.
* @param name the name of the property
* @return the property value, or null for no match
*/
public String getUserProperty(String name) {
if (name == null) {
return null;
}
String property = (String) userProperties.get(name);
return property;
}
/**
* get a copy of the property hashtable
* @return the hashtable containing all properties, user included
*/
public Hashtable getProperties() {
Hashtable propertiesCopy = new Hashtable();
Enumeration e = properties.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
Object value = properties.get(name);
propertiesCopy.put(name, value);
}
return propertiesCopy;
}
/**
* get a copy of the user property hashtable
* @return the hashtable user properties only
*/
public Hashtable getUserProperties() {
Hashtable propertiesCopy = new Hashtable();
Enumeration e = userProperties.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
Object value = properties.get(name);
propertiesCopy.put(name, value);
}
return propertiesCopy;
}
/**
* set the default target of the project
* @deprecated, use setDefault
* @see #setDefault(String)
*/
public void setDefaultTarget(String defaultTarget) {
this.defaultTarget = defaultTarget;
}
/**
* get the default target of the project
* @return default target or null
*/
public String getDefaultTarget() {
return defaultTarget;
}
/**
* set the default target of the project
* XML attribute name.
*/
public void setDefault(String defaultTarget) {
this.defaultTarget = defaultTarget;
}
/**
* ant xml property. Set the project name as
* an attribute of this class, and of the property
* ant.project.name
*/
public void setName(String name) {
setUserProperty("ant.project.name", name);
this.name = name;
}
/** get the project name
* @return name string
*/
public String getName() {
return name;
}
/** set the project description
* @param description text
*/
public void setDescription(String description) {
this.description = description;
}
/** get the project description
* @return description or null if no description has been set
*/
public String getDescription() {
return description;
}
/** @deprecated */
public void addFilter(String token, String value) {
if (token == null) {
return;
}
globalFilterSet.addFilter(new FilterSet.Filter(token, value));
}
/** @deprecated */
public Hashtable getFilters() {
// we need to build the hashtable dynamically
return globalFilterSet.getFilterHash();
}
/**
* match basedir attribute in xml
* @param baseD project base directory.
* @throws BuildException if the directory was invalid
*/
public void setBasedir(String baseD) throws BuildException {
setBaseDir(new File(baseD));
}
/**
* set the base directory; XML attribute.
* checks for the directory existing and being a directory type
* @param baseDir project base directory.
* @throws BuildException if the directory was invalid
*/
public void setBaseDir(File baseDir) throws BuildException {
baseDir = fileUtils.normalize(baseDir.getAbsolutePath());
if (!baseDir.exists()) {
throw new BuildException("Basedir " + baseDir.getAbsolutePath() +
" does not exist");
}
if (!baseDir.isDirectory()) {
throw new BuildException("Basedir " + baseDir.getAbsolutePath() +
" is not a directory");
}
this.baseDir = baseDir;
setPropertyInternal( "basedir", this.baseDir.getPath());
String msg = "Project base dir set to: " + this.baseDir;
log(msg, MSG_VERBOSE);
}
/**
* get the base directory of the project as a file object
* @return the base directory. If this is null, then the base
* dir is not valid
*/
public File getBaseDir() {
if (baseDir == null) {
try {
setBasedir(".");
} catch (BuildException ex) {
ex.printStackTrace();
}
}
return baseDir;
}
/**
* static query of the java version
* @return something like "1.1" or "1.3"
*/
public static String getJavaVersion() {
return javaVersion;
}
/**
* set the ant.java.version property, also tests for
* unsupported JVM versions, prints the verbose log messages
* @throws BuildException if this Java version is not supported
*/
public void setJavaVersionProperty() throws BuildException {
setPropertyInternal("ant.java.version", javaVersion);
// sanity check
if (javaVersion == JAVA_1_0) {
throw new BuildException("Ant cannot work on Java 1.0");
}
log("Detected Java version: " + javaVersion + " in: " +
System.getProperty("java.home"), MSG_VERBOSE);
log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
}
/**
* turn all the system properties into ant properties.
* user properties still override these values
*/
public void setSystemProperties() {
Properties systemP = System.getProperties();
Enumeration e = systemP.keys();
while (e.hasMoreElements()) {
Object name = e.nextElement();
String value = systemP.get(name).toString();
this.setPropertyInternal(name.toString(), value);
}
}
/**
* add a new task definition, complain if there is an overwrite attempt
* @param taskName name of the task
* @param taskClass full task classname
* @throws BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail.
*/
public void addTaskDefinition(String taskName, Class taskClass)
throws BuildException {
Class old = symbols.add("task", taskName, taskClass);
if (null != old && !old.equals(taskClass)) {
invalidateCreatedTasks(taskName);
}
String msg =
" +User task: " + taskName + " " + taskClass.getName();
log(msg, MSG_DEBUG);
checkTaskClass(taskClass);
}
/**
* Checks a class, whether it is suitable for serving as ant task.
* @throws BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail.
*/
public void checkTaskClass(final Class taskClass) throws BuildException {
if( !Task.class.isAssignableFrom(taskClass) ) {
TaskAdapter.checkTaskClass(taskClass, this);
}
}
/**
* get the current task definition hashtable
*/
public Hashtable getTaskDefinitions() {
return symbols.getTaskDefinitions();
}
/**
* add a new datatype
* @param typeName name of the datatype
* @param typeClass full datatype classname
*/
public void addDataTypeDefinition(String typeName, Class typeClass) {
symbols.add("datatype", typeName, typeClass);
String msg =
" +User datatype: " + typeName + " " + typeClass.getName();
log(msg, MSG_DEBUG);
}
/**
* get the current task definition hashtable
*/
public Hashtable getDataTypeDefinitions() {
return symbols.getDataTypeDefinitions();
}
/**
* This call expects to add a <em>new</em> Target.
* @param target is the Target to be added to the current
* Project.
* @exception BuildException if the Target already exists
* in the project.
* @see Project#addOrReplaceTarget to replace existing Targets.
*/
public void addTarget(Target target) {
String name = target.getName();
if (targets.get(name) != null) {
throw new BuildException("Duplicate target: `"+name+"'");
}
addOrReplaceTarget(name, target);
}
/**
* This call expects to add a <em>new</em> Target.
* @param target is the Target to be added to the current
* Project.
* @param targetName is the name to use for the Target
* @exception BuildException if the Target already exists
* in the project.
* @see Project#addOrReplaceTarget to replace existing Targets.
*/
public void addTarget(String targetName, Target target)
throws BuildException {
if (targets.get(targetName) != null) {
throw new BuildException("Duplicate target: `"+targetName+"'");
}
addOrReplaceTarget(targetName, target);
}
/**
* @param target is the Target to be added or replaced in
* the current Project.
*/
public void addOrReplaceTarget(Target target) {
addOrReplaceTarget(target.getName(), target);
}
/**
* @param target is the Target to be added/replaced in
* the current Project.
* @param targetName is the name to use for the Target
*/
public void addOrReplaceTarget(String targetName, Target target) {
String msg = " +Target: " + targetName;
log(msg, MSG_DEBUG);
target.setProject(this);
targets.put(targetName, target);
}
/**
* get the target hashtable
* @return hashtable, the contents of which can be cast to Target
*/
public Hashtable getTargets() {
return targets;
}
/**
* create a new task instance
* @param taskType name of the task
* @throws BuildException when task creation goes bad
* @return null if the task name is unknown
*/
public Task createTask(String taskType) throws BuildException {
Class c = symbols.get("task", taskType);
if (c == null) {
return null;
}
try {
Object o = c.newInstance();
Task task = null;
if( o instanceof Task ) {
task=(Task)o;
} else {
// "Generic" Bean - use the setter pattern
// and an Adapter
TaskAdapter taskA=new TaskAdapter();
taskA.setProxy( o );
task=taskA;
}
task.setProject(this);
task.setTaskType(taskType);
// set default value, can be changed by the user
task.setTaskName(taskType);
String msg = " +Task: " + taskType;
log (msg, MSG_DEBUG);
addCreatedTask(taskType, task);
return task;
} catch (Throwable t) {
String msg = "Could not create task of type: "
+ taskType + " due to " + t;
throw new BuildException(msg, t);
}
}
/**
* Keep a record of all tasks that have been created so that they
* can be invalidated if a taskdef overrides the definition.
*/
private void addCreatedTask(String type, Task task) {
synchronized (createdTasks) {
Vector v = (Vector) createdTasks.get(type);
if (v == null) {
v = new Vector();
createdTasks.put(type, v);
}
v.addElement(task);
}
}
/**
* Mark tasks as invalid which no longer are of the correct type
* for a given taskname.
*/
private void invalidateCreatedTasks(String type) {
synchronized (createdTasks) {
Vector v = (Vector) createdTasks.get(type);
if (v != null) {
Enumeration enum = v.elements();
while (enum.hasMoreElements()) {
Task t = (Task) enum.nextElement();
t.markInvalid();
}
v.removeAllElements();
createdTasks.remove(type);
}
}
}
/**
* create a new DataType instance
* @param typeName name of the datatype
* @throws BuildException when datatype creation goes bad
* @return null if the datatype name is unknown
*/
public Object createDataType(String typeName) throws BuildException {
Class c = symbols.get("datatype", typeName);
if (c == null) {
return null;
}
try {
java.lang.reflect.Constructor ctor = null;
boolean noArg = false;
// DataType can have a "no arg" constructor or take a single
// Project argument.
try {
ctor = c.getConstructor(new Class[0]);
noArg = true;
} catch (NoSuchMethodException nse) {
ctor = c.getConstructor(new Class[] {Project.class});
noArg = false;
}
Object o = null;
if (noArg) {
o = ctor.newInstance(new Object[0]);
} else {
o = ctor.newInstance(new Object[] {this});
}
if (o instanceof ProjectComponent) {
((ProjectComponent)o).setProject(this);
}
String msg = " +DataType: " + typeName;
log (msg, MSG_DEBUG);
return o;
} catch (java.lang.reflect.InvocationTargetException ite) {
Throwable t = ite.getTargetException();
String msg = "Could not create datatype of type: "
+ typeName + " due to " + t;
throw new BuildException(msg, t);
} catch (Throwable t) {
String msg = "Could not create datatype of type: "
+ typeName + " due to " + t;
throw new BuildException(msg, t);
}
}
/**
* execute the sequence of targets, and the targets they depend on
* @param Vector a vector of target name strings
* @throws BuildException if the build failed
*/
public void executeTargets(Vector targetNames) throws BuildException {
Throwable error = null;
for (int i = 0; i < targetNames.size(); i++) {
executeTarget((String)targetNames.elementAt(i));
}
}
public void demuxOutput(String line, boolean isError) {
Task task = (Task)threadTasks.get(Thread.currentThread());
if (task == null) {
fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO);
}
else {
if (isError) {
task.handleErrorOutput(line);
}
else {
task.handleOutput(line);
}
}
}
/**
* execute the targets and any targets it depends on
* @param targetName the target to execute
* @throws BuildException if the build failed
*/
public void executeTarget(String targetName) throws BuildException {
// sanity check ourselves, if we've been asked to build nothing
// then we should complain
if (targetName == null) {
String msg = "No target specified";
throw new BuildException(msg);
}
// Sort the dependency tree, and run everything from the
// beginning until we hit our targetName.
// Sorting checks if all the targets (and dependencies)
// exist, and if there is any cycle in the dependency
// graph.
Vector sortedTargets = topoSort(targetName, targets);
int curidx = 0;
Target curtarget;
do {
curtarget = (Target) sortedTargets.elementAt(curidx++);
curtarget.performTasks();
} while (!curtarget.getName().equals(targetName));
}
/**
* Return the canonical form of fileName as an absolute path.
*
* <p>If fileName is a relative file name, resolve it relative to
* rootDir.</p>
*
* @deprecated
*/
public File resolveFile(String fileName, File rootDir) {
return fileUtils.resolveFile(rootDir, fileName);
}
public File resolveFile(String fileName) {
return fileUtils.resolveFile(baseDir, fileName);
}
/**
* Translate a path into its native (platform specific) format.
* <p>
* This method uses the PathTokenizer class to separate the input path
* into its components. This handles DOS style paths in a relatively
* sensible way. The file separators are then converted to their platform
* specific versions.
*
* @param to_process the path to be converted
*
* @return the native version of to_process or
* an empty string if to_process is null or empty
*/
public static String translatePath(String to_process) {
if ( to_process == null || to_process.length() == 0 ) {
return "";
}
StringBuffer path = new StringBuffer(to_process.length() + 50);
PathTokenizer tokenizer = new PathTokenizer(to_process);
while (tokenizer.hasMoreTokens()) {
String pathComponent = tokenizer.nextToken();
pathComponent = pathComponent.replace('/', File.separatorChar);
pathComponent = pathComponent.replace('\\', File.separatorChar);
if (path.length() != 0) {
path.append(File.pathSeparatorChar);
}
path.append(pathComponent);
}
return path.toString();
}
/**
* Convienence method to copy a file from a source to a destination.
* No filtering is performed.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(String sourceFile, String destFile) throws
IOException {
fileUtils.copyFile(sourceFile, destFile);
}
/**
* Convienence method to copy a file from a source to a destination
* specifying if token filtering must be used.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(String sourceFile, String destFile, boolean
filtering)
throws IOException {
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters :
null);
}
/**
* Convienence method to copy a file from a source to a
* destination specifying if token filtering must be used and if
* source files may overwrite newer destination files.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(String sourceFile, String destFile, boolean
filtering,
boolean overwrite) throws IOException {
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters :
null, overwrite);
}
/**
* Convienence method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* source files may overwrite newer destination files and the
* last modified time of <code>destFile</code> file should be made equal
* to the last modified time of <code>sourceFile</code>.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(String sourceFile, String destFile, boolean
filtering,
boolean overwrite, boolean preserveLastModified)
throws IOException {
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters :
null,
overwrite, preserveLastModified);
}
/**
* Convienence method to copy a file from a source to a destination.
* No filtering is performed.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(File sourceFile, File destFile) throws IOException {
fileUtils.copyFile(sourceFile, destFile);
}
/**
* Convienence method to copy a file from a source to a destination
* specifying if token filtering must be used.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(File sourceFile, File destFile, boolean filtering)
throws IOException {
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters :
null);
}
/**
* Convienence method to copy a file from a source to a
* destination specifying if token filtering must be used and if
* source files may overwrite newer destination files.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(File sourceFile, File destFile, boolean filtering,
boolean overwrite) throws IOException {
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters :
null, overwrite);
}
/**
* Convienence method to copy a file from a source to a
* destination specifying if token filtering must be used, if
* source files may overwrite newer destination files and the
* last modified time of <code>destFile</code> file should be made equal
* to the last modified time of <code>sourceFile</code>.
*
* @throws IOException
*
* @deprecated
*/
public void copyFile(File sourceFile, File destFile, boolean filtering,
boolean overwrite, boolean preserveLastModified)
throws IOException {
fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters :
null,
overwrite, preserveLastModified);
}
/**
* Calls File.setLastModified(long time) in a Java 1.1 compatible way.
*
* @deprecated
*/
public void setFileLastModified(File file, long time) throws
BuildException {
if (getJavaVersion() == JAVA_1_1) {
log("Cannot change the modification time of " + file
+ " in JDK 1.1", Project.MSG_WARN);
return;
}
fileUtils.setFileLastModified(file, time);
log("Setting modification time for " + file, MSG_VERBOSE);
}
/**
* returns the boolean equivalent of a string, which is considered true
* if either "on", "true", or "yes" is found, ignoring case.
*/
public static boolean toBoolean(String s) {
return (s.equalsIgnoreCase("on") ||
s.equalsIgnoreCase("true") ||
s.equalsIgnoreCase("yes"));
}
/**
* Topologically sort a set of Targets.
* @param root is the (String) name of the root Target. The sort is
* created in such a way that the sequence of Targets uptil the root
* target is the minimum possible such sequence.
* @param targets is a Hashtable representing a "name to Target" mapping
* @return a Vector of Strings with the names of the targets in
* sorted order.
* @exception BuildException if there is a cyclic dependency among the
* Targets, or if a Target does not exist.
*/
public final Vector topoSort(String root, Hashtable targets)
throws BuildException {
Vector ret = new Vector();
Hashtable state = new Hashtable();
Stack visiting = new Stack();
// We first run a DFS based sort using the root as the starting node.
// This creates the minimum sequence of Targets to the root node.
// We then do a sort on any remaining unVISITED targets.
// This is unnecessary for doing our build, but it catches
// circular dependencies or missing Targets on the entire
// dependency tree, not just on the Targets that depend on the
// build Target.
tsort(root, targets, state, visiting, ret);
log("Build sequence for target `"+root+"' is "+ret, MSG_VERBOSE);
for (Enumeration en=targets.keys(); en.hasMoreElements();) {
String curTarget = (String)(en.nextElement());
String st = (String) state.get(curTarget);
if (st == null) {
tsort(curTarget, targets, state, visiting, ret);
}
else if (st == VISITING) {
throw new RuntimeException("Unexpected node in visiting
state: "+curTarget);
}
}
log("Complete build sequence is "+ret, MSG_VERBOSE);
return ret;
}
// one step in a recursive DFS traversal of the Target dependency tree.
// - The Hashtable "state" contains the state (VISITED or VISITING or
null)
// of all the target names.
// - The Stack "visiting" contains a stack of target names that are
// currently on the DFS stack. (NB: the target names in "visiting" are
// exactly the target names in "state" that are in the VISITING state.)
// 1. Set the current target to the VISITING state, and push it onto
// the "visiting" stack.
// 2. Throw a BuildException if any child of the current node is
// in the VISITING state (implies there is a cycle.) It uses the
// "visiting" Stack to construct the cycle.
// 3. If any children have not been VISITED, tsort() the child.
// 4. Add the current target to the Vector "ret" after the children
// have been visited. Move the current target to the VISITED state.
// "ret" now contains the sorted sequence of Targets upto the current
// Target.
private final void tsort(String root, Hashtable targets,
Hashtable state, Stack visiting,
Vector ret)
throws BuildException {
state.put(root, VISITING);
visiting.push(root);
Target target = (Target)(targets.get(root));
// Make sure we exist
if (target == null) {
StringBuffer sb = new StringBuffer("Target `");
sb.append(root);
sb.append("' does not exist in this project. ");
visiting.pop();
if (!visiting.empty()) {
String parent = (String)visiting.peek();
sb.append("It is used from target `");
sb.append(parent);
sb.append("'.");
}
throw new BuildException(new String(sb));
}
for (Enumeration en=target.getDependencies(); en.hasMoreElements();) {
String cur = (String) en.nextElement();
String m=(String)state.get(cur);
if (m == null) {
// Not been visited
tsort(cur, targets, state, visiting, ret);
}
else if (m == VISITING) {
// Currently visiting this node, so have a cycle
throw makeCircularException(cur, visiting);
}
}
String p = (String) visiting.pop();
if (root != p) {
throw new RuntimeException("Unexpected internal error: expected
to pop "+root+" but got "+p);
}
state.put(root, VISITED);
ret.addElement(target);
}
private static BuildException makeCircularException(String end, Stack
stk) {
StringBuffer sb = new StringBuffer("Circular dependency: ");
sb.append(end);
String c;
do {
c = (String)stk.pop();
sb.append(" <- ");
sb.append(c);
} while(!c.equals(end));
return new BuildException(new String(sb));
}
public void addReference(String name, Object value) {
if (null != references.get(name)) {
log("Overriding previous definition of reference to " + name,
MSG_WARN);
}
log("Adding reference: " + name + " -> " + value, MSG_DEBUG);
references.put(name,value);
}
public Hashtable getReferences() {
return references;
}
/**
* @return The object with the "id" key.
*/
public Object getReference(String key) {
return references.get(key);
}
/**
* send build started event to the listeners
*/
protected void fireBuildStarted() {
BuildEvent event = new BuildEvent(this);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.buildStarted(event);
}
}
/**
* send build finished event to the listeners
* @param exception exception which indicates failure if not null
*/
protected void fireBuildFinished(Throwable exception) {
BuildEvent event = new BuildEvent(this);
event.setException(exception);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.buildFinished(event);
}
}
/**
* send target started event to the listeners
*/
protected void fireTargetStarted(Target target) {
BuildEvent event = new BuildEvent(target);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.targetStarted(event);
}
}
/**
* send build finished event to the listeners
* @param exception exception which indicates failure if not null
*/
protected void fireTargetFinished(Target target, Throwable exception) {
BuildEvent event = new BuildEvent(target);
event.setException(exception);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.targetFinished(event);
}
}
protected void fireTaskStarted(Task task) {
// register this as the current task on the current thread.
threadTasks.put(Thread.currentThread(), task);
BuildEvent event = new BuildEvent(task);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.taskStarted(event);
}
}
protected void fireTaskFinished(Task task, Throwable exception) {
threadTasks.remove(Thread.currentThread());
System.out.flush();
System.err.flush();
BuildEvent event = new BuildEvent(task);
event.setException(exception);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.taskFinished(event);
}
}
private void fireMessageLoggedEvent(BuildEvent event, String message, int
priority) {
event.setMessage(message, priority);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.messageLogged(event);
}
}
protected void fireMessageLogged(Project project, String message, int
priority) {
BuildEvent event = new BuildEvent(project);
fireMessageLoggedEvent(event, message, priority);
}
protected void fireMessageLogged(Target target, String message, int
priority) {
BuildEvent event = new BuildEvent(target);
fireMessageLoggedEvent(event, message, priority);
}
protected void fireMessageLogged(Task task, String message, int priority)
{
BuildEvent event = new BuildEvent(task);
fireMessageLoggedEvent(event, message, priority);
}
}
1.1
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/RoleAdapter.java
Index: RoleAdapter.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 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 [EMAIL PROTECTED]
*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;
public interface RoleAdapter {
/**
* Set the object being adapted.
* @param o the object being adapted
*/
public void setProxy(Object o);
/**
* Get the object adapted by this class.
* @return the object being adapted, if any.
*/
public Object getProxy();
}
1.1
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/SymbolTable.java
Index: SymbolTable.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 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 [EMAIL PROTECTED]
*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import org.apache.tools.ant.types.Path;
public class SymbolTable {
/** Parent symbol table */
private SymbolTable parentTable;
/** Project associated with this symbol table */
private Project project;
/** The table of roles available to this Project */
private Hashtable roles = new Hashtable();
/** The table of loaders active on this Project */
private Hashtable loaders = new Hashtable();
/**
* Table of per role definitions.
*/
private Hashtable defs = new Hashtable();
/**
* Parameters for checking adapters.
*/
private static final Class[] CHECK_ADAPTER_PARAMS =
new Class[]{Class.class, Project.class};
/**
* Create a top level Symbol table.
*/
public SymbolTable() {
}
/**
* Create a symbol table inheriting the definitions
* from that defined in the calling Project.
* @param p the calling project
*/
public SymbolTable(Project p) {
parentTable = p.getSymbols();
}
/**
* Set the project associated with this symbol table.
* @param p the project for this symbol table
*/
public void setProject(Project p) {
this.project = p;
}
/**
* Find all the roles supported by a Class
* on this symbol table.
* @param clz the class to analyze
* @return an array of roles supported by the class
*/
public String[] findRoles(final Class clz) {
Vector list = new Vector();
findRoles(clz, list);
return (String[])list.toArray(new String[list.size()]);
}
/**
* Collect the roles for the class
* @param clz the class being inspected
* @param list the roles collected up to this point
*/
private void findRoles(final Class clz, Vector list) {
for (Enumeration e = roles.keys(); e.hasMoreElements();) {
String role = (String) e.nextElement();
if (((Role) roles.get(role)).isImplementedBy(clz)) {
list.addElement(role);
}
}
if (parentTable != null) findRoles(clz, list);
}
/**
* Get the Role definition
* @param role the name of the role
* @return the method used to support objects on this role
*/
public Role getRole(String role) {
Role r = (Role) roles.get(role);
if (r == null && parentTable != null) {
return parentTable.getRole(role);
}
return r;
}
/**
* Add a new role definition to this project.
* @param role the name of the role
* @param rclz the interface used to specify support for the role.
* @param aclz the optional adapter class
* @return whether the role replaced a different definition
*/
public boolean addRole(String role, Class rclz, Class aclz) {
// Check if role already declared
Role old = getRole(role);
if (old != null && old.isSameAsFor(rclz, aclz)
) {
project.log("Ignoring override for role " + role
+ ", it is already defined by the same definition.",
project.MSG_VERBOSE);
return false;
}
// Role interfaces should only contain one method
roles.put(role, new Role(rclz, aclz));
return (old != null);
}
/**
* Verify if the interface is valid.
* @param clz the interface to validate
* @return the method defined by the interface
*/
private Method validInterface(Class clz) {
Method m[] = clz.getDeclaredMethods();
if (m.length == 1
&& java.lang.Void.TYPE.equals(m[0].getReturnType())) {
Class args[] = m[0].getParameterTypes();
if (args.length == 1
&& !java.lang.String.class.equals(args[0])
&& !args[0].isArray()
&& !args[0].isPrimitive()) {
return m[0];
}
else {
throw new BuildException("Invalid role interface method in: "
+ clz.getName());
}
}
else {
throw new BuildException("More than one method on role interface");
}
}
/**
* Verify if the adapter is valid with respect to the interface.
* @param clz the class adapter to validate
* @param mtd the method whose only argument must match
* @return the static method to use for validating adaptees
*/
private Method validAdapter(Class clz, Method mtd) {
if (clz == null) return null;
checkClass(clz);
if (!mtd.getParameterTypes()[0].isAssignableFrom(clz)) {
String msg = "Adapter " + clz.getName() +
" is incompatible with role interface " +
mtd.getDeclaringClass().getName();
throw new BuildException(msg);
}
String msg = "Class " + clz.getName() + " is not an adapter: ";
if (!RoleAdapter.class.isAssignableFrom(clz)) {
throw new BuildException(msg + "does not implement RoleAdapter");
}
try {
Method chk = clz.getMethod("checkClass", CHECK_ADAPTER_PARAMS);
if (!Modifier.isStatic(chk.getModifiers())) {
throw new BuildException(msg + "checkClass() is not static");
}
return chk;
}
catch(NoSuchMethodException nme){
throw new BuildException(msg + "checkClass() not found", nme);
}
}
/**
* Get the specified loader for the project.
* @param name the name of the loader
* @return the corresponding ANT classloader
*/
private AntClassLoader getLoader(String name) {
AntClassLoader cl = (AntClassLoader) loaders.get(name);
if (cl == null && parentTable != null) {
return parentTable.getLoader(name);
}
return cl;
}
/**
* Add the specified class-path to a loader.
* If the loader is defined in an ancestor project then a new
* classloader inheritin from the one already existing
* will be created, otherwise the path willbe added to the existing
* ClassLoader.
* @param name the name of the loader to use.
* @param clspath the path to be added to the classloader
*/
public ClassLoader addToLoader(String name, Path clspath) {
// Find if the loader is already defined in the current project
AntClassLoader cl = (AntClassLoader) loaders.get(name);
if (cl == null) {
// Is it inherited from the calling project
if (parentTable != null) {
cl = parentTable.getLoader(name);
}
cl = new AntClassLoader(cl, project, clspath, true);
loaders.put(name, cl);
}
else {
// Add additional path to the existing definition
String[] pathElements = clspath.list();
for (int i = 0; i < pathElements.length; ++i) {
try {
cl.addPathElement(pathElements[i]);
}
catch (BuildException e) {
// ignore path elements invalid relative to the project
}
}
}
return cl;
}
/**
* Add a new type of element to a role.
* @param role the role for this Class.
* @param name the name of the element for this Class
* @param clz the Class being declared
* @return the old definition
*/
public Class add(String role, String name, Class clz) {
// Find the role definition
Role r = getRole(role);
if (r == null) {
throw new BuildException("Unknown role: " + role);
}
// Check if it is already defined
Class old = get(role, name);
if (old != null) {
if (old.equals(clz)) {
project.log("Ignoring override for "+ role + " " + name
+ ", it is already defined by the same class.",
project.MSG_VERBOSE);
return old;
}
else {
project.log("Trying to override old definition of " +
role + " " + name,
project.MSG_WARN);
}
}
checkClass(clz);
// Check that the Class is compatible with the role definition
r.verifyAdaptability(role, clz);
// Record the new type
Hashtable defTable = (Hashtable)defs.get(role);
if (defTable == null) {
defTable = new Hashtable();
defs.put(role, defTable);
}
defTable.put(name, clz);
return old;
}
/**
* Checks a class, whether it is suitable for serving in ANT.
* @throws BuildException and logs as Project.MSG_ERR for
* conditions, that will cause execution to fail.
*/
void checkClass(final Class clz)
throws BuildException {
if(!Modifier.isPublic(clz.getModifiers())) {
final String message = clz + " is not public";
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
if(Modifier.isAbstract(clz.getModifiers())) {
final String message = clz + " is abstract";
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
try {
// Class can have a "no arg" constructor or take a single
// Project argument.
// don't have to check for public, since
// getConstructor finds public constructors only.
try {
clz.getConstructor(new Class[0]);
} catch (NoSuchMethodException nse) {
clz.getConstructor(new Class[] {Project.class});
}
} catch(NoSuchMethodException e) {
final String message =
"No valid public constructor in " + clz;
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
}
/**
* Get the class in the role identified with the element name.
* @param role the role to look into.
* @param name the name of the element to sea
* @return the Class implementation
*/
public Class get(String role, String name) {
Hashtable defTable = (Hashtable)defs.get(role);
if (defTable != null) {
Class clz = (Class)defTable.get(name);
if (clz != null) return clz;
}
if (parentTable != null) {
return parentTable.get(role, name);
}
return null;
}
/**
* Get a Hashtable that is usable for manipulating Tasks,
* @return a Hashtable that delegates to the Symbol table.
*/
public Hashtable getTaskDefinitions() {
return new SymbolHashtable("task");
}
/**
* Get a Hashtable that is usable for manipulating Datatypes,
* @return a Hashtable that delegates to the Symbol table.
*/
public Hashtable getDataTypeDefinitions() {
return new SymbolHashtable("datatype");
}
/**
* Hashtable implementation that delegates
* the search operations to the Symbol table
*/
private class SymbolHashtable extends Hashtable {
final String role;
SymbolHashtable(String role) {
this.role = role;
}
public synchronized Object put(Object key, Object value) {
return SymbolTable.this.add(role, (String) key, (Class) value);
}
public synchronized Object get(Object key) {
return SymbolTable.this.get(role, (String)key);
}
}
/**
* The definition of a role
*/
public class Role {
private Method interfaceMethod;
private Method adapterVerifier;
/**
* Creates a new Role object
* @param roleClz the class that defines the role
* @param adapterClz the class for the adapter, or null if none
*/
Role(Class roleClz, Class adapterClz) {
interfaceMethod = validInterface(roleClz);
adapterVerifier = validAdapter(adapterClz, interfaceMethod);
}
/**
* Get the method used to set on interface
*/
public Method getInterfaceMethod() {
return interfaceMethod;
}
/**
* Instantiate a new adapter for this role.
*/
public RoleAdapter createAdapter() {
if (adapterVerifier == null) return null;
try {
return (RoleAdapter)
adapterVerifier.getDeclaringClass().newInstance();
}
catch(BuildException be) {
throw be;
}
catch(Exception e) {
throw new BuildException(e);
}
}
/**
* Verify if the class can be adapted to use by the role
* @param role the name of the role to verify
* @param clz the class to verify
*/
public void verifyAdaptability(String role, Class clz) {
if (interfaceMethod.getParameterTypes()[0].isAssignableFrom(clz)) {
return;
}
if (adapterVerifier == null) {
String msg = "Class " + clz.getName() +
" incompatible with role: " + role;
throw new BuildException(msg);
}
try {
try {
adapterVerifier.invoke(null,
new Object[]{clz, project});
}
catch (InvocationTargetException ite) {
throw ite.getTargetException();
}
}
catch(BuildException be) { throw be; }
catch(Error err) {throw err; }
catch(Throwable t) {
throw new BuildException(t);
}
}
public boolean isSameAsFor(Class clz, Class pclz) {
return interfaceMethod.getDeclaringClass().equals(clz) &&
((adapterVerifier == null && pclz == null) ||
adapterVerifier.getDeclaringClass().equals(pclz));
}
public boolean isImplementedBy(Class clz) {
return interfaceMethod.getDeclaringClass().isAssignableFrom(clz);
}
}
}
1.1
jakarta-ant/proposal/sandbox/antlib/src/main/org/apache/tools/ant/TaskAdapter.java
Index: TaskAdapter.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 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 [EMAIL PROTECTED]
*
* 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
* <http://www.apache.org/>.
*/
package org.apache.tools.ant;
import java.lang.reflect.Method;
/**
* Use introspection to "adapt" an arbitrary Bean ( not extending Task, but
with similar
* patterns).
*
* @author [EMAIL PROTECTED]
* @author [EMAIL PROTECTED]
*/
public class TaskAdapter extends Task implements RoleAdapter {
Object proxy;
/**
* Checks a class, whether it is suitable to be adapted by TaskAdapter.
*
* Checks conditions only, which are additionally required for a tasks
* adapted by TaskAdapter. Thus, this method should be called by
* [EMAIL PROTECTED] Project#checkTaskClass}.
*
* Throws a BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail.
* Logs other suspicious conditions with Project.MSG_WARN.
*/
public static void checkTaskClass(final Class taskClass, final Project
project) {
// This code is for backward compatibility
checkClass(taskClass, project);
}
/**
* Checks a class, whether it is suitable to be adapted.
*
* Checks conditions only, which are additionally required for a tasks
* adapted by TaskAdapter.
*
* Throws a BuildException and logs as Project.MSG_ERR for
* conditions, that will cause the task execution to fail.
* Logs other suspicious conditions with Project.MSG_WARN.
*/
public static void checkClass(final Class taskClass, final Project
project) {
// don't have to check for interface, since then
// taskClass would be abstract too.
try {
final Method executeM = taskClass.getMethod( "execute", null );
// don't have to check for public, since
// getMethod finds public method only.
// don't have to check for abstract, since then
// taskClass would be abstract too.
if(!Void.TYPE.equals(executeM.getReturnType())) {
final String message = "return type of execute() should be
void but was \""+executeM.getReturnType()+"\" in " + taskClass;
project.log(message, Project.MSG_WARN);
}
} catch(NoSuchMethodException e) {
final String message = "No public execute() in " + taskClass;
project.log(message, Project.MSG_ERR);
throw new BuildException(message);
}
}
/**
* Do the execution.
*/
public void execute() throws BuildException {
Method setProjectM = null;
try {
Class c = proxy.getClass();
setProjectM =
c.getMethod( "setProject", new Class[] {Project.class});
if(setProjectM != null) {
setProjectM.invoke(proxy, new Object[] {project});
}
} catch (NoSuchMethodException e) {
// ignore this if the class being used as a task does not have
// a set project method.
} catch( Exception ex ) {
log("Error setting project in " + proxy.getClass(),
Project.MSG_ERR);
throw new BuildException( ex );
}
Method executeM=null;
try {
Class c=proxy.getClass();
executeM=c.getMethod( "execute", new Class[0] );
if( executeM == null ) {
log("No public execute() in " + proxy.getClass(),
Project.MSG_ERR);
throw new BuildException("No public execute() in " +
proxy.getClass());
}
executeM.invoke(proxy, null);
return;
} catch( Exception ex ) {
log("Error in " + proxy.getClass(), Project.MSG_ERR);
throw new BuildException( ex );
}
}
/**
* Set the target object class
*/
public void setProxy(Object o) {
this.proxy = o;
}
public Object getProxy() {
return this.proxy ;
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>