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

Reply via email to