diff --git a/src/main/org/apache/tools/ant/ComponentHelper.java b/src/main/org/apache/tools/ant/ComponentHelper.java index 820e45a97..fe1fee281 100644 --- a/src/main/org/apache/tools/ant/ComponentHelper.java +++ b/src/main/org/apache/tools/ant/ComponentHelper.java @@ -58,14 +58,19 @@ import org.apache.tools.ant.util.WeakishReference; import java.util.Enumeration; import java.util.Hashtable; +import java.util.HashSet; import java.util.Iterator; import java.util.Properties; +import java.util.Set; +import java.util.Stack; import java.util.Vector; import java.io.InputStream; import java.io.IOException; import java.lang.reflect.Modifier; +import org.apache.tools.ant.taskdefs.Typedef; + /** * Component creation and configuration. * @@ -98,6 +103,17 @@ public class ComponentHelper { /** flag to rebuild typeClassDefinitions */ private boolean rebuildTypeClassDefinitions = true; + /** Set of namespaces that have been checked for antlibs */ + private Set checkedNamespaces = new HashSet(); + + /** + * Stack of antlib contexts used to resolve definitions while + * processing antlib + */ + private Stack antLibStack = new Stack(); + /** current antlib context */ + private AntTypeTable antLibTypeTable = null; + /** * Map from task names to vectors of created tasks * (String to Vector of Task). This is used to invalidate tasks if @@ -175,32 +191,38 @@ public class ComponentHelper { AntTypeDefinition def = (AntTypeDefinition) i.next(); antTypeTable.put(def.getName(), def); } + // add the parsed namespaces of the parent project + checkedNamespaces.add(helper.checkedNamespaces); } /** Factory method to create the components. * * This should be called by UnknownElement. * - * @param ue The component helper has access via ue to the entire XML tree. - * @param ns Namespace. Also available as ue.getNamespace() - * @param taskName The element name. Also available as ue.getTag() + * @param ue The Unknown Element creating this component + * @param ns Namespace URI. Also available as ue.getNamespace() + * @param componentType The component type, + * Also available as ue.getComponentName() * @return the created component * @throws BuildException if an error occuries */ public Object createComponent(UnknownElement ue, String ns, - String taskName) + String componentType) throws BuildException { - Object component = createComponent(taskName); + Object component = createComponent(componentType); if (component == null) { return null; } if (component instanceof Task) { Task task = (Task) component; - task.setTaskType(taskName); - task.setTaskName(taskName); - addCreatedTask(taskName, task); + task.setLocation(ue.getLocation()); + task.setTaskType(componentType); + task.setTaskName(ue.getTaskName()); + task.setOwningTarget(ue.getOwningTarget()); + task.init(); + addCreatedTask(componentType, task); } return component; @@ -215,7 +237,11 @@ public class ComponentHelper { * @return the class if found or null if not. */ public Object createComponent(String componentName) { - return antTypeTable.create(componentName); + AntTypeDefinition def = getDefinition(componentName); + if (def == null) { + return null; + } + return def.create(project); } /** @@ -227,7 +253,11 @@ public class ComponentHelper { * @return the class if found or null if not. */ public Class getComponentClass(String componentName) { - return antTypeTable.getExposedClass(componentName); + AntTypeDefinition def = getDefinition(componentName); + if (def == null) { + return null; + } + return def.getExposedClass(project); } /** @@ -236,7 +266,15 @@ public class ComponentHelper { * @return the ant definition or null if not present */ public AntTypeDefinition getDefinition(String componentName) { - return antTypeTable.getDefinition(componentName); + checkNamespace(componentName); + AntTypeDefinition ret = null; + if (antLibTypeTable != null && componentName.indexOf(':') == -1) { + ret = antLibTypeTable.getDefinition(componentName); + } + if (ret == null) { + ret = antTypeTable.getDefinition(componentName); + } + return ret; } /** @@ -474,7 +512,7 @@ public class ComponentHelper { * creation fails. */ private Task createNewTask(String taskType) throws BuildException { - Class c = antTypeTable.getExposedClass(taskType); + Class c = getComponentClass(taskType); if (c == null) { return null; } @@ -482,7 +520,7 @@ public class ComponentHelper { if (!(Task.class.isAssignableFrom(c))) { return null; } - Task task = (Task) antTypeTable.create(taskType); + Task task = (Task) createComponent(taskType); if (task == null) { return null; } @@ -557,7 +595,7 @@ public class ComponentHelper { * instance creation fails. */ public Object createDataType(String typeName) throws BuildException { - return antTypeTable.create(typeName); + return createComponent(typeName); } /** @@ -660,6 +698,31 @@ public class ComponentHelper { project.log(" +Datatype " + name + " " + def.getClassName(), Project.MSG_DEBUG); antTypeTable.put(name, def); + + if (antLibTypeTable != null && name.lastIndexOf(':') != -1) { + String baseName = name.substring(name.lastIndexOf(':') + 1); + antLibTypeTable.put(baseName, def); + } + } + } + + /** + * Called at the start of processing an antlib + */ + public void enterAntLib() { + antLibTypeTable = new AntTypeTable(project); + antLibStack.push(antLibTypeTable); + } + + /** + * Called at the end of processing an antlib + */ + public void exitAntLib() { + antLibStack.pop(); + if (antLibStack.size() != 0) { + antLibTypeTable = (AntTypeTable) antLibStack.peek(); + } else { + antLibTypeTable = null; } } @@ -751,6 +814,35 @@ public class ComponentHelper { } } + /** + * called for each component name, check if the + * associated URI has been examined for antlibs. + */ + private void checkNamespace(String componentName) { + if (componentName.indexOf(':') == -1) { + return; // not a namespaced name + } + + String uri = ProjectHelper.extractUriFromComponentName(componentName); + if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) { + return; // namespace that does not contain antlib + } + if (checkedNamespaces.contains(uri)) { + return; // Alreay processed + } + checkedNamespaces.add(uri); + Typedef definer = new Typedef(); + definer.setProject(project); + definer.setURI(uri); + definer.setResource( + uri.substring("antlib:".length()).replace('.', '/') + + "/antlib.xml"); + // a fishing expedition :- ignore errors if antlib not present + definer.setOnError(new Typedef.OnError("ignore")); + definer.init(); + definer.execute(); + } + /** * map that contains the component definitions */ diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java index 7a9a37f29..27b193dc2 100644 --- a/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/src/main/org/apache/tools/ant/ProjectHelper.java @@ -85,6 +85,12 @@ import org.xml.sax.AttributeList; * @author duncan@x180.com */ public class ProjectHelper { + /** The URI for ant name space */ + public static final String ANT_CORE_URI = "ant:core"; + + /** The URI for defined types/tasks - the format is antlib: */ + public static final String ANTLIB_URI = "antlib:"; + /** * Name of JVM system property which provides the name of the * ProjectHelper class to use. @@ -493,5 +499,34 @@ public class ProjectHelper { PropertyHelper.parsePropertyStringDefault(value, fragments, propertyRefs); } + /** + * Map a namespaced {uri,name} to an internal string format. + * For BC purposes the names from the ant core uri will be + * mapped to "name", other names will be mapped to + * uri + ":" + name. + * @param uri The namepace URI + * @param name The localname + * @return The stringified form of the ns name + */ + public static String genComponentName(String uri, String name) { + if (uri == null || uri.equals("") || uri.equals(ANT_CORE_URI)) { + return name; + } + return uri + ":" + name; + } + + /** + * extract a uri from a component name + * + * @param componentName The stringified form for {uri, name} + * @return The uri or "" if not present + */ + public static String extractUriFromComponentName(String componentName) { + int index = componentName.lastIndexOf(':'); + if (index == -1) { + return ""; + } + return componentName.substring(0, index); + } //end class } diff --git a/src/main/org/apache/tools/ant/RuntimeConfigurable.java b/src/main/org/apache/tools/ant/RuntimeConfigurable.java index 7b296ee04..20e2e8528 100644 --- a/src/main/org/apache/tools/ant/RuntimeConfigurable.java +++ b/src/main/org/apache/tools/ant/RuntimeConfigurable.java @@ -176,6 +176,14 @@ public class RuntimeConfigurable implements Serializable { return polyType; } + /** + * set the polymorphic type for this element + * @param polyType the ant component type name, null if not set + */ + public void setPolyType(String polyType) { + this.polyType = polyType; + } + /** * Sets the attributes for the wrapped element. * @@ -260,10 +268,10 @@ public class RuntimeConfigurable implements Serializable { /** * Returns an enumeration of all child wrappers. - * + * @return an enumeration of the child wrappers. * @since Ant 1.5.1 */ - Enumeration getChildren() { + public Enumeration getChildren() { if (children != null) { return Collections.enumeration(children); } else { diff --git a/src/main/org/apache/tools/ant/UnknownElement.java b/src/main/org/apache/tools/ant/UnknownElement.java index 6dcf52e8b..f7adc947c 100644 --- a/src/main/org/apache/tools/ant/UnknownElement.java +++ b/src/main/org/apache/tools/ant/UnknownElement.java @@ -81,6 +81,11 @@ public class UnknownElement extends Task { */ private String namespace; + /** + * Holds the namespace qname of the element. + */ + private String qname; + /** * The real object after it has been loaded. */ @@ -129,6 +134,24 @@ public class UnknownElement extends Task { this.namespace = namespace; } + /** Return the qname of the XML element associated with this component. + * + * @return namespace Qname used in the element declaration. + */ + public String getQName() { + return qname; + } + + /** Set the namespace qname of the XML element. + * This method is typically called by the XML processor. + * + * @param qname the qualified name of the element + */ + public void setQName(String qname) { + this.qname = qname; + } + + /** * Get the RuntimeConfigurable instance for this UnknownElement, containing * the configuration information. @@ -334,6 +357,13 @@ public class UnknownElement extends Task { } } + /** + * @return the component name - uses ProjectHelper#genComponentName() + */ + protected String getComponentName() { + return ProjectHelper.genComponentName(getNamespace(), getTag()); + } + /** * Creates a named task or data type. If the real object is a task, * it is configured up to the init() stage. @@ -345,12 +375,17 @@ public class UnknownElement extends Task { * @return the task or data type represented by the given unknown element. */ protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) { - Object o = makeTask(ue, w); + ComponentHelper helper = ComponentHelper.getComponentHelper( + getProject()); + String name = ue.getComponentName(); + Object o = helper.createComponent(ue, ue.getNamespace(), name); if (o == null) { - o = getProject().createDataType(ue.getTag()); + throw getNotFoundException("task or type", name); } - if (o == null) { - throw getNotFoundException("task or type", ue.getTag()); + if (o instanceof Task) { + Task task = (Task) o; + task.setOwningTarget(getOwningTarget()); + task.init(); } return o; } diff --git a/src/main/org/apache/tools/ant/helper/AntXMLContext.java b/src/main/org/apache/tools/ant/helper/AntXMLContext.java index ae26d1bba..4e63c8347 100644 --- a/src/main/org/apache/tools/ant/helper/AntXMLContext.java +++ b/src/main/org/apache/tools/ant/helper/AntXMLContext.java @@ -54,6 +54,10 @@ package org.apache.tools.ant.helper; import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Vector; import org.xml.sax.Locator; @@ -120,6 +124,11 @@ public class AntXMLContext { * when processing a particular build file. */ private boolean ignoreProjectTag = false; + + /** Keeps track of prefix -> uri mapping during parsing */ + private Map prefixMapping = new HashMap(); + + /** * constructor * @param project the project to which this antxml context belongs to @@ -263,7 +272,7 @@ public class AntXMLContext { /** * sets the implicit target - * @param target + * @param target the implicit target */ public void setImplicitTarget(Target target) { this.implicitTarget = target; @@ -284,6 +293,8 @@ public class AntXMLContext { *

* This method was moved out of the configure method to allow * it to be executed at parse time. + * @param element the current element + * @param attr attributes of the current element */ public void configureId(Object element, Attributes attr) { String id = attr.getValue("id"); @@ -323,6 +334,48 @@ public class AntXMLContext { public void setIgnoreProjectTag(boolean flag) { this.ignoreProjectTag = flag; } + + /** + * Called during parsing, stores the prefix to uri mapping. + * + * @param prefix a namespace prefix + * @param uri a namespace uri + */ + public void startPrefixMapping(String prefix, String uri) { + List list = (List) prefixMapping.get(prefix); + if (list == null) { + list = new ArrayList(); + prefixMapping.put(prefix, list); + } + list.add(uri); + } + + /** + * End of prefix to uri mapping. + * + * @param prefix the namespace prefix + */ + public void endPrefixMapping(String prefix) { + List list = (List) prefixMapping.get(prefix); + if (list == null || list.size() == 0) { + return; // Should not happen + } + list.remove(list.size() - 1); + } + + /** + * prefix to namespace uri mapping + * + * @param prefix the prefix to map + * @return the uri for this prefix, null if not present + */ + public String getPrefixMapping(String prefix) { + List list = (List) prefixMapping.get(prefix); + if (list == null || list.size() == 0) { + return null; + } + return (String) list.get(list.size() - 1); + } } diff --git a/src/main/org/apache/tools/ant/helper/ProjectHelper2.java b/src/main/org/apache/tools/ant/helper/ProjectHelper2.java index bbc7c6a41..607cdd13e 100644 --- a/src/main/org/apache/tools/ant/helper/ProjectHelper2.java +++ b/src/main/org/apache/tools/ant/helper/ProjectHelper2.java @@ -474,6 +474,9 @@ public class ProjectHelper2 extends ProjectHelper { */ public void startElement(String uri, String tag, String qname, Attributes attrs) throws SAXParseException { + if (uri.equals(ANT_CORE_URI)) { + uri = ""; + } AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context); antHandlers.push(currentHandler); @@ -506,6 +509,9 @@ public class ProjectHelper2 extends ProjectHelper { * */ public void endElement(String uri, String name, String qName) throws SAXException { + if (uri.equals(ANT_CORE_URI)) { + uri = ""; + } currentHandler.onEndElement(uri, name, context); AntHandler prev = (AntHandler) antHandlers.pop(); currentHandler = prev; @@ -526,6 +532,25 @@ public class ProjectHelper2 extends ProjectHelper { throws SAXParseException { currentHandler.characters(buf, start, count, context); } + + /** + * Start a namespace prefix to uri mapping + * + * @param prefix the namespace prefix + * @param uri the namespace uri + */ + public void startPrefixMapping(String prefix, String uri) { + context.startPrefixMapping(prefix, uri); + } + + /** + * End a namepace prefix to uri mapping + * + * @param prefix the prefix that is not mapped anymore + */ + public void endPrefixMapping(String prefix) { + context.endPrefixMapping(prefix); + } } /** @@ -550,7 +575,7 @@ public class ProjectHelper2 extends ProjectHelper { Attributes attrs, AntXMLContext context) throws SAXParseException { - if (qname.equals("project")) { + if (name.equals("project") && uri.equals("")) { return ProjectHelper2.projectHandler; } else { // if (context.importlevel > 0) { @@ -610,7 +635,7 @@ public class ProjectHelper2 extends ProjectHelper { */ for (int i = 0; i < attrs.getLength(); i++) { - String key = attrs.getQName(i); + String key = attrs.getLocalName(i); String value = attrs.getValue(i); if (key.equals("default")) { @@ -715,7 +740,7 @@ public class ProjectHelper2 extends ProjectHelper { Attributes attrs, AntXMLContext context) throws SAXParseException { - if (qname.equals("target")) { + if (name.equals("target") && uri.equals("")) { return ProjectHelper2.targetHandler; } else { return ProjectHelper2.elementHandler; @@ -761,7 +786,7 @@ public class ProjectHelper2 extends ProjectHelper { context.addTarget(target); for (int i = 0; i < attrs.getLength(); i++) { - String key = attrs.getQName(i); + String key = attrs.getLocalName(i); String value = attrs.getValue(i); if (key.equals("name")) { @@ -904,7 +929,7 @@ public class ProjectHelper2 extends ProjectHelper { task.setNamespace(uri); task.setProject(context.getProject()); //XXX task.setTaskType(qname); - + task.setQName(qname); task.setTaskName(qname); Location location = new Location(context.getLocator().getSystemId(), @@ -930,8 +955,26 @@ public class ProjectHelper2 extends ProjectHelper { = new RuntimeConfigurable(task, task.getTaskName()); for (int i = 0; i < attrs.getLength(); i++) { - wrapper.setAttribute(attrs.getQName(i), - attrs.getValue(i)); + String name = attrs.getLocalName(i); + String value = attrs.getValue(i); + // PR: Hack for ant-type value + // an ant-type is a component name which can + // be namespaced, need to extract the name + // and convert from qualifed name to uri/name + if (name.equals("ant-type")) { + int index = value.indexOf(":"); + if (index != -1) { + String prefix = value.substring(0, index); + String mappedUri = context.getPrefixMapping(prefix); + if (mappedUri == null) { + throw new BuildException( + "Unable to find XML NS prefix " + prefix); + } + value = ProjectHelper.genComponentName( + mappedUri, value.substring(index + 1)); + } + } + wrapper.setAttribute(name, value); } if (parentWrapper != null) { diff --git a/src/main/org/apache/tools/ant/taskdefs/Antlib.java b/src/main/org/apache/tools/ant/taskdefs/Antlib.java index ce845776c..fdca8b881 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Antlib.java +++ b/src/main/org/apache/tools/ant/taskdefs/Antlib.java @@ -62,7 +62,7 @@ import java.util.List; import org.apache.tools.ant.TaskContainer; import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Location; +import org.apache.tools.ant.ComponentHelper; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.helper.ProjectHelper2; @@ -124,6 +124,7 @@ public class Antlib extends Task implements TaskContainer { // private ClassLoader classLoader; private String prefix; + private String uri = ""; private List tasks = new ArrayList(); /** @@ -137,6 +138,14 @@ public class Antlib extends Task implements TaskContainer { this.classLoader = classLoader; } + /** + * Set the URI for this antlib. + * @param uri the namespace uri + */ + protected void setURI(String uri) { + this.uri = uri; + } + private ClassLoader getClassLoader() { if (classLoader == null) { classLoader = Antlib.class.getClassLoader(); @@ -158,20 +167,28 @@ public class Antlib extends Task implements TaskContainer { * any tasks that derive from Definer. */ public void execute() { - for (Iterator i = tasks.iterator(); i.hasNext();) { - UnknownElement ue = (UnknownElement) i.next(); - ue.maybeConfigure(); - setLocation(ue.getLocation()); - Task t = ue.getTask(); - if (t == null) { - continue; - } - if (t instanceof Definer) { - Definer d = (Definer) t; - d.setInternalClassLoader(getClassLoader()); + ComponentHelper helper = + ComponentHelper.getComponentHelper(getProject()); + helper.enterAntLib(); + try { + for (Iterator i = tasks.iterator(); i.hasNext();) { + UnknownElement ue = (UnknownElement) i.next(); + ue.maybeConfigure(); + setLocation(ue.getLocation()); + Task t = ue.getTask(); + if (t == null) { + continue; + } + if (t instanceof AntlibInterface) { + AntlibInterface d = (AntlibInterface) t; + d.setURI(uri); + d.setAntlibClassLoader(getClassLoader()); + } + t.init(); + t.execute(); } - t.init(); - t.execute(); + } finally { + helper.exitAntLib(); } } diff --git a/src/main/org/apache/tools/ant/taskdefs/AntlibInterface.java b/src/main/org/apache/tools/ant/taskdefs/AntlibInterface.java new file mode 100644 index 000000000..807bd504c --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/AntlibInterface.java @@ -0,0 +1,81 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 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 "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs; + +/** + * Interface for tasks that should be informed when + * they are loaded in antlib's. + * For handling uri and and class loading. + * + * @author Peter Reilly + * + * @since Ant 1.6 + */ +public interface AntlibInterface { + + /** + * The URI for this definition. + * @param uri the namespace URI + */ + void setURI(String uri); + + /** + * Set the class loader of the loading object + * + * @param classLoader a ClassLoader value + */ + void setAntlibClassLoader(ClassLoader classLoader); + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/DefBase.java b/src/main/org/apache/tools/ant/taskdefs/DefBase.java new file mode 100644 index 000000000..a34c5e6a1 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/DefBase.java @@ -0,0 +1,234 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2001-2003 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 "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs; + +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.util.ClasspathUtils; + +/** + * Base class for Definitions + * handling uri and and class loading. + * (This was part of Definer) + * + * @author Costin Manolache + * @author Stefan Bodewig + * @author Peter Reilly + * + * @since Ant 1.6 + */ +public abstract class DefBase extends Task implements AntlibInterface { + private String uri = ""; + private ClassLoader internalClassLoader; + private ClassLoader createdLoader; + private ClasspathUtils.Delegate cpDelegate; + + /** + * The URI for this definition. + * If the URI is "ant:core", the uri will be set to "". (This + * is the default uri). + * URIs that start with "ant:" and are not + * "ant:core" are reserved and are not allowed in this context. + * @param uri the namespace URI + * @throws BuildException if a reserved URI is used + */ + public void setURI(String uri) throws BuildException { + if (uri.equals(ProjectHelper.ANT_CORE_URI)) { + uri = ""; + } + if (uri.startsWith("ant:") && !uri.startsWith("antlib:")) { + throw new BuildException("Attempt to use use a reserved URI " + uri); + } + this.uri = uri; + } + + /** + * @return the namespace uri for this definition + */ + public String getUri() { + return uri; + } + + + /** + * Set the class loader, overrides the cpDelagate + * classloader. + * + * @param classLoader a ClassLoader value + */ + public void setAntlibClassLoader(ClassLoader classLoader) { + this.internalClassLoader = classLoader; + } + + /** + * @param reverseLoader if true a delegated loader will take precedence over + * the parent + * @deprecated stop using this attribute + * @ant.attribute ignore="true" + */ + public void setReverseLoader(boolean reverseLoader) { + this.cpDelegate.setReverseLoader(reverseLoader); + log("The reverseloader attribute is DEPRECATED. It will be removed", + Project.MSG_WARN); + } + + /** + * @return the class path path for this definition + */ + public Path getClasspath() { + return cpDelegate.getClasspath(); + } + + /** + * @return the reverse loader attribute of the classpath delegate. + */ + public boolean isReverseLoader() { + return cpDelegate.isReverseLoader(); + } + + /** + * Returns the loader id of the class path Delegate. + * @return the loader id + */ + public String getLoaderId() { + return cpDelegate.getClassLoadId(); + } + + /** + * Returns the class path id of the class path delegate. + * @return the class path id + */ + public String getClasspathId() { + return cpDelegate.getClassLoadId(); + } + + /** + * Set the classpath to be used when searching for component being defined + * + * @param classpath an Ant Path object containing the classpath. + */ + public void setClasspath(Path classpath) { + this.cpDelegate.setClasspath(classpath); + } + + /** + * Create the classpath to be used when searching for component being + * defined + * @return the classpath of the this definition + */ + public Path createClasspath() { + return this.cpDelegate.createClasspath(); + } + + /** + * reference to a classpath to use when loading the files. + * To actually share the same loader, set loaderref as well + * @param r the reference to the classpath + */ + public void setClasspathRef(Reference r) { + this.cpDelegate.setClasspathref(r); + } + + /** + * Use the reference to locate the loader. If the loader is not + * found, taskdef will use the specified classpath and register it + * with the specified name. + * + * This allow multiple taskdef/typedef to use the same class loader, + * so they can be used together. It eliminate the need to + * put them in the CLASSPATH. + * + * @param r the reference to locate the loader. + * @since Ant 1.5 + */ + public void setLoaderRef(Reference r) { + this.cpDelegate.setLoaderRef(r); + } + + /** + * create a classloader for this definition + * @return the classloader from the cpDelegate + */ + protected ClassLoader createLoader() { + if (internalClassLoader != null) { + return internalClassLoader; + } + if (createdLoader == null) { + createdLoader = this.cpDelegate.getClassLoader(); + // need to load Task via system classloader or the new + // task we want to define will never be a Task but always + // be wrapped into a TaskAdapter. + ((AntClassLoader) createdLoader) + .addSystemPackageRoot("org.apache.tools.ant"); + } + return createdLoader; + } + + /** + * @see org.apache.tools.ant.Task#init() + * @since Ant 1.6 + */ + public void init() throws BuildException { + this.cpDelegate = ClasspathUtils.getDelegate(this); + super.init(); + } + + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/Definer.java b/src/main/org/apache/tools/ant/taskdefs/Definer.java index 66bbf1e9d..78940781a 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Definer.java +++ b/src/main/org/apache/tools/ant/taskdefs/Definer.java @@ -63,32 +63,29 @@ import java.util.Locale; import java.util.Properties; import org.apache.tools.ant.AntTypeDefinition; -import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.ComponentHelper; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Location; import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.Reference; -import org.apache.tools.ant.util.ClasspathUtils; +import org.apache.tools.ant.ProjectHelper; import org.apache.tools.ant.types.EnumeratedAttribute; /** - * Base class for Taskdef and Typedef - does all the classpath - * handling and and class loading. + * Base class for Taskdef and Typedef - handles all + * the attributes for Typedef. The uri and class + * handling is handled by DefBase * * @author Costin Manolache * @author Stefan Bodewig + * @author Peter Reilly * * @since Ant 1.4 */ -public abstract class Definer extends Task { +public abstract class Definer extends DefBase { private String name; private String classname; private File file; private String resource; - private ClasspathUtils.Delegate cpDelegate; private int format = Format.PROPERTIES; private boolean definerSet = false; @@ -172,18 +169,6 @@ public abstract class Definer extends Task { this.format = format.getIndex(); } - /** - * @param reverseLoader if true a delegated loader will take precedence over - * the parent - * @deprecated stop using this attribute - * @ant.attribute ignore="true" - */ - public void setReverseLoader(boolean reverseLoader) { - this.cpDelegate.setReverseLoader(reverseLoader); - log("The reverseloader attribute is DEPRECATED. It will be removed", - Project.MSG_WARN); - } - /** * @return the name for this definition */ @@ -191,13 +176,6 @@ public abstract class Definer extends Task { return name; } - /** - * @return the class path path for this definition - */ - public Path getClasspath() { - return cpDelegate.getClasspath(); - } - /** * @return the file containing definitions */ @@ -212,72 +190,6 @@ public abstract class Definer extends Task { return resource; } - /** - * @return the reverse loader attribute of the classpath delegate. - */ - public boolean isReverseLoader() { - return cpDelegate.isReverseLoader(); - } - - /** - * Returns the loader id of the class path Delegate. - * @return the loader id - */ - public String getLoaderId() { - return cpDelegate.getClassLoadId(); - } - - /** - * Returns the class path id of the class path delegate. - * @return the class path id - */ - public String getClasspathId() { - return cpDelegate.getClassLoadId(); - } - - /** - * Set the classpath to be used when searching for component being defined - * - * @param classpath an Ant Path object containing the classpath. - */ - public void setClasspath(Path classpath) { - this.cpDelegate.setClasspath(classpath); - } - - /** - * Create the classpath to be used when searching for component being - * defined - * @return the classpath of the this definition - */ - public Path createClasspath() { - return this.cpDelegate.createClasspath(); - } - - /** - * reference to a classpath to use when loading the files. - * To actually share the same loader, set loaderref as well - * @param r the reference to the classpath - */ - public void setClasspathRef(Reference r) { - this.cpDelegate.setClasspathref(r); - } - - /** - * Use the reference to locate the loader. If the loader is not - * found, taskdef will use the specified classpath and register it - * with the specified name. - * - * This allow multiple taskdef/typedef to use the same class loader, - * so they can be used together. It eliminate the need to - * put them in the CLASSPATH. - * - * @param r the reference to locate the loader. - * @since Ant 1.5 - */ - public void setLoaderRef(Reference r) { - this.cpDelegate.setLoaderRef(r); - } - /** * Run the definition. @@ -406,6 +318,7 @@ public abstract class Definer extends Task { try { Antlib antlib = Antlib.createAntlib(getProject(), url); antlib.setClassLoader(classLoader); + antlib.setURI(getUri()); antlib.perform(); } catch (BuildException ex) { Location exLocation = ex.getLocation(); @@ -420,23 +333,6 @@ public abstract class Definer extends Task { } } - /** - * create a classloader for this definition - * @return the classloader from the cpDelegate - */ - protected ClassLoader createLoader() { - if (internalClassLoader != null) { - return internalClassLoader; - } - ClassLoader al = this.cpDelegate.getClassLoader(); - // need to load Task via system classloader or the new - // task we want to define will never be a Task but always - // be wrapped into a TaskAdapter. - ((AntClassLoader) al).addSystemPackageRoot("org.apache.tools.ant"); - - return al; - } - /** * Name of the property file to load * ant name/classname pairs from. @@ -474,7 +370,7 @@ public abstract class Definer extends Task { definerSet = true; this.name = name; } - + /** * Returns the classname of the object we are defining. * May be null. @@ -541,25 +437,6 @@ public abstract class Definer extends Task { } - /** - * Set the class loader, overrides the cpDelagate - * classloader. - * - * @param classLoader a ClassLoader value - */ - protected void setInternalClassLoader(ClassLoader classLoader) { - this.internalClassLoader = classLoader; - } - - /** - * @see org.apache.tools.ant.Task#init() - * @since Ant 1.6 - */ - public void init() throws BuildException { - this.cpDelegate = ClasspathUtils.getDelegate(this); - super.init(); - } - /** * Add a definition using the attributes of Definer * @@ -573,6 +450,8 @@ public abstract class Definer extends Task { Class cl = null; try { try { + name = ProjectHelper.genComponentName(getUri(), name); + if (onError != OnError.IGNORE) { cl = Class.forName(classname, true, al); }