Also split Definer.java in a base class (DefBase) to allow it to be used for other defining tasks Also add AntlibInterface to allow antlib to set uri and classloader for other tasks/types that Definer. Bugzilla: 19897 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275064 13f79535-47bb-0310-9956-ffa450edef68master
@@ -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 | |||
*/ | |||
@@ -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:<package> */ | |||
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 | |||
} |
@@ -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 { | |||
@@ -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; | |||
} | |||
@@ -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 { | |||
* <p> | |||
* 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); | |||
} | |||
} | |||
@@ -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) { | |||
@@ -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(); | |||
} | |||
} | |||
@@ -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 | |||
* <http://www.apache.org/>. | |||
*/ | |||
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 <code>ClassLoader</code> value | |||
*/ | |||
void setAntlibClassLoader(ClassLoader classLoader); | |||
} |
@@ -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 | |||
* <http://www.apache.org/>. | |||
*/ | |||
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 <code>ClassLoader</code> 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(); | |||
} | |||
} |
@@ -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 <code>null</code>. | |||
@@ -541,25 +437,6 @@ public abstract class Definer extends Task { | |||
} | |||
/** | |||
* Set the class loader, overrides the cpDelagate | |||
* classloader. | |||
* | |||
* @param classLoader a <code>ClassLoader</code> 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); | |||
} | |||