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