From 31deeb980977afb1cfe3234eb17a1360aab49d5e Mon Sep 17 00:00:00 2001
From: Peter Reilly
Date: Fri, 10 Aug 2007 22:26:22 +0000
Subject: [PATCH] adding componentdef code
git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@564787 13f79535-47bb-0310-9956-ffa450edef68
---
.../apache/tools/ant/AntTypeDefinition.java | 23 ++-
.../org/apache/tools/ant/ComponentHelper.java | 61 +++++++-
.../apache/tools/ant/IntrospectionHelper.java | 129 ++++++++++++++---
src/main/org/apache/tools/ant/antlib.xml | 135 ++++++++++++++++++
.../tools/ant/taskdefs/Componentdef.java | 44 ++++++
.../apache/tools/ant/taskdefs/Definer.java | 12 ++
.../ant/taskdefs/condition/ConditionBase.java | 25 +---
.../tools/ant/taskdefs/defaults.properties | 1 +
8 files changed, 386 insertions(+), 44 deletions(-)
create mode 100644 src/main/org/apache/tools/ant/antlib.xml
create mode 100644 src/main/org/apache/tools/ant/taskdefs/Componentdef.java
diff --git a/src/main/org/apache/tools/ant/AntTypeDefinition.java b/src/main/org/apache/tools/ant/AntTypeDefinition.java
index 32c1b14c2..a51482fd7 100644
--- a/src/main/org/apache/tools/ant/AntTypeDefinition.java
+++ b/src/main/org/apache/tools/ant/AntTypeDefinition.java
@@ -38,6 +38,23 @@ public class AntTypeDefinition {
private Class adaptToClass;
private String className;
private ClassLoader classLoader;
+ private boolean restrict = false;
+
+ /**
+ * Set the restrict attribute.
+ * @param restrict the value to set.
+ */
+ public void setRestrict(boolean restrict) {
+ this.restrict = restrict;
+ }
+
+ /**
+ * Get the restrict attribute.
+ * @return the restrict attribute.
+ */
+ public boolean isRestrict() {
+ return restrict;
+ }
/**
* Set the definition's name.
@@ -129,7 +146,7 @@ public class AntTypeDefinition {
* class and the definition class is not
* assignable from the assignable class.
* @param project the current project.
- * @return the exposed class.
+ * @return the exposed class - may return null if upable to load the class
*/
public Class getExposedClass(Project project) {
if (adaptToClass != null) {
@@ -327,6 +344,7 @@ public class AntTypeDefinition {
return (other != null && other.getClass() == getClass()
&& other.getTypeClass(project).equals(getTypeClass(project))
&& other.getExposedClass(project).equals(getExposedClass(project))
+ && other.restrict == restrict
&& other.adapterClass == adapterClass
&& other.adaptToClass == adaptToClass);
}
@@ -349,7 +367,8 @@ public class AntTypeDefinition {
|| !extractClassname(adapterClass).equals(
extractClassname(other.adapterClass))
|| !extractClassname(adaptToClass).equals(
- extractClassname(other.adaptToClass))) {
+ extractClassname(other.adaptToClass))
+ || restrict != other.restrict) {
return false;
}
// all the names are the same: check if the class path of the loader
diff --git a/src/main/org/apache/tools/ant/ComponentHelper.java b/src/main/org/apache/tools/ant/ComponentHelper.java
index 89666f4b8..4be9f125c 100644
--- a/src/main/org/apache/tools/ant/ComponentHelper.java
+++ b/src/main/org/apache/tools/ant/ComponentHelper.java
@@ -33,6 +33,8 @@ import java.util.Set;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
import org.apache.tools.ant.taskdefs.Typedef;
import org.apache.tools.ant.taskdefs.Definer;
@@ -56,6 +58,9 @@ import org.apache.tools.ant.util.FileUtils;
* @since Ant1.6
*/
public class ComponentHelper {
+ /** Map of component name to lists of restricted definitions */
+ private Map restrictedDefinitions = new HashMap();
+
/** Map from component name to anttypedefinition */
private AntTypeTable antTypeTable;
@@ -123,6 +128,14 @@ public class ComponentHelper {
// {tasks, types}
private static Properties[] defaultDefinitions = new Properties[2];
+ /**
+ * Get the project.
+ * @return the project owner of this helper.
+ */
+ public Project getProject() {
+ return project;
+ }
+
/**
* Find a project component for a specific project, creating
* it if it does not exist.
@@ -196,6 +209,14 @@ public class ComponentHelper {
for (Iterator i = helper.checkedNamespaces.iterator(); i.hasNext();) {
checkedNamespaces.add(i.next());
}
+
+ // Add the restricted definitions
+ for (Iterator i = helper.restrictedDefinitions.entrySet().iterator();
+ i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ restrictedDefinitions.put(
+ entry.getKey(), new ArrayList((List) entry.getValue()));
+ }
}
/**
@@ -395,6 +416,15 @@ public class ComponentHelper {
return typeClassDefinitions;
}
+ /**
+ * This returns a list of restricted definitions for a name.
+ * @param componentName the name to use.
+ * @return the list of restricted definitions for a particular name.
+ */
+ public List getRestrictedDefinitions(String componentName) {
+ return (List) restrictedDefinitions.get(componentName);
+ }
+
/**
* Adds a new datatype definition.
* Attempting to override an existing definition with an
@@ -423,7 +453,11 @@ public class ComponentHelper {
* @param def an AntTypeDefinition
value.
*/
public void addDataTypeDefinition(AntTypeDefinition def) {
- updateDataTypeDefinition(def);
+ if (!def.isRestrict()) {
+ updateDataTypeDefinition(def);
+ } else {
+ updateRestrictedDefinition(def);
+ }
}
/**
@@ -607,6 +641,31 @@ public class ComponentHelper {
return sameValidity && (!defValid || def.sameDefinition(old, project));
}
+ /**
+ * update the restricted definition table with a new or
+ * modified definition.
+ */
+ private void updateRestrictedDefinition(AntTypeDefinition def) {
+ String name = def.getName();
+ synchronized (restrictedDefinitions) {
+ List list = (List) restrictedDefinitions.get(name);
+ if (list == null) {
+ list = new ArrayList();
+ restrictedDefinitions.put(name, list);
+ }
+ // Check if the classname is already present and remove it
+ // if it is
+ for (Iterator i = list.iterator(); i.hasNext();) {
+ AntTypeDefinition current = (AntTypeDefinition) i.next();
+ if (current.getClassName().equals(def.getClassName())) {
+ i.remove();
+ break;
+ }
+ }
+ list.add(def);
+ }
+ }
+
/**
* Update the component definition table with a new or
* modified definition.
diff --git a/src/main/org/apache/tools/ant/IntrospectionHelper.java b/src/main/org/apache/tools/ant/IntrospectionHelper.java
index cbedda447..9961c0b56 100644
--- a/src/main/org/apache/tools/ant/IntrospectionHelper.java
+++ b/src/main/org/apache/tools/ant/IntrospectionHelper.java
@@ -1383,28 +1383,33 @@ public final class IntrospectionHelper {
}
ComponentHelper helper = ComponentHelper.getComponentHelper(project);
- Object addedObject = null;
- Method addMethod = null;
- Class clazz = helper.getComponentClass(elementName);
- if (clazz == null) {
- return null;
- }
- addMethod = findMatchingMethod(clazz, addTypeMethods);
- if (addMethod == null) {
+ MethodAndObject restricted = createRestricted(
+ helper, elementName, addTypeMethods);
+ MethodAndObject topLevel = createTopLevel(
+ helper, elementName, addTypeMethods);
+
+ if (restricted == null && topLevel == null) {
return null;
}
- addedObject = helper.createComponent(elementName);
- if (addedObject == null) {
- return null;
+
+ if (restricted != null && topLevel != null) {
+ throw new BuildException(
+ "ambiguous: type and component definitions for "
+ + elementName);
}
- Object rObject = addedObject;
- if (addedObject instanceof PreSetDef.PreSetDefinition) {
- rObject = ((PreSetDef.PreSetDefinition) addedObject).createObject(project);
+
+ MethodAndObject methodAndObject
+ = restricted != null ? restricted : topLevel;
+
+ Object rObject = methodAndObject.object;
+ if (methodAndObject.object instanceof PreSetDef.PreSetDefinition) {
+ rObject = ((PreSetDef.PreSetDefinition) methodAndObject.object)
+ .createObject(project);
}
- final Object nestedObject = addedObject;
+ final Object nestedObject = methodAndObject.object;
final Object realObject = rObject;
-
- return new NestedCreator(addMethod) {
+
+ return new NestedCreator(methodAndObject.method) {
Object create(Project project, Object parent, Object ignore)
throws InvocationTargetException, IllegalAccessException {
if (!getMethod().getName().endsWith("Configured")) {
@@ -1460,6 +1465,9 @@ public final class IntrospectionHelper {
* @return a matching Method
; null if none found.
*/
private Method findMatchingMethod(Class paramClass, List methods) {
+ if (paramClass == null) {
+ return null;
+ }
Class matchedClass = null;
Method matchedMethod = null;
@@ -1486,4 +1494,91 @@ public final class IntrospectionHelper {
int ends = (MAX_REPORT_NESTED_TEXT - ELLIPSIS.length()) / 2;
return new StringBuffer(text).replace(ends, text.length() - ends, ELLIPSIS).toString();
}
+
+
+ private class MethodAndObject {
+ private Method method;
+ private Object object;
+ public MethodAndObject(Method method, Object object) {
+ this.method = method;
+ this.object = object;
+ }
+ }
+
+ /**
+ *
+ */
+ private AntTypeDefinition findRestrictedDefinition(
+ ComponentHelper helper, String componentName, List methods) {
+ AntTypeDefinition definition = null;
+ Class matchedDefinitionClass = null;
+
+ List definitions = helper.getRestrictedDefinitions(componentName);
+ if (definitions == null) {
+ return null;
+ }
+ for (int i = 0; i < definitions.size(); ++i) {
+ AntTypeDefinition d = (AntTypeDefinition) definitions.get(i);
+ Class exposedClass = d.getExposedClass(helper.getProject());
+ if (exposedClass == null) {
+ continue;
+ }
+ Method method = findMatchingMethod(exposedClass, methods);
+ if (method == null) {
+ continue;
+ }
+ if (matchedDefinitionClass != null) {
+ throw new BuildException(
+ "ambiguous: restricted definitions for "
+ + componentName + " " +
+ matchedDefinitionClass + " and " + exposedClass);
+ }
+ matchedDefinitionClass = exposedClass;
+ definition = d;
+ }
+ return definition;
+ }
+
+ private MethodAndObject createRestricted(
+ ComponentHelper helper, String elementName, List addTypeMethods) {
+
+ Project project = helper.getProject();
+
+ AntTypeDefinition restrictedDefinition =
+ findRestrictedDefinition(helper, elementName, addTypeMethods);
+
+ if (restrictedDefinition == null) {
+ return null;
+ }
+
+ Method addMethod = findMatchingMethod(
+ restrictedDefinition.getExposedClass(project), addTypeMethods);
+ if (addMethod == null) {
+ throw new BuildException(
+ "Ant Internal Error - contract mismatch for "
+ + elementName);
+ }
+ Object addedObject = restrictedDefinition.create(project);
+ if (addedObject == null) {
+ throw new BuildException(
+ "Failed to create object " + elementName
+ + " of type " + restrictedDefinition.getTypeClass(project));
+ }
+ return new MethodAndObject(addMethod, addedObject);
+ }
+
+ private MethodAndObject createTopLevel(
+ ComponentHelper helper, String elementName, List methods) {
+ Class clazz = helper.getComponentClass(elementName);
+ if (clazz == null) {
+ return null;
+ }
+ Method addMethod = findMatchingMethod(clazz, addTypeMethods);
+ if (addMethod == null) {
+ return null;
+ }
+ Object addedObject = helper.createComponent(elementName);
+ return new MethodAndObject(addMethod, addedObject);
+ }
+
}
diff --git a/src/main/org/apache/tools/ant/antlib.xml b/src/main/org/apache/tools/ant/antlib.xml
new file mode 100644
index 000000000..d274d09f4
--- /dev/null
+++ b/src/main/org/apache/tools/ant/antlib.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/apache/tools/ant/taskdefs/Componentdef.java b/src/main/org/apache/tools/ant/taskdefs/Componentdef.java
new file mode 100644
index 000000000..7f825fbc1
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/Componentdef.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskAdapter;
+
+/**
+ * Adds a compenent definition to the current project.
+ * used in the current project. Two attributes are needed, the name that identifies
+ * this compenent uniquely, and the full name of the class (
+ * including the packages) that
+ * implements this component.
+ * @since Ant 1.8
+ * @ant.task category="internal"
+ */
+public class Componentdef extends Definer {
+
+ /**
+ * Default constructor.
+ * Creates a new ComponentDef instance.
+ * Sets the restrict attribute to true.
+ */
+
+ public Componentdef() {
+ setRestrict(true);
+ }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/Definer.java b/src/main/org/apache/tools/ant/taskdefs/Definer.java
index d523ef8ed..e00b1013a 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Definer.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Definer.java
@@ -66,6 +66,7 @@ public abstract class Definer extends DefBase {
private String classname;
private File file;
private String resource;
+ private boolean restrict = false;
private int format = Format.PROPERTIES;
private boolean definerSet = false;
@@ -144,6 +145,16 @@ public abstract class Definer extends DefBase {
}
}
+ /**
+ * The restrict attribute.
+ * If this is true, only use this definition in add(X).
+ * @param restrict the value to set.
+ */
+ protected void setRestrict(boolean restrict) {
+ this.restrict = restrict;
+ }
+
+
/**
* What to do if there is an error in loading the class.
*
@@ -597,6 +608,7 @@ public abstract class Definer extends DefBase {
def.setClass(cl);
def.setAdapterClass(adapterClass);
def.setAdaptToClass(adaptToClass);
+ def.setRestrict(restrict);
def.setClassLoader(al);
if (cl != null) {
def.checkClass(getProject());
diff --git a/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java b/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java
index f483f357f..acee3023d 100644
--- a/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java
+++ b/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java
@@ -35,11 +35,7 @@ import org.apache.tools.ant.taskdefs.UpToDate;
*
* @since Ant 1.4
*/
-public abstract class ConditionBase extends ProjectComponent
- implements DynamicElement {
-
- private static final String CONDITION_ANTLIB
- = "antlib:org.apache.tools.ant.types.conditions:";
+public abstract class ConditionBase extends ProjectComponent {
/**
* name of the component
@@ -284,23 +280,4 @@ public abstract class ConditionBase extends ProjectComponent
conditions.addElement(c);
}
- /**
- * Create a dynamically discovered condition. Built-in conditions can
- * be discovered from the org.apache.tools.ant.taskdefs.condition
- * antlib.
- * @param name the condition to create.
- * @return the dynamic condition if found, null otherwise.
- */
- public Object createDynamicElement(String name) {
- Object cond = ComponentHelper.getComponentHelper(getProject())
- .createComponent(CONDITION_ANTLIB + name);
- if (!(cond instanceof Condition)) {
- return null;
- }
- log("Dynamically discovered '" + name + "' " + cond,
- Project.MSG_DEBUG);
- add((Condition) cond);
- return cond;
- }
-
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties
index 6e18840df..8eba3fa5c 100644
--- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties
+++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties
@@ -12,6 +12,7 @@ bzip2=org.apache.tools.ant.taskdefs.BZip2
checksum=org.apache.tools.ant.taskdefs.Checksum
chmod=org.apache.tools.ant.taskdefs.Chmod
classloader=org.apache.tools.ant.taskdefs.Classloader
+componentdef=org.apache.tools.ant.taskdefs.Componentdef
concat=org.apache.tools.ant.taskdefs.Concat
condition=org.apache.tools.ant.taskdefs.ConditionTask
copy=org.apache.tools.ant.taskdefs.Copy