KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > flowcontrol > call > CallerTask


1 /**
2  * $Id: CallerTask.java 180 2007-03-15 12:56:38Z ssmc $
3  * Copyright 2002-2004 iDare Media, Inc. All rights reserved.
4  *
5  * Originally written by iDare Media, Inc. for release into the public domain. This
6  * library, source form and binary form, is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or (at your option) any later
9  * version.<p>
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU LGPL (GNU Lesser General Public License) for more details.<p>
14  *
15  * You should have received a copy of the GNU Lesser General Public License along with this
16  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite
17  * 330, Boston, MA 02111-1307 USA. The LGPL can be found online at
18  * http://www.fsf.org/copyleft/lesser.html<p>
19  *
20  * This product has been influenced by several projects within the open-source community.
21  * The JWare developers wish to acknowledge the open-source community's support. For more
22  * information regarding the open-source products used within JWare, please visit the
23  * JWare website.
24  *----------------------------------------------------------------------------------------*
25  * WEBSITE- http://www.jware.info EMAIL- inquiries@jware.info
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.flowcontrol.call;
30
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33
34 import org.apache.tools.ant.BuildException;
35 import org.apache.tools.ant.Project;
36 import org.apache.tools.ant.Task;
37
38 import com.idaremedia.antx.AntX;
39 import com.idaremedia.antx.AntXFixture;
40 import com.idaremedia.antx.AssertableTask;
41 import com.idaremedia.antx.ExportedProperties;
42 import com.idaremedia.antx.helpers.Strings;
43 import com.idaremedia.antx.ownhelpers.TaskExaminer;
44 import com.idaremedia.antx.parameters.RecoveryEnabled;
45
46 /**
47  * Superclass of any task that can run either a set of nested tasksets or a set
48  * of real top level targets . Whether the targets are run from an isolated sub-project
49  * is subclass dependent. This class was originally named
50  * "<span class="src">StepCaller</span>" but was renamed to eliminate the confusion
51  * caused by the "Step" prefix. For simplicity in our documentation we refer to both
52  * top-level targets and nested tasksets as "targets". The CallerTask class implements
53  * basic support for the following common behavior:<ul>
54  * <li>Target verification (ensure named steps or top-level targets actually exist).</li>
55  * <li>The default fixture passthru options (like 'inheritRefs', and 'inheritAll').</li>
56  * <li>Implementation for basic property-based overlay instructions.</li>
57  * <li>The standard execution of named targets in order. The support is based on
58  * the {@linkplain TargetCaller} interface. Whether targets are nested or
59  * top-level is subclass defined.</li>
60  * <li>Problem handling when a called target generates an error. This support is
61  * based on the 'haltiferror' and 'tryeach' options. </li>
62  * </ul>
63  *
64  * @since JWare/AntX 0.1
65  * @author ssmc, &copy;2002-2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
66  * @version 0.5
67  * @.safety single
68  * @.group api,infra
69  * @see InlineStep
70  * @see TargetCaller
71  **/

72
73 public abstract class CallerTask extends AssertableTask
74     implements RecoveryEnabled
75 {
76     /**
77      * Initializes a new caller task.
78      **/

79     protected CallerTask()
80     {
81         super(AntX.flow+"call");
82     }
83
84
85
86     /**
87      * Iniitializes a new, custom caller task.
88      * @param iam CV-label
89      **/

90     protected CallerTask(String JavaDoc iam)
91     {
92         super(iam);
93     }
94
95
96     /**
97      * Optionally delays configuration of nested tasks until they're
98      * executed (like standard '<i>sequential</i>' task).
99      * @see TaskExaminer#ignoreConfigure TaskExaminer.ignoreConfigure(&#8230;)
100      * @since JWare/AntX 0.4
101      **/

102     public void maybeConfigure()
103         throws BuildException
104     {
105         if (!TaskExaminer.ignoreConfigure(this)) {//@since AntX0.4+Ant1.6
106
super.maybeConfigure();
107         }
108     }
109
110
111 // ---------------------------------------------------------------------------------------
112
// Script-facing Parameters:
113
// ---------------------------------------------------------------------------------------
114

115     /**
116      * Sets name of a property to update in event any target fails.
117      * @param property the property's name (non-null)
118      **/

119     public void setFailProperty(String JavaDoc property)
120     {
121         require_(property!=null,"setFailProperty- nonzro name");
122         m_failProperty = property;
123     }
124
125
126     /**
127      * Returns name of a property to update in event any caller
128      * fails. Returns <i>null</i> if never set. This property is set
129      * irregardless of this task's "haltiferror" setting.
130      **/

131     public final String JavaDoc getFailProperty()
132     {
133         return m_failProperty;
134     }
135
136
137     /**
138      * Sets the name of a variable to update in event any
139      * target caller fails.
140      * @see #setFailValue
141      * @since JWare/AntX 0.3
142      **/

143     public void setFailVariable(String JavaDoc variable)
144     {
145         require_(variable!=null,"setFailVariable- nonzro name");
146         m_failVariable = variable;
147     }
148
149
150
151     /**
152      * Returns name of the variable to update in event
153      * any target caller fails. Returns <i>null</i> if never set.
154      * @since JWare/AntX 0.3
155      **/

156     public final String JavaDoc getFailVariable()
157     {
158         return m_failVariable;
159     }
160
161
162     /**
163      * Sets value used for {@linkplain #setFailProperty failproperty}
164      * and/or {@linkplain #setFailVariable failvariable}
165      * in event of failure.
166      * @param value the value to be used (non-null)
167      **/

168     public void setFailValue(String JavaDoc value)
169     {
170         require_(value!=null,"setFailValu- nonzro valu");
171         m_failValue = value;
172     }
173
174
175     /**
176      * Returns value used for {@linkplain #setFailProperty failproperty}
177      * and/or {@linkplain #setFailVariable failvariable}
178      * in event of failure. Defaults to the string "true".
179      **/

180     public final String JavaDoc getFailValue()
181     {
182         return m_failValue;
183     }
184
185
186
187     /**
188      * Sets whether this task will continue to unwind the call
189      * stack and eventually fail with a top-level build exception.
190      * Defaults to <i>true</i>.
191      **/

192     public void setHaltIfError(boolean balk)
193     {
194         m_haltIfError = balk;
195     }
196
197
198     /**
199      * Returns <i>true</i> if this task will propagate any
200      * build exceptions unconditionally. Defaults to <i>true</i>.
201      **/

202     public final boolean isHaltIfError()
203     {
204         return m_haltIfError;
205     }
206
207
208     /**
209      * Sets whether this task will ignore any target failures
210      * and continue executing subsequent targets.
211      **/

212     public void setTryEach(boolean tryEach)
213     {
214         m_tryEach = tryEach;
215     }
216
217
218     /**
219      * Returns whether this task will ignore any target failures
220      * and continue executing subsequent targets. Defaults to
221      * <i>false</i>.
222      **/

223     public final boolean isTryEach()
224     {
225         return m_tryEach;
226     }
227
228
229 // ---------------------------------------------------------------------------------------
230
// Execution:
231
// ---------------------------------------------------------------------------------------
232

233
234     /**
235      * Returns this task's overlay instructions tracker. Never returns
236      * <i>null</i>. Must be called after this task initialized.
237      * @since JWare/AntX 0.4
238      **/

239     protected OverlayParametersHelper getParametersKeeper()
240     {
241         if (m_paramsHelper==null) {
242             m_paramsHelper= new OverlayParametersHelper(getProject());
243         }
244         return m_paramsHelper;
245     }
246
247
248
249     /**
250      * Returns <i>true</i> if this task has been assigned
251      * specific overlay instructions.
252      * @since JWare/AntX 0.4
253      **/

254     protected final boolean haveOverlayParameters()
255     {
256         if (m_paramsHelper==null) {
257             return false;
258         }
259         return !m_paramsHelper.getParameters().isEmpty();
260     }
261
262
263
264     /**
265      * Copies this task's fixture configuration instructions to the
266      * target caller's environment.
267      * @since JWare/AntX 0.4
268      **/

269     protected final void transferOverlayParameters(TargetCaller caller)
270     {
271         if (m_paramsHelper!=null) {
272             m_paramsHelper.transferParameters(caller);
273         }
274     }
275
276
277
278     /**
279      * Factory-method that returns an ordered, filtered list of configured
280      * step or top-level target callers. Subclasses must provide. Never
281      * returns <i>null</i> but can return an empty list. Caller assumes
282      * ownership of the returned list.
283      * @see #getFilteredStepsLike getFilteredStepsLike(&#8230;)
284      * @throws BuildException if unable to determine targets.
285      **/

286     protected abstract List JavaDoc copyOfOrderedTargetCallers()
287         throws BuildException;
288
289
290
291     /**
292      * Template-method that executes this caller's targets in natural order.
293      * @param selector [optional] callback to select which run method to use
294      * @see #copyOfOrderedTargetCallers
295      * @throws BuildException if unable to determine targets or any target
296      * does and "haltiferror" is <i>false</i>
297      **/

298     protected void runTargetCallers(TargetCaller.RunSelector selector)
299         throws BuildException
300     {
301         List JavaDoc callers = copyOfOrderedTargetCallers();
302         verify_(callers!=null,"runcalrs- nonzro calrs to run");
303
304         if (!callers.isEmpty()) {
305             Iterator JavaDoc itr= callers.listIterator();
306             boolean started=false;
307             TargetCaller caller=null;
308
309             while (itr.hasNext()) {
310                 caller = (TargetCaller)itr.next();
311                 try {
312
313                     callerStarted(caller);
314                     started=true;
315                     log("Caller for '"+callerName(caller)+
316                         "' about to run.",Project.MSG_DEBUG);
317
318                     if (selector!=null) {
319                         selector.run(caller);
320                     } else {
321                         caller.run();
322                     }
323
324                     started=false;
325                     callerFinished(caller,null);
326
327                 } catch(RuntimeException JavaDoc rtX) {
328                     callerFailed(caller, rtX, callers);
329                     if (started) {
330                         callerFinished(caller,rtX);
331                     }
332                     if (isHaltIfError()) {
333                         throw rtX;
334                     } else if (!isTryEach()) {
335                         break;
336                     }
337                 }
338             }//foreach
339

340             callers.clear();
341
342         }//!=0
343
}
344
345
346
347     /**
348      * Generates a series of (possibly partitioned) calls to either
349      * a set of top-level targets or a set of nested steps. By default
350      * just calls {@linkplain #runTargetCallers runTargetCallers}.
351      * @throws BuildException if any caller does.
352      **/

353     public void execute() throws BuildException
354     {
355         verifyCanExecute_("execute");
356         runTargetCallers(null);
357     }
358
359
360
361     /**
362      * Called before a target caller is executed. By default
363      * does nothing.
364      * @param caller the verified (about-to-be)started caller (non-null)
365      **/

366     protected void callerStarted(TargetCaller caller)
367     {
368         //do-nothing
369
}
370
371
372
373     /**
374      * Called after a target caller returns (successfully or
375      * not). By default does nothing.
376      * @param caller the finished caller (non-null)
377      * @param cause [optional] if non-null caller aborted with this
378      **/

379     protected void callerFinished(TargetCaller caller, Throwable JavaDoc cause)
380     {
381         //do-nothing
382
}
383
384
385
386     /**
387      * Called if this caller catches a runtime exception while
388      * executing a sequence of target callers. By default logs an
389      * error and updates failproperty if one was requested.
390      * @param caller the target caller that failed (non-null)
391      * @param failure the barfage (non-null)
392      * @param callers list of all targets being executed (non-null)
393      **/

394     protected void callerFailed(TargetCaller caller, Throwable JavaDoc failure,
395                                 List JavaDoc callers)
396     {
397         String JavaDoc targetName = callerName(caller);
398
399         if (getMsgId()!=null) {
400             log(getMsg(newMsgGetter(targetName)), Project.MSG_ERR);
401         } else {
402             log(uistrs().get("flow.runsteps.failure",getTaskName(),targetName),
403                 Project.MSG_ERR);
404         }
405
406         String JavaDoc what = getFailValue();
407
408         if (getFailProperty()!=null) {
409             checkIfProperty_(getFailProperty(),true);
410             getProject().setNewProperty(getFailProperty(), what);
411         }
412         if (getFailVariable()!=null) {
413             ExportedProperties.set(getFailVariable(), what);
414         }
415     }
416
417
418 // ---------------------------------------------------------------------------------------
419
// Determining(sp?) Call Targets:
420
// ---------------------------------------------------------------------------------------
421

422
423     /**
424      * Returns <i>true</i> if the named target exists within this
425      * task's project.
426      * @param targetName the name of candidate target (non-null)
427      **/

428     protected boolean targetExists(String JavaDoc targetName)
429     {
430         return getProject().getTargets().get(targetName)!=null;
431     }
432
433
434     /**
435      * Returns a new list of all possible tasks-- not just steps. By
436      * default returns task list of enclosing target. Never returns
437      * <i>null</i>. Caller assumes ownership of returned array. Returned
438      * list can include task placeholders (UnknownElements).
439      **/

440     protected Task[] getAllPossibleTasks()
441     {
442         return getOwningTarget().getTasks();
443     }
444
445
446
447     /**
448      * Returns a new list of all possible steps of a particular class.
449      * The filter class must be a kind-of {@linkplain InlineStep} class. Caller
450      * assumes ownership of returned list. The returned list of tasks can
451      * contain task placeholders (instead of true steps). It is assumed
452      * that the caller is examining task attributes. If the caller needs
453      * additional information, they will have to force the placeholders
454      * to be replaced by true tasks.
455      * @param thisClass required step class (non-null)
456      * @.impl This method must not convert proxies to their real objects YET.
457      * If this conversion were done here, it's very likely to be
458      * premature as tasks subsequent to the this task may depend
459      * on side-effects of this task (like properties being defined,
460      * etc.)
461      **/

462     protected List JavaDoc getAllPossibleStepsLike(Class JavaDoc thisClass)
463     {
464         require_(InlineStep.class.isAssignableFrom(thisClass),
465                  "getStpsLik- kindof(inlineStep)");
466         Task[] tasks = getAllPossibleTasks();
467         List JavaDoc l = AntXFixture.newList(tasks.length);
468         for (int i=0;i<tasks.length;i++) {
469             Class JavaDoc taskClass = TaskExaminer.trueClass(tasks[i]);//@.impl
470
if (taskClass!=null && thisClass.isAssignableFrom(taskClass)) {
471                 l.add(tasks[i]);
472             }
473         }
474         return l;
475     }
476
477
478
479     /**
480      * Extracts a step's name from a placeholder task or if not a
481      * placeholder the real step object.
482      * @param t placeholder or step task (non-null)
483      * @return the value of the 'name' attribute
484      * @.impl Expects Ant 1.6.1
485      * @since JWare/AntX 0.4
486      **/

487     private String JavaDoc getStepName(Object JavaDoc t)
488     {
489         if (t instanceof InlineStep) {
490             return ((InlineStep)t).getName();
491         }
492         return TaskExaminer.trueAttr((Task)t,"name");
493     }
494
495
496
497     /**
498      * Returns a new list of steps (of particular class) that match a
499      * supplied name list. Caller assumes ownership of returned list. The
500      * returned list of tasks can contain task placeholders (instead of
501      * actual steps).
502      * @param thisClass required step class (non-null)
503      * @param filterList the set of step names (non-null)
504      * @return list of matching steps
505      * @see #getAllPossibleStepsLike getAllPossibleStepsLike(&#8230;)
506      * @.impl See {@linkplain #getAllPossibleStepsLike getAllPossibleStepsLike(&#8230;)}
507      **/

508     protected final List JavaDoc getFilteredStepsLike(Class JavaDoc thisClass, List JavaDoc filterList)
509     {
510         require_(filterList!=null,"filterlst- nonzro list");
511         List JavaDoc steps = getAllPossibleStepsLike(thisClass);
512         if (!steps.isEmpty()) {
513             Iterator JavaDoc itr= steps.iterator();
514             while (itr.hasNext()) {
515                 String JavaDoc sn = getStepName(itr.next());
516                 if (!filterList.contains(sn)) {
517                     itr.remove();
518                 }
519             }
520         }
521         return steps;
522     }
523
524
525
526     /**
527      * Utility method to get a useful name for caller.
528      * @param caller the caller in question (non-null)
529      **/

530     static final String JavaDoc callerName(TargetCaller caller)
531     {
532         String JavaDoc name = caller.getStepName();
533         if (name==null) {
534             name = caller.getTargetName();
535         }
536         if (name==null) {
537             name = "n/d";
538         }
539         return name;
540     }
541
542
543
544     OverlayParametersHelper m_paramsHelper;//NB: lazy-inited
545
private boolean m_haltIfError= true; /* NB: unrolls and barfs by default */
546     private boolean m_tryEach=false; /* NB: abort if any task fails */
547     private String JavaDoc m_failProperty, m_failVariable;
548     private String JavaDoc m_failValue = Strings.TRUE;
549 }
550
551 /* end-of-CallerTask.java */
552
Popular Tags