/* * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved. * * Licensed 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 net.sf.antcontrib.logic; import java.util.Enumeration; import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Sequential; /** * A wrapper that lets you run a set of tasks and optionally run a * different set of tasks if the first set fails and yet another set * after the first one has finished. * *

This mirrors Java's try/catch/finally.

* *

The tasks inside of the required <try> * element will be run. If one of them should throw a {@link * org.apache.tools.ant.BuildException BuildException} several things * can happen:

* * * *

If a <finally> block is present, the task * nested into it will be run, no matter whether the first tasks have * thrown an exception or not.

* *

Attributes:

* * * * * * * * * * * * * * * * * *
NameDescriptionRequired
propertyName of a property that will receive the message of the * exception that has been caught (if any)No
referenceId of a reference that will point to the exception object * that has been caught (if any)No
* *

Use the following task to define the <trycatch> * task before you use it the first time:

* *

 *   <taskdef name="trycatch" 
 *            classname="net.sf.antcontrib.logic.TryCatchTask" />
 * 
* *

Crude Example

* *

 * <trycatch property="foo" reference="bar">
 *   <try>
 *     <fail>Tada!</fail>
 *   </try>
 *
 *   <catch>
 *     <echo>In &lt;catch&gt;.</echo>
 *   </catch>
 *
 *   <finally>
 *     <echo>In &lt;finally&gt;.</echo>
 *   </finally>
 * </trycatch>
 *
 * <echo>As property: ${foo}</echo>
 * <property name="baz" refid="bar" />
 * <echo>From reference: ${baz}</echo>
 * 
* *

results in

* *

 *   [trycatch] Caught exception: Tada!
 *       [echo] In <catch>.
 *       [echo] In <finally>.
 *       [echo] As property: Tada!
 *       [echo] From reference: Tada!
 * 
* * @author Stefan Bodewig * @author Dan Ritchey */ public class TryCatchTask extends Task { public static final class CatchBlock extends Sequential { private String throwable = BuildException.class.getName(); public CatchBlock() { super(); } public void setThrowable(String throwable) { this.throwable = throwable; } public boolean execute(Throwable t) throws BuildException { try { Class c = Thread.currentThread().getContextClassLoader().loadClass(throwable); if (c.isAssignableFrom(t.getClass())) { execute(); return true; } return false; } catch (ClassNotFoundException e) { throw new BuildException(e); } } } private Sequential tryTasks = null; private Vector catchBlocks = new Vector(); private Sequential finallyTasks = null; private String property = null; private String reference = null; /** * Adds a nested <try> block - one is required, more is * forbidden. */ public void addTry(Sequential seq) throws BuildException { if (tryTasks != null) { throw new BuildException("You must not specify more than one "); } tryTasks = seq; } public void addCatch(CatchBlock cb) { catchBlocks.add(cb); } /** * Adds a nested <finally> block - at most one is allowed. */ public void addFinally(Sequential seq) throws BuildException { if (finallyTasks != null) { throw new BuildException("You must not specify more than one "); } finallyTasks = seq; } /** * Sets the property attribute. */ public void setProperty(String p) { property = p; } /** * Sets the reference attribute. */ public void setReference(String r) { reference = r; } /** * The heart of the task. */ public void execute() throws BuildException { Throwable thrown = null; if (tryTasks == null) { throw new BuildException("A nested element is required"); } try { tryTasks.perform(); } catch (Throwable e) { if (property != null) { /* * Using setProperty instead of setNewProperty to * be able to compile with Ant < 1.5. */ getProject().setProperty(property, e.getMessage()); } if (reference != null) { getProject().addReference(reference, e); } boolean executed = false; Enumeration blocks = catchBlocks.elements(); while (blocks.hasMoreElements() && ! executed) { CatchBlock cb = (CatchBlock)blocks.nextElement(); executed = cb.execute(e); } if (! executed) { thrown = e; } } finally { if (finallyTasks != null) { finallyTasks.perform(); } } if (thrown != null) { throw new BuildException(thrown); } } }