Hello,
I'm trying to write an ant task that does substitution like macroDef or
ant-contrib:foreach does. I want to take something like this:
<choice property="foo">
<condition> <available file="@{foo}/foo.txt" /> </condition>
<option value="${env.FOO}" />
<option value="${basedir}/foo" />
<option>
<dirset dir="/usr" includes="**/foo*"/>
</option>
</choice>
and evaluate the <condition> tag, substituting each option into the
condition for @{foo}. However, I'm having trouble getting this to work.
I first tried following the lead of foreach by simply internally
creating a macroDef and using that, however the condition doesn't hold
tasks, but rather Conditions.
I then tried making my <condition> into a TaskContainer (like
MacroDef.NestedSequential), and collecting up the UnknownElements and
then cloning them and doing the substitution. However, I don't know how
to then turn them into a Condition object and evaluate them. I've
attached my current efforts.
Any thoughts?
Thanks,
--Mike
package apl.ant;
import org.apache.tools.ant.taskdefs.condition.Condition;
import org.apache.tools.ant.taskdefs.condition.ConditionBase;
import org.apache.tools.ant.taskdefs.condition.HasFreeSpace;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.UnknownElement;
import org.apache.tools.ant.RuntimeConfigurable;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.Enumeration;
public class Choice extends Task
{
//////////////////////////////////////////////////////////////////////////////
// Attributes and elements //
//////////////////////////////////////////////////////////////////////////////
private String propName = null;
private ConditionTemplate condition = null;
private boolean prompt = false;
private Collection<String> options = new ArrayList<String>();
/**
* set the Select attribute.
*/
public void setSelect(String select)
{
if ("prompt".equalsIgnoreCase(select))
prompt = true;
else if ("first".equalsIgnoreCase(select))
prompt = false;
else
throw new BuildException("select attribute must be either \"prompt\" or \"first\".");
}
/**
* set the Property attribute.
*/
public void setProperty(String propName)
{
this.propName = propName;
}
/**
* create a nested Condition object.
*/
public ConditionTemplate createCondition()
{
if (null != this.condition)
throw new BuildException ("Choice may only contain a single <condition>");
this.condition = new ConditionTemplate();
return this.condition;
}
public class ConditionTemplate
implements TaskContainer
{
private UnknownElement condition = null;
public void addTask(Task task)
{
if (this.condition != null)
throw new BuildException("Condition may only contain a single child");
this.condition = (UnknownElement) task;
}
}
/**
* create a nested Option object.
*/
public NestedOption createOption()
{
return new NestedOption();
}
public class NestedOption
{
public void setValue(String value)
{
Choice.this.options.add(value);
}
public void addConfigured(ResourceCollection c)
{
Iterator<Resource> i = c.iterator();
while (i.hasNext())
Choice.this.options.add(i.next().getName());
}
}
//////////////////////////////////////////////////////////////////////////////
// Helper Methods //
//////////////////////////////////////////////////////////////////////////////
/**
* copy an UnknownElement, substituting attributes
*
* @param template the UnknownElement to copy
* @param attrs a map from attribute names to values
*/
public static UnknownElement substitute(UnknownElement template, Map<String,String> attrMap)
{
UnknownElement result = template.copy(template.getProject());
substitute(result.getWrapper(), attrMap);
return result;
}
private static void substitute(RuntimeConfigurable rc, Map<String,String> attrMap)
{
// replace attributes
Collection<Map.Entry<String,String>> attrset = rc.getAttributeMap().entrySet();
for (Map.Entry<String,String> attr : attrset)
{
String value = attr.getValue();
for (Map.Entry<String,String> subst : attrMap.entrySet())
value = value.replace("@{" + subst.getKey() + "}", subst.getValue());
attr.setValue(value);
}
// recursively substitute on children.
Enumeration i = rc.getChildren();
while(i.hasMoreElements())
substitute((RuntimeConfigurable) i.nextElement(), attrMap);
}
public class ConditionInstance
extends ConditionBase
implements Condition
{
private final ConditionTemplate template;
private final Map<String,String> attributes;
public ConditionInstance(ConditionTemplate template)
{
this.template = template;
this.attributes = new HashMap<String,String>();
}
public void setDynamicAttribute(String name, String value)
{
attributes.put(name, value);
}
public boolean eval()
{
// copy condition, substituting param
UnknownElement subst = substitute(this.template.condition, this.attributes);
subst.bindToOwner(Choice.this);
// create an UnknownElement corresponding to this
UnknownElement element = new UnknownElement("condition");
RuntimeConfigurable rc = new RuntimeConfigurable(element, "condition");
element.bindToOwner(Choice.this);
rc.addChild(subst.getWrapper());
element.addChild(subst);
element.configure(this);
System.out.println(element.getRealThing());
// convert it to a condition
Condition c = (Condition) this.getConditions().nextElement();
System.out.println(c);
// evaluate it
return c.eval();
}
}
//////////////////////////////////////////////////////////////////////////////
// Execution //
//////////////////////////////////////////////////////////////////////////////
public void execute()
{
for(String option : options)
{
System.out.println("evaluating possible choice: " + option);
ConditionInstance instance = new ConditionInstance(condition);
instance.setDynamicAttribute(propName, option);
System.out.println(" --> " + instance.eval());
}
}
}
/*
** vim: ts=4 sw=4 cindent cino=\:0
*/
---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscr...@ant.apache.org
For additional commands, e-mail: user-h...@ant.apache.org