/********************************************************************** * Copyright (c) 2005-2009 ant4eclipse project team. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich **********************************************************************/ package org.ant4eclipse.ant.platform.core.delegate; import java.io.StringReader; import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; import org.ant4eclipse.lib.core.Assure; import org.ant4eclipse.lib.core.ldapfilter.LdapFilter; import org.ant4eclipse.lib.core.ldapfilter.ParseException; import org.ant4eclipse.lib.core.logging.A4ELogging; import org.ant4eclipse.lib.core.util.StringMap; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DynamicAttribute; import org.apache.tools.ant.UnknownElement; import org.apache.tools.ant.taskdefs.MacroDef; /** * <p> * Extends the {@link MacroDef} to support conditional execution. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ public class ConditionalMacroDef extends MacroDef { /** the conditional nested sequential */ private ConditionalNestedSequential _conditionalNestedSequential; /** * <p> * Returns the filter expression. * </p> * * @return the filter expression. */ public String getFilter() { return this._conditionalNestedSequential.getFilter(); } /** * <p> * Returns the 'if' condition. * </p> * * @return the 'if' condition. */ public boolean isIf() { return this._conditionalNestedSequential.isIf(); } /** * <p> * Returns the 'unless' condition. * </p> * * @return the 'unless' condition. */ public boolean isUnless() { return this._conditionalNestedSequential.isUnless(); } /** * Returns the value of the given attribute or <tt>defaultValue</tt> if the attribute has not been set on this * ConditionalMacroDef * * @param name * The name of the attribute * @param defaultValue * The default value that is returned when the attribute is not set * @return The attribute value or defaultValue */ public String getAttribute(String name, String defaultValue) { return this._conditionalNestedSequential.getAttribute(name, defaultValue); } /** * {@inheritDoc} */ @Override public NestedSequential createSequential() { try { // object rape - access the nestedSequential field... Field field = MacroDef.class.getDeclaredField("nestedSequential"); field.setAccessible(true); // copied from the original createSequential method if (field.get(this) != null) { throw new BuildException("Only one sequential allowed"); } // set the conditional nested sequential this._conditionalNestedSequential = new ConditionalNestedSequential(this); field.set(this, this._conditionalNestedSequential); // return the result return this._conditionalNestedSequential; } catch (Throwable e) { // what should be do now!? e.printStackTrace(); throw new BuildException("Internal Ant4Eclipse error..."); } } /** * <p> * Extends the {@link NestedSequential} to support conditional execution. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ public static class ConditionalNestedSequential extends MacroDef.NestedSequential implements DynamicAttribute { /** the sequential should only be executed if '_if == true' */ private boolean _if = true; /** the sequential should only be executed if '_unless == false' */ private boolean _unless = false; /** a filter expression to filter the elements to execute a sequential for */ private String _filter = null; /** the parent conditional macro definition */ private ConditionalMacroDef _conditionalMacroDef; /** a {@link StringMap} containing the (dynamic) attributes of this Sequential */ private StringMap _attributes = new StringMap(); /** * <p> * </p> * * @param conditionalMacroDef */ public ConditionalNestedSequential(ConditionalMacroDef conditionalMacroDef) { Assure.notNull("conditionalMacroDef", conditionalMacroDef); this._conditionalMacroDef = conditionalMacroDef; } /** * <p> * Returns the filter expression. * </p> * * @return the filter expression. */ public String getFilter() { return this._filter; } /** * <p> * Sets the filter expression. * </p> * * @param filter * the filter expression. */ @SuppressWarnings("unchecked") public void setFilter(String filter) { // try to parse the filter try { new LdapFilter(new HashMap<String, String>(), new StringReader(filter)).validate(); } // in case of an exception we have create an useful BuildException catch (ParseException e) { try { if (A4ELogging.isDebuggingEnabled()) { A4ELogging.debug("Exception while parsing filter string '%s'.", filter); } // get the current UnknownElement UnknownElement element = (UnknownElement) this._conditionalMacroDef.getProject().getThreadTask( Thread.currentThread()); if (A4ELogging.isDebuggingEnabled()) { A4ELogging.debug("Current UnknownElement is '%s'.", element); } // search for the unknown element that causes the problem for (UnknownElement unknownElement : (List<UnknownElement>) element.getChildren()) { if (equals(unknownElement.getWrapper().getProxy())) { throw new BuildException("Invalid filter '" + filter + "'.", unknownElement.getLocation()); } } // no element found -> throw simple BuildException throw new BuildException("Invalid filter '" + filter + "'."); } catch (BuildException exception) { throw exception; } catch (Exception exception) { // if (A4ELogging.isDebuggingEnabled()) { A4ELogging .debug("Exception while computing the line number for an exception: '%s'", exception.getMessage()); } // no element found -> throw simple BuildException throw new BuildException("Invalid filter '" + filter + "'."); } } // set the filter this._filter = filter; } /** * <p> * Returns the 'if' condition. * </p> * * @return the 'if' condition. */ public boolean isIf() { return this._if; } /** * <p> * Sets the 'if' condition. * </p> * * @param aIf * the 'if' condition. */ public void setIf(boolean aIf) { this._if = aIf; } /** * <p> * Returns the 'unless' condition. * </p> * * @return the 'unless' condition. */ public boolean isUnless() { return this._unless; } /** * <p> * Sets the 'unless' condition. * </p> * * @param the * 'unless' condition. */ public void setUnless(boolean unless) { this._unless = unless; } /** * Allows the specification of additional attributes on a MacroDefinition * * @see org.apache.tools.ant.DynamicAttribute#setDynamicAttribute(java.lang.String, java.lang.String) * */ public void setDynamicAttribute(String name, String value) throws BuildException { this._attributes.put(name, value); } /** * Returns the attribute with the given name or <tt>defaultValue</tt> if the attribute has not been set. * * @param name * the attribute name * @param defaultValue * the default value * @return the attribute value or defaultValie */ public String getAttribute(String name, String defaultValue) { return this._attributes.get(name, defaultValue); } } }