git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272721 13f79535-47bb-0310-9956-ffa450edef68master
@@ -440,21 +440,40 @@ public class ComponentManager implements ComponentService { | |||||
* @exception ExecutionException if there is a problem creating or | * @exception ExecutionException if there is a problem creating or | ||||
* configuring the component | * configuring the component | ||||
*/ | */ | ||||
protected Object createComponent(String componentName, BuildElement model) | |||||
private Object createComponent(String componentName, BuildElement model) | |||||
throws ExecutionException { | throws ExecutionException { | ||||
ImportInfo importInfo = getImport(componentName); | |||||
if (importInfo == null) { | |||||
throw new ExecutionException("There is no definition of the <" | |||||
+ componentName + "> component"); | |||||
Object component = null; | |||||
if (model != null) { | |||||
for (Iterator i = aspects.iterator(); i.hasNext();) { | |||||
Aspect aspect = (Aspect) i.next(); | |||||
component = aspect.preCreateComponent(component, model); | |||||
} | |||||
} | } | ||||
String className = importInfo.getClassName(); | |||||
ComponentLibrary componentLibrary | |||||
= importInfo.getComponentLibrary(); | |||||
return createComponentFromDef(componentName, componentLibrary, | |||||
importInfo.getDefinition(), model); | |||||
if (component == null) { | |||||
ImportInfo importInfo = getImport(componentName); | |||||
if (importInfo == null) { | |||||
throw new ExecutionException("There is no definition of the <" | |||||
+ componentName + "> component"); | |||||
} | |||||
String className = importInfo.getClassName(); | |||||
ComponentLibrary componentLibrary | |||||
= importInfo.getComponentLibrary(); | |||||
component = createComponentFromDef(componentName, componentLibrary, | |||||
importInfo.getDefinition(), model); | |||||
} | |||||
if (model != null) { | |||||
for (Iterator i = aspects.iterator(); i.hasNext();) { | |||||
Aspect aspect = (Aspect) i.next(); | |||||
component = aspect.postCreateComponent(component, model); | |||||
} | |||||
} | |||||
return component; | |||||
} | } | ||||
/** | /** | ||||
@@ -672,36 +691,12 @@ public class ComponentManager implements ComponentService { | |||||
// is there a polymorph indicator - look in Ant aspects | // is there a polymorph indicator - look in Ant aspects | ||||
String typeName | String typeName | ||||
= model.getAspectAttributeValue(Constants.ANT_ASPECT, "type"); | = model.getAspectAttributeValue(Constants.ANT_ASPECT, "type"); | ||||
String refId | |||||
= model.getAspectAttributeValue(Constants.ANT_ASPECT, "refid"); | |||||
if (refId != null && typeName != null) { | |||||
throw new ExecutionException("Only one of " + Constants.ANT_ASPECT | |||||
+ ":type and " + Constants.ANT_ASPECT | |||||
+ ":refid may be specified at a time", model.getLocation()); | |||||
} | |||||
Object typeInstance = null; | Object typeInstance = null; | ||||
if (typeName != null) { | if (typeName != null) { | ||||
// the build file has specified the actual type of the element. | // the build file has specified the actual type of the element. | ||||
// we need to look up that type and use it | // we need to look up that type and use it | ||||
typeInstance = createComponent(typeName, model); | typeInstance = createComponent(typeName, model); | ||||
} else if (refId != null) { | |||||
// We have a reference to an existing instance. Need to check if | |||||
// it is compatible with the type expected by the nested element's | |||||
// adder method | |||||
typeInstance = frame.getDataValue(refId); | |||||
if (model.getAttributeNames().hasNext() || | |||||
model.getNestedElements().hasNext() || | |||||
model.getText().length() != 0) { | |||||
throw new ExecutionException("Element <" + nestedElementName | |||||
+ "> is defined by reference and hence may not specify " | |||||
+ "any attributes, nested elements or content", | |||||
model.getLocation()); | |||||
} | |||||
if (typeInstance == null) { | |||||
throw new ExecutionException("The given ant:refid value '" | |||||
+ refId + "' is not defined", model.getLocation()); | |||||
} | |||||
} else if (nestedType != null) { | } else if (nestedType != null) { | ||||
// We need to create an instance of the class expected by the nested | // We need to create an instance of the class expected by the nested | ||||
// element's adder method if that is possible | // element's adder method if that is possible | ||||
@@ -723,17 +718,9 @@ public class ComponentManager implements ComponentService { | |||||
// is the typeInstance compatible with the type expected | // is the typeInstance compatible with the type expected | ||||
// by the element's add method | // by the element's add method | ||||
if (!nestedType.isInstance(typeInstance)) { | if (!nestedType.isInstance(typeInstance)) { | ||||
if (refId != null) { | |||||
throw new ExecutionException("The value specified by refId " | |||||
+ refId + " is not compatible with the <" | |||||
+ nestedElementName + "> nested element", | |||||
model.getLocation()); | |||||
} else if (typeName != null) { | |||||
throw new ExecutionException("The type " | |||||
+ typeName + " is not compatible with the <" | |||||
+ nestedElementName + "> nested element", | |||||
model.getLocation()); | |||||
} | |||||
throw new ExecutionException("The type " | |||||
+ typeName + " is not compatible with the <" | |||||
+ nestedElementName + "> nested element", model.getLocation()); | |||||
} | } | ||||
setter.addElement(element, nestedElementName, typeInstance); | setter.addElement(element, nestedElementName, typeInstance); | ||||
} | } | ||||
@@ -781,23 +768,28 @@ public class ComponentManager implements ComponentService { | |||||
* | * | ||||
* @param object the object to be configured. | * @param object the object to be configured. | ||||
* @param attributeValues a map containing named attribute values. | * @param attributeValues a map containing named attribute values. | ||||
* | |||||
* @param ignoreUnsupported if this is true, attribute names for which no | |||||
* setter method exists are ignored. | |||||
* @exception ExecutionException if the object does not support an | * @exception ExecutionException if the object does not support an | ||||
* attribute in the map. | * attribute in the map. | ||||
*/ | */ | ||||
public void configureAttributes(Object object, Map attributeValues) | |||||
public void configureAttributes(Object object, Map attributeValues, | |||||
boolean ignoreUnsupported) | |||||
throws ExecutionException { | throws ExecutionException { | ||||
Setter setter = getSetter(object.getClass()); | Setter setter = getSetter(object.getClass()); | ||||
for (Iterator i = attributeValues.keySet().iterator(); i.hasNext();) { | for (Iterator i = attributeValues.keySet().iterator(); i.hasNext();) { | ||||
String attributeName = (String) i.next(); | String attributeName = (String) i.next(); | ||||
String attributeValue = (String) attributeValues.get(attributeName); | String attributeValue = (String) attributeValues.get(attributeName); | ||||
if (!setter.supportsAttribute(attributeName)) { | if (!setter.supportsAttribute(attributeName)) { | ||||
throw new ExecutionException(object.getClass().getName() | |||||
+ " does not support the \"" + attributeName | |||||
+ "\" attribute"); | |||||
if (!ignoreUnsupported) { | |||||
throw new ExecutionException(object.getClass().getName() | |||||
+ " does not support the \"" + attributeName | |||||
+ "\" attribute"); | |||||
} | |||||
} else { | |||||
setter.setAttribute(object, attributeName, | |||||
frame.replacePropertyRefs(attributeValue)); | |||||
} | } | ||||
setter.setAttribute(object, attributeName, | |||||
frame.replacePropertyRefs(attributeValue)); | |||||
} | } | ||||
} | } | ||||
@@ -868,6 +868,7 @@ public class Frame implements DemuxOutputReceiver { | |||||
*/ | */ | ||||
protected void executeTask(Task task, AspectValueCollection aspectValues) | protected void executeTask(Task task, AspectValueCollection aspectValues) | ||||
throws ExecutionException { | throws ExecutionException { | ||||
List aspects = componentManager.getAspects(); | List aspects = componentManager.getAspects(); | ||||
Map aspectContexts = new HashMap(); | Map aspectContexts = new HashMap(); | ||||
for (Iterator i = aspects.iterator(); i.hasNext();) { | for (Iterator i = aspects.iterator(); i.hasNext();) { | ||||
@@ -897,6 +898,7 @@ public class Frame implements DemuxOutputReceiver { | |||||
} | } | ||||
// Now call back the aspects that registered interest | // Now call back the aspects that registered interest | ||||
Set activeAspects = aspectContexts.keySet(); | Set activeAspects = aspectContexts.keySet(); | ||||
for (Iterator i = activeAspects.iterator(); i.hasNext();) { | for (Iterator i = activeAspects.iterator(); i.hasNext();) { | ||||
Aspect aspect = (Aspect) i.next(); | Aspect aspect = (Aspect) i.next(); | ||||
@@ -932,18 +934,8 @@ public class Frame implements DemuxOutputReceiver { | |||||
BuildElement model = (BuildElement) taskIterator.next(); | BuildElement model = (BuildElement) taskIterator.next(); | ||||
// what sort of element is this. | // what sort of element is this. | ||||
List aspects = componentManager.getAspects(); | |||||
try { | try { | ||||
Object component = componentManager.createComponent(model); | Object component = componentManager.createComponent(model); | ||||
for (Iterator i = aspects.iterator(); i.hasNext();) { | |||||
Aspect aspect = (Aspect) i.next(); | |||||
Object replacement | |||||
= aspect.postCreateComponent(component, model); | |||||
if (replacement != null) { | |||||
component = replacement; | |||||
} | |||||
} | |||||
if (component instanceof Task) { | if (component instanceof Task) { | ||||
execService.executeTask((Task) component); | execService.executeTask((Task) component); | ||||
} | } | ||||
@@ -91,6 +91,41 @@ public class AntAspect extends AbstractAspect { | |||||
= (ComponentService) context.getCoreService(ComponentService.class); | = (ComponentService) context.getCoreService(ComponentService.class); | ||||
} | } | ||||
/** | |||||
* This join point is activated before a component has been created. | |||||
* The aspect can return an object to be used rather than the core creating | |||||
* the object. | |||||
* | |||||
* @param component the component that has been created. This will be null | |||||
* unless another aspect has created the component | |||||
* @param model the Build model that applies to the component | |||||
* | |||||
* @return a component to use. | |||||
* @exception ExecutionException if the aspect cannot process the component. | |||||
*/ | |||||
public Object preCreateComponent(Object component, BuildElement model) | |||||
throws ExecutionException { | |||||
String refId = model.getAspectAttributeValue(ANT_ASPECT, "refid"); | |||||
if (refId != null) { | |||||
if (model.getAttributeNames().hasNext() || | |||||
model.getNestedElements().hasNext() || | |||||
model.getText().length() != 0) { | |||||
throw new ExecutionException("Element <" + model.getType() | |||||
+ "> is defined by reference and hence may not specify " | |||||
+ "any attributes, nested elements or content", | |||||
model.getLocation()); | |||||
} | |||||
Object referredComponent = dataService.getDataValue(refId); | |||||
if (referredComponent == null) { | |||||
throw new ExecutionException("The given ant:refid value '" | |||||
+ refId + "' is not defined", model.getLocation()); | |||||
} | |||||
return referredComponent; | |||||
} | |||||
return component; | |||||
} | |||||
/** | /** | ||||
* This join point is activated after a component has been created and | * This join point is activated after a component has been created and | ||||
* configured. If the aspect wishes, an object can be returned in place | * configured. If the aspect wishes, an object can be returned in place | ||||
@@ -111,7 +146,7 @@ public class AntAspect extends AbstractAspect { | |||||
dataService.setMutableDataValue(typeId, component); | dataService.setMutableDataValue(typeId, component); | ||||
} | } | ||||
return null; | |||||
return super.postCreateComponent(component, model); | |||||
} | } | ||||
/** | /** | ||||
@@ -135,7 +170,8 @@ public class AntAspect extends AbstractAspect { | |||||
return null; | return null; | ||||
} | } | ||||
componentService.configureAttributes(aspectContext, antAspectValues); | |||||
componentService.configureAttributes(aspectContext, antAspectValues, | |||||
true); | |||||
if (aspectContext.isRequired()) { | if (aspectContext.isRequired()) { | ||||
return aspectContext; | return aspectContext; | ||||
} | } | ||||
@@ -88,7 +88,23 @@ public class AbstractAspect implements Aspect { | |||||
return context; | return context; | ||||
} | } | ||||
/** | |||||
* This join point is activated before a component is to be created. | |||||
* The aspect can return an object to be used rather than the core creating | |||||
* the object. | |||||
* | |||||
* @param component the component that has been created. This will be null | |||||
* unless another aspect has created the component | |||||
* @param model the Build model that applies to the component | |||||
* | |||||
* @return a component to use. | |||||
* @exception ExecutionException if the aspect cannot process the component. | |||||
*/ | |||||
public Object preCreateComponent(Object component, BuildElement model) | |||||
throws ExecutionException { | |||||
return component; | |||||
} | |||||
/** | /** | ||||
* This join point is activated after a component has been created and | * This join point is activated after a component has been created and | ||||
* configured. If the aspect wishes, an object can be returned in place | * configured. If the aspect wishes, an object can be returned in place | ||||
@@ -103,7 +119,7 @@ public class AbstractAspect implements Aspect { | |||||
*/ | */ | ||||
public Object postCreateComponent(Object component, BuildElement model) | public Object postCreateComponent(Object component, BuildElement model) | ||||
throws ExecutionException { | throws ExecutionException { | ||||
return null; | |||||
return component; | |||||
} | } | ||||
/** | /** | ||||
@@ -111,8 +127,8 @@ public class AbstractAspect implements Aspect { | |||||
* | * | ||||
* @param task the task being executed. | * @param task the task being executed. | ||||
* @param aspectValues a collection of aspect attribute values for use | * @param aspectValues a collection of aspect attribute values for use | ||||
* during the task execution. | |||||
* | |||||
* during the task execution - may be null if no aspect values are | |||||
* provided. | |||||
* @return an object which indicates that this aspect wishes to | * @return an object which indicates that this aspect wishes to | ||||
* be notified after execution has been completed, in which case the obkect | * be notified after execution has been completed, in which case the obkect | ||||
* is returned to provide the aspect its context. If this returns null | * is returned to provide the aspect its context. If this returns null | ||||
@@ -75,6 +75,21 @@ public interface Aspect { | |||||
throws ExecutionException; | throws ExecutionException; | ||||
/** | |||||
* This join point is activated before a component has been created. | |||||
* The aspect can return an object to be used rather than the core creating | |||||
* the object. | |||||
* | |||||
* @param component the component that has been created. This will be null | |||||
* unless another aspect has created the component | |||||
* @param model the Build model that applies to the component | |||||
* | |||||
* @return a component to use. | |||||
* @exception ExecutionException if the aspect cannot process the component. | |||||
*/ | |||||
Object preCreateComponent(Object component, BuildElement model) | |||||
throws ExecutionException; | |||||
/** | /** | ||||
* This join point is activated after a component has been created and | * This join point is activated after a component has been created and | ||||
* configured. If the aspect wishes, an object can be returned in place | * configured. If the aspect wishes, an object can be returned in place | ||||
@@ -83,8 +98,7 @@ public interface Aspect { | |||||
* @param component the component that has been created. | * @param component the component that has been created. | ||||
* @param model the Build model used to create the component. | * @param model the Build model used to create the component. | ||||
* | * | ||||
* @return a replacement for the component if desired. If null is returned | |||||
* the current component is used. | |||||
* @return a component to use | |||||
* @exception ExecutionException if the aspect cannot process the component. | * @exception ExecutionException if the aspect cannot process the component. | ||||
*/ | */ | ||||
Object postCreateComponent(Object component, BuildElement model) | Object postCreateComponent(Object component, BuildElement model) | ||||
@@ -190,15 +190,17 @@ public interface ComponentService { | |||||
throws ExecutionException; | throws ExecutionException; | ||||
/** | /** | ||||
* Configure an object with attribtes from the given map | |||||
* configure an object with attribtes from the given map | |||||
* | * | ||||
* @param object the object to be configured. | * @param object the object to be configured. | ||||
* @param attributeValues a map containing named attribute values. | * @param attributeValues a map containing named attribute values. | ||||
* | |||||
* @param ignoreUnsupported if this is true, attribute names for which no | |||||
* setter method exists are ignored. | |||||
* @exception ExecutionException if the object does not support an | * @exception ExecutionException if the object does not support an | ||||
* attribute in the map. | * attribute in the map. | ||||
*/ | */ | ||||
void configureAttributes(Object object, Map attributeValues) | |||||
void configureAttributes(Object object, Map attributeValues, | |||||
boolean ignoreUnsupported) | |||||
throws ExecutionException; | throws ExecutionException; | ||||
} | } | ||||