KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > flowcontrol > match > SwitchTask


1 /**
2  * $Id: SwitchTask.java 187 2007-03-25 17:59:16Z ssmc $
3  * Copyright 2002-2004,2007 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.1 of the License, or (at your option) any
9  * later 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://antxtras.sf.net/ EMAIL- jware[at]users[dot]sourceforge[dot]net
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.flowcontrol.match;
30
31 import java.util.Iterator JavaDoc;
32
33 import org.apache.tools.ant.BuildException;
34 import org.apache.tools.ant.Project;
35 import org.apache.tools.ant.Task;
36 import org.apache.tools.ant.types.Reference;
37
38 import com.idaremedia.antx.AntX;
39 import com.idaremedia.antx.FlexString;
40 import com.idaremedia.antx.helpers.Strings;
41 import com.idaremedia.antx.helpers.TaskHandle;
42 import com.idaremedia.antx.ownhelpers.TaskExaminer;
43 import com.idaremedia.antx.parameters.FlexValueSupport;
44 import com.idaremedia.antx.starters.StrictOuterTask;
45 import com.idaremedia.antx.starters.TaskSet;
46
47 /**
48  * A task that executes a named taskset that matches some selection criterion. The
49  * selection criterion is defined like a Java-style '<i>switch</i>' statement:
50  * the switch task's value is the source (or unknown) value; the possible
51  * choice tasks values are the candidate matches (or known) values. Candidate tasksets
52  * are all nested within a single owning SwitchTask and must all be {@linkplain ChoiceTask
53  * ChoiceTasks} or ChoiceTask subclasses. Usually defined &lt;domatch&gt;.
54  * <p>
55  * <b>Examples:</b><pre>
56  * &lt;domatch property="dist.type"&gt;
57  * &lt;like value="public|production"&gt;
58  * ...
59  * &lt;/like&gt;
60  * &lt;like value="local|internal"&gt;
61  * ...
62  * &lt;/like&gt;
63  * &lt;/domatch&gt;
64  * -OR-
65  * &lt;domatch value="${build.type}"&gt;
66  * &lt;equals value="debug"&gt;
67  * ...
68  * &lt;/equals&gt;
69  * &lt;equals value="opt"&gt;
70  * ...
71  * &lt;/equals&gt;
72  * &lt;default&gt;
73  * ...
74  * &lt;/default&gt;
75  * &lt;/domatch&gt;
76  * -OR-
77  * &lt;domatch property="build.type" context="build.properties"&gt;
78  * &lt;meets criteria="is-intranet"&gt;
79  * ...
80  * &lt;/meets&gt;
81  * &lt;meets criteria="is-public"&gt;
82  * ...
83  * &lt;/meets&gt;
84  * &lt;/domatch&gt;
85  * </pre>
86  *
87  * @since JWare/AntX 0.1
88  * @author ssmc, &copy;2002-2004,2007 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
89  * @version 0.5.1
90  * @.safety single
91  * @.group api,infra
92  * @see MatchAll
93  * @see MatchEquals
94  * @see MatchLike
95  * @see MatchCondition
96  **/

97
98 public class SwitchTask extends TaskSet implements StrictOuterTask, FlexValueSupport
99 {
100     /**
101      * Initializes a new SwitchTask.
102      **/

103     public SwitchTask()
104     {
105         super(AntX.flow+"switch");
106         m_value.setLenient(false);
107     }
108
109
110     /**
111      * Initializes a new SwitchTask with custom delay configuration.
112      **/

113     protected SwitchTask(String JavaDoc iam, boolean delayConfiguration)
114     {
115         super(iam, delayConfiguration);
116         m_value.setLenient(false);
117     }
118
119
120     /**
121      * Initializes the enclosing project of this component. Updates
122      * any internal project-components too.
123      **/

124     public void setProject(Project P)
125     {
126         super.setProject(P);
127         m_value.setProject(P);
128     }
129
130 // ---------------------------------------------------------------------------------------
131
// Match-(Flex)Value Parameters:
132
// ---------------------------------------------------------------------------------------
133

134     /**
135      * Sets the switch literal value for this task. One of the flex
136      * value types must be defined before this task is executed.
137      * @param value the application value to compare (non-null)
138      **/

139     public final void setValue(String JavaDoc value)
140     {
141         require_(value!=null,"setValu- nonzro valu");
142         if (!m_value.isLiteral()) {
143             throw new BuildException
144                 (uistrs().get("flow.switch.needs.value",
145                               getTaskName()), getLocation());
146         }
147         m_value.set(value);
148         m_value.setIsLiteral();
149     }
150
151
152     /**
153      * Returns the switch value for this task. Returns <i>null</i>
154      * if never set or switch is not setup to use a literal value.
155      * @since JWare/AntX 0.2
156      **/

157     public final String JavaDoc getSwitchValue()
158     {
159         return m_value.isLiteral() ? m_value.get() : null;
160     }
161
162
163
164     /**
165      * Sets the switch property for this task. The property's value is
166      * determined when this task is executed (not at time of this
167      * assignment).
168      * @param property the application property to compare (non-null)
169      **/

170     public void setProperty(String JavaDoc property)
171     {
172         require_(property!=null,"setProp- nonzro name");
173         if (!m_value.isUndefined() && !m_value.isProperty()) {
174             throw new BuildException
175                 (uistrs().get("flow.switch.needs.value",
176                               getTaskName()), getLocation());
177         }
178         m_value.set(property);
179         m_value.setIsProperty(true);
180     }
181
182
183
184     /**
185      * Returns the switch property for this task. Returns <i>null</i>
186      * if never set or switch is not setup to use a property.
187      * @since JWare/AntX 0.2
188      **/

189     public final String JavaDoc getSwitchProperty()
190     {
191         return m_value.isProperty() ? m_value.get() : null;
192     }
193
194
195
196     /**
197      * Sets the switch variable for this task. The variables's value
198      * is determined when this task is executed (not at time
199      * of this assignment).
200      * @param variable the variable to compare (non-null)
201      * @since JWare/AntX 0.2
202      **/

203     public void setVariable(String JavaDoc variable)
204     {
205         require_(variable!=null,"setVar- nonzro name");
206         if (!m_value.isUndefined() && !m_value.isExported()) {
207             throw new BuildException
208                 (uistrs().get("flow.switch.needs.value",
209                               getTaskName()), getLocation());
210         }
211         m_value.set(variable);
212         m_value.setIsExported(true);
213     }
214
215
216
217     /**
218      * Returns the switch variable for this task. Returns <i>null</i>
219      * if never set or switch not setup to use a variable.
220      * @since JWare/AntX 0.2
221      **/

222     public final String JavaDoc getSwitchVariable()
223     {
224         return m_value.isExported() ? m_value.get() : null;
225     }
226
227
228
229     /**
230      * Sets the switch reference object for this task. The referenced
231      * object's string value is determined when this task is executed
232      * (not at time of this assignment). Currently only references of
233      * type String, URL, File, and Number are supported.
234      * @param refid the referenced item's identifier (non-null)
235      * @since JWare/AntX 0.2
236      **/

237     public void setReference(String JavaDoc refid)
238     {
239         require_(refid!=null,"setRef- nonzro refid");
240         if (!m_value.isUndefined() && !m_value.isReference()) {
241             throw new BuildException
242                 (uistrs().get("flow.switch.needs.value",
243                               getTaskName()), getLocation());
244         }
245         m_value.set(refid);
246         m_value.setIsReference(true);
247     }
248
249
250
251     /**
252      * Returns the switch reference object's id for this task. Returns
253      * <i>null</i> if never set or switch not setup to use a reference
254      * object.
255      * @since JWare/AntX 0.2
256      **/

257     public final String JavaDoc getSwitchReference()
258     {
259         return m_value.isReference() ? m_value.get() : null;
260     }
261
262
263
264     /**
265      * Assigns an evaluation context to this switch task. How the
266      * context is used by the different kinds of choices is not known
267      * to this task.
268      * @param refid reference to collection of key-value settings
269      * @since JWare/AntX 0.5
270      **/

271     public void setContext(Reference refid)
272     {
273         m_evalContext = refid;
274     }
275
276
277
278     /**
279      * Returns this task's evaluation context. Will return <i>null</i>
280      * if no context set explicitly.
281      * @since JWare/AntX 0.5
282      **/

283     public final Reference getContext()
284     {
285         return m_evalContext;
286     }
287
288
289
290     /**
291      * Returns <i>true</i> if none of the possible switch value types
292      * have been explicitly defined. One of the valu types (literal,
293      * property-name, variable-name, or reference-id) must be defined
294      * before this task is executed.
295      **/

296     public final boolean isUndefined()
297     {
298         return m_value.isUndefined();
299     }
300
301
302
303     /**
304      * Returns the actual value used in the switch comparisions. All
305      * modifier instructions and property resolution will been applied.
306      * Returns <i>null</i> if this task's switch value is undefined or
307      * resolves to <i>null</i>.
308      **/

309     public final String JavaDoc getVUT()
310     {
311         return m_value.getValue(getProject());
312     }
313
314
315
316     /**
317      * Returns a more human-friendly diagnostic description of broken
318      * switch value.
319      **/

320     private String JavaDoc switchvalueString()
321     {
322         String JavaDoc s = getSwitchValue();
323         if (s!=null) {
324             return s;
325         }
326         s = getSwitchProperty();
327         if (s!=null) {
328             return "property="+s;
329         }
330         s = getSwitchVariable();
331         if (s!=null) {
332             return "variable="+s;
333         }
334         s = getSwitchReference();
335         if (s!=null) {
336             return "reference="+s;
337         }
338         return "";
339     }
340
341 // ---------------------------------------------------------------------------------------
342
// Other Parameters:
343
// ---------------------------------------------------------------------------------------
344

345     /**
346      * Sets whether this taskset will abort if no match is found. Note
347      * defining a default choice effectively nullifies this option since
348      * the default will alway match.
349      * @param balk <i>true</i> if no match raises a build exception
350      * @see #getDefaultChoice
351      **/

352     public void setHaltIfNoMatch(boolean balk)
353     {
354         m_haltIfNoMatch = balk;
355     }
356
357
358     /**
359      * Returns <i>true</i> if this taskset will raise an exception if
360      * no match is found. Defaults to <i>false</i>
361      **/

362     public final boolean isHaltIfNoMatch()
363     {
364         return m_haltIfNoMatch;
365     }
366
367
368     /**
369      * Sets the property to be updated with positive match information.
370      * By default the property is set with the matching choice's value.
371      * @see #setMatchValue
372      **/

373     public void setMatchProperty(String JavaDoc property)
374     {
375         require_(property!=null,"setMtchProp- nonzro name");
376         m_matchProperty = property;
377     }
378
379
380     /**
381      * Returns name of property updated if a positive match is made.
382      * Returns <i>null</i> if never set.
383      **/

384     public final String JavaDoc getMatchProperty()
385     {
386         return m_matchProperty;
387     }
388
389
390     /**
391      * Sets the value to use when setting the {@linkplain
392      * #getMatchProperty match property}.
393      * @param propertyValue value to be used (non-null)
394      **/

395     public void setMatchValue(String JavaDoc propertyValue)
396     {
397         require_(propertyValue!=null,"setMtchVal- nonzro valu");
398         m_matchValue = propertyValue;
399     }
400
401
402     /**
403      * Returns the property value to use when setting the match
404      * property. Returns <i>null</i> if never set.
405      **/

406     public final String JavaDoc getMatchValue()
407     {
408         return m_matchValue;
409     }
410
411
412 // ---------------------------------------------------------------------------------------
413
// Match Execution:
414
// ---------------------------------------------------------------------------------------
415

416     /**
417      * Returns this switch task's default choice. If non-null and no
418      * explicit choice is matched, this task's nested items are performed.
419      * Returns <i>null</i> if this switch task has no default choice.
420      * @see #isHaltIfNoMatch
421      **/

422     public final MatchAll getDefaultChoice()
423     {
424         return m_defaultTask;
425     }
426
427
428
429     /**
430      * Initializes the default choice taskset for this switch task.
431      * Only one default taskset is acceptable.
432      **/

433     protected final void setTheDefaultChoice(MatchAll cDefault)
434     {
435         verifyIsUndefined_(m_defaultTask, cDefault);
436         m_defaultTask = cDefault;
437         m_defaultTask.setEnclosingTask(this);
438     }
439
440
441
442     /**
443      * Ensure the nested choices are configured at same time as this
444      * switch task. (Note the choice's sub-tasks aren't configured.)
445      **/

446     protected void maybeConfigureSpecialTasks()
447     {
448         Iterator JavaDoc itr= getTasksList().listIterator();
449         while (itr.hasNext()) {
450             ((ChoiceTask)itr.next()).maybeConfigure();
451         }
452         if (getDefaultChoice()!=null) {
453             getDefaultChoice().maybeConfigure();
454         }
455     }
456
457
458
459     /**
460      * Returns <i>true</i> if task is of the allowed choice types.
461      * task). The first nested choice determines the required type
462      * of all subsequent choices. You cannot mix both 'like' and
463      * 'equal' choices.
464      * @see MatchLike
465      * @see MatchEquals
466      **/

467     protected boolean includeTask(TaskHandle taskH)
468     {
469         require_(!taskH.isEmpty(),"includTsk- filld hndl");
470         Task task = taskH.getTask();
471
472         ChoiceType type = ChoiceType.from(task.getClass());
473         boolean ok= type!=null;
474
475         if (ok) {
476             if (m_dominantMatchType!=ChoiceType.NONE) {
477                 if (type!=m_dominantMatchType) { //only nest one kind
478
String JavaDoc ermsg = uistrs().get("flow.switch.case.onekind",getTaskName());
479                     log(ermsg, Project.MSG_ERR);
480                     throw new BuildException(ermsg, task.getLocation());
481                 }
482             } else {
483                 m_dominantMatchType = type;
484             }
485         }
486         return ok;
487     }
488
489
490
491     /**
492      * Ensures only ChoiceTasks added to this taskset. Looks for the
493      * special {@linkplain MatchAll} (&lt;default&gt;) element.
494      * @see #setTheDefaultChoice
495      **/

496     public void addTask(Task task)
497     {
498         require_(task!=null,"addTsk- nonzro tsk");
499
500         task = TaskExaminer.trueTask(task,COI_,this);//remove placeholders!
501

502         if (task instanceof MatchAll) {
503             setTheDefaultChoice((MatchAll)task);
504             addedTask();
505         } else {
506             super.addTask(task);
507             verify_((task instanceof ChoiceTask),"addTsk- choice tsk");
508             ((ChoiceTask)task).setEnclosingTask(this);
509         }
510     }
511
512
513
514     /**
515      * Looks (in order) for a match to this switch task's value. If
516      * no match and a default choice has been defined, it's used. The
517      * matching choice's sub-tasks are executed. If no match found and
518      * the "haltIfNoMatch" attribute is <i>true</i>, this method raises
519      * a build exception.
520      * @throws BuildExceptio if matched choice does or unable to find a
521      * match and "haltIfNoMatch" is <i>true</i>
522      **/

523     protected void performNestedTasks()
524         throws BuildException
525     {
526         String JavaDoc value = getVUT();
527         Task choiceTask = null;
528         String JavaDoc choiceValue = Strings.DEFAULT;
529
530         if (value!=null || !m_dominantMatchType.needsLeftAndRight()) {
531             Iterator JavaDoc itr = getTasksList().listIterator();
532             while (itr.hasNext()) {
533                 ChoiceTask choice = (ChoiceTask)itr.next();
534                 if (choice.eval(value, m_evalContext)) {
535                     choiceTask = choice;
536                     choiceValue = choice.getVUT();
537                     break;
538                 }
539             }
540         }
541         if (choiceTask==null && getDefaultChoice()!=null) {
542             choiceTask = getDefaultChoice();
543         }
544         if (choiceTask!=null) {
545             choiceFound(choiceValue,(value==null ? "n/a" : value));
546             choiceTask.perform();
547
548         } else if (isHaltIfNoMatch()) {
549             String JavaDoc ermsg = uistrs().get("flow.switch.nomatch",switchvalueString());
550             log(ermsg,Project.MSG_ERR);
551             throw new BuildException(ermsg,getLocation());
552         } else {
553             log("Unable to match switch-value \""+switchvalueString()+"\"",
554                 Project.MSG_DEBUG);
555         }
556     }
557
558
559
560     /**
561      * Called when a positive match is found for this switch task's
562      * value. By default updates 'matchProperty' if requested and logs
563      * a diagnostic message.
564      * @param choiceValue the hit (non-null)
565      * @param switchValue the value under test (non-null)
566      * @see #setMatchProperty
567      **/

568     protected void choiceFound(String JavaDoc choiceValue, String JavaDoc switchValue)
569     {
570         log("Found hit for '"+switchValue+"' from choice value='"+
571             choiceValue+"'", Project.MSG_DEBUG);
572
573         if (getMatchProperty()!=null) {
574             String JavaDoc what = getMatchValue();
575             if (what==null) {
576                 what = choiceValue;
577             }
578             getProject().setNewProperty(getMatchProperty(),what);
579         }
580     }
581
582
583
584     /**
585      * Ensures this switch task has its 'value' attribute defined.
586      * @throws BuildException if not in valid target/project or missing
587      * 'value' attribute
588      * @see #setValue
589      **/

590     protected void verifyCanExecute_(String JavaDoc calr)
591     {
592         super.verifyCanExecute_(calr);
593
594         if (isUndefined() && m_dominantMatchType.needsLeftAndRight()) {
595             String JavaDoc ermsg = uistrs().get("flow.switch.needs.value",getTaskName());
596             log(ermsg, Project.MSG_ERR);
597             throw new BuildException(ermsg,getLocation());
598         }
599     }
600
601
602
603     private MatchAll m_defaultTask;
604     private boolean m_haltIfNoMatch=false;//NB: don't balk if no match!
605
private String JavaDoc m_matchProperty, m_matchValue;
606     private ChoiceType m_dominantMatchType=ChoiceType.NONE;//NB: defined by first nested item
607
private FlexString m_value = new FlexString();
608     private Reference m_evalContext;
609
610     /**
611      * Controls the amount of peek-under for UnknownElement placeholders
612      * nested inside task containers.
613      * @since JWare/AntX 0.4
614      **/

615     private static final Class JavaDoc[] COI_= {
616         MatchAll.class, ChoiceTask.class
617     };
618 }
619
620 /* end-of-SwitchTask.java */
621
Popular Tags