KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > condition > solo > BooleanRule


1 /**
2  * $Id: BooleanRule.java 180 2007-03-15 12:56:38Z ssmc $
3  * Copyright 2003-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.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://www.jware.info EMAIL- inquiries@jware.info
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.condition.solo;
30
31 import java.util.ArrayList JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35
36 import org.apache.tools.ant.BuildException;
37 import org.apache.tools.ant.Location;
38 import org.apache.tools.ant.Project;
39 import org.apache.tools.ant.taskdefs.condition.Condition;
40
41 import com.idaremedia.antx.AntX;
42 import com.idaremedia.antx.AssertableTask;
43 import com.idaremedia.antx.FlexString;
44 import com.idaremedia.antx.NoiseLevel;
45 import com.idaremedia.antx.apis.AntLibFriendly;
46 import com.idaremedia.antx.helpers.Strings;
47 import com.idaremedia.antx.helpers.Tk;
48 import com.idaremedia.antx.parameters.EnumSkeleton;
49 import com.idaremedia.antx.starters.Chainable;
50
51 /**
52  * Sequence of one or more true|false conditions. A boolean's conditions are usually
53  * evaluated in the order in which they're added. BooleanRule is modeled after the
54  * standard <i>ConditionBase</i>, but is more amenable to extension "the AntX-way"
55  * than the standard Ant task. A boolean rule when exposed as a type should be placed
56  * at a project's top level or within a fixture definition container.
57  * <p>
58  * <b>Implementation Notes:</b><br>
59  * Changes to a boolean rule are not guarded for concurrent modification. We expect
60  * a rule to be fully configured (and optionally frozen) before it is exposed for
61  * use (optionally from multiple threads).
62  *
63  * @since JWare/AntX 0.1
64  * @author ssmc, &copy;2003-2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
65  * @version 0.5
66  * @.safety multiple for evaluation <em>after</em> fully configured
67  * @.group api,infra
68  **/

69
70 public abstract class BooleanRule extends AssertableTask
71     implements Condition, Chainable, AntLibFriendly
72 {
73     /**
74      * A rule's combining logic selector. Only two options: or'ed or and'ed.
75      * @since JWare/AntX 0.1
76      * @author ssmc
77      * @.safety multiple
78      * @.group api,infra
79      **/

80     public static final class Operator extends EnumSkeleton
81     {
82         /** Index of {@linkplain #OR OR}. **/
83         public static final int OR_INDEX = 0;
84
85         /** VM-shareable instance of 'or' operator. **/
86         public static final Operator OR = new Operator("or");
87
88         /** Index of {@linkplain #AND AND}. **/
89         public static final int AND_INDEX = OR_INDEX+1;
90
91         /** VM-shareable instance of 'and' operator. **/
92         public static final Operator AND = new Operator("and");
93
94
95         /** Required bean void constructor for Ant's introspector. **/
96         public Operator() {
97             super();
98         }
99
100         /** Private constructor used to create our singletons. **/
101         private Operator(String JavaDoc v) {
102             super(v);
103         }
104
105         /** Returns copy of all possible values as ordered string
106             array. Must be in same order as public *_INDEX. **/

107         public String JavaDoc[] getValues() {
108             return new String JavaDoc[]{"or","and"};
109         }
110
111         /** Helper that converts a string to a known operator
112             singleton. Returns <i>null</i> if string unrecognized. **/

113         public static Operator from(String JavaDoc s) {
114             if (s!=null) {
115                 s= Tk.lowercaseFrom(s);
116                 if (OR.value.equals(s)) { return OR; }
117                 if (AND.value.equals(s)) { return AND; }
118             }
119             return null;
120         }
121
122         /** Converts a string to a known operator, with a default
123             operator value if string unrecognized. **/

124         public static Operator from(String JavaDoc s, Operator dfltOp) {
125             Operator op= from(s);
126             return (op==null) ? dfltOp : op;
127         }
128     }//clas:Operator
129

130 // ---------------------------------------------------------------------------------------
131
// Construction:
132
// ---------------------------------------------------------------------------------------
133

134     /**
135      * Initializes a new embedded boolean rule.
136      **/

137     protected BooleanRule()
138     {
139         super(AntX.rules);
140         m_rules = new ArrayList JavaDoc(INITIAL_CAPACITY);
141         m_rulesRO = Collections.unmodifiableList(m_rules);
142     }
143
144
145     /**
146      * Initializes a new (embedded) CV-labeled boolean rule.
147      * @param iam CV-label (non-null)
148      **/

149     protected BooleanRule(String JavaDoc iam)
150     {
151         super(iam);
152         m_rules = new ArrayList JavaDoc(INITIAL_CAPACITY);
153         m_rulesRO = Collections.unmodifiableList(m_rules);
154     }
155
156
157     /**
158      * Initializes a new CV-labeled boolean rule with custom
159      * embedded setting.
160      * @param iam cv-label (non-null)
161      * @param embedded <i>false</i> if this rule is not embedded
162      **/

163     protected BooleanRule(String JavaDoc iam, boolean embedded)
164     {
165         this(iam);
166         setEmbedded(embedded);
167     }
168
169
170     /**
171      * Initializes the enclosing project for this rule. Also
172      * updates internal project-component helpers.
173      **/

174     public void setProject(Project project)
175     {
176         super.setProject(project);
177         m_updateValue.setProject(project);
178     }
179
180
181     /**
182      * Returns whether this rule is embedded (and acting more
183      * like a component or type and not a standalone task).
184      **/

185     protected final boolean isEmbedded()
186     {
187         return m_embedded;
188     }
189
190
191     /**
192      * Flags this rule as either embedded or not. Should be set
193      * at construction.
194      * @.safety single
195      **/

196     protected final void setEmbedded(boolean isE)
197     {
198         m_embedded= isE;
199     }
200
201
202 // ---------------------------------------------------------------------------------------
203
// Common rule functionality helpers:
204
// ---------------------------------------------------------------------------------------
205

206     /**
207      * Sets this rule's default combining logic.
208      * @param op new combining logic operator (non-null)
209      **/

210     protected final void setDefaultCombineOperator(Operator op)
211     {
212         require_(op!=null,"setDfltOp- nonzro op");
213         checkModify("setDfltOp");
214         m_defaultOperator = op;
215     }
216
217
218     /**
219      * Returns this rule's default combining logic operator.
220      * Never return <i>null</i>. Defaults to {@linkplain Operator#AND
221      * AND}.
222      **/

223     protected final Operator getDefaultCombineOperator()
224     {
225         return m_defaultOperator;
226     }
227
228
229     /**
230      * Sets whether this rule task will quick-stop its evaluation.
231      * When quick-stop is <i>true</i> (the default) the default evaluation
232      * methods should stop as soon as the evaluation result can be
233      * determined (leaving unevaluated conditions if necessary). In the
234      * case of "or" this means stopping on the first true-condition; in
235      * the case of "and" this means stopping on the first false-condition.
236      * If quick-stop is turned off, all conditions are evaluated. This
237      * is useful for tallying tasks and rules that want all conditions
238      * evaluated regardless of the outcome.
239      * @since JWare/AntX 0.3
240      **/

241     protected final void setStopQuickEvaluation(boolean quikstop)
242     {
243         m_quickStop = quikstop;
244     }
245
246
247     /**
248      * Returns <i>true</i> if default rule evaluation should stop as
249      * soon as the final result can be determined. Defaults to
250      * <i>true</i>.
251      * @since JWare/AntX 0.3
252      **/

253     protected final boolean isStopQuickEvaluation()
254     {
255         return m_quickStop;
256     }
257
258
259     /**
260      * Defines the property to be set on a negative evaluation.
261      * @param pn property name (non-whitespace)
262      **/

263     protected void setUpdateProperty(String JavaDoc pn)
264     {
265         require_(pn!=null && pn.length()>0,"setUpdtProp- nonwspc nam");
266         checkModify("setUpdtProp");
267         m_updateProperty = pn;
268     }
269
270
271     /**
272      * Returns name of property to be set if this rule evaluates
273      * <i>false</i>. Returns <i>null</i> if property name never
274      * set.
275      **/

276     protected String JavaDoc getUpdateProperty()
277     {
278         return m_updateProperty;
279     }
280
281
282     /**
283      * Defines the value to which this rule's update-property will
284      * be set. Defaults to string "<i>true</i>".
285      * @param pv property value (non-whitespace)
286      **/

287     protected void setUpdatePropertyValue(String JavaDoc pv)
288     {
289         require_(pv!=null && pv.length()>0,"setUpdtValu- nonwspc val");
290         checkModify("setUpdtValu");
291         m_updateValue.set(pv);
292         m_updateValue.setIsLiteral();
293     }
294
295
296     /**
297      * Returns the underlying flexible value to update properties
298      * and/or variables if this rule evaluates <i>false</i>. Never
299      * returns <i>null</i>.
300      * @since JWare/AntX 0.3
301      **/

302     protected final FlexString getUpdatePropertyFlexValue()
303     {
304         return m_updateValue;
305     }
306
307
308     /**
309      * Returns value of update-property used if this rule evaluates
310      * <i>false</i>. Returns <i>true</i> by default; never returns
311      * <i>null</i>.
312      **/

313     protected String JavaDoc getUpdatePropertyValue()
314     {
315         return String.valueOf(m_updateValue.getValue());
316     }
317
318
319     /**
320      * Sets name of modifiable property to be set on a negative
321      * evaluation.
322      * @param pn the property's name (non-null)
323      **/

324     protected void setUpdateVariable(String JavaDoc pn)
325     {
326         require_(pn!=null && pn.length()>0,"setUpdtVar- nonzro varnam");
327         checkModify("setUpdtVar");
328         m_updateVariable = pn;
329     }
330
331
332     /**
333      * Returns name of modifiable property to be set if this
334      * rule evaluates <i>false</i>. Returns <i>null</i> if
335      * variable name never set.
336      **/

337     protected String JavaDoc getUpdateVariable()
338     {
339         return m_updateVariable;
340     }
341
342
343     /**
344      * Tries to return an unique identifier for this rule. Never returns
345      * <i>null</i>.
346      **/

347     public String JavaDoc getId()
348     {
349         if (getLocation()!=Location.UNKNOWN_LOCATION) {
350             return getTaskName()+"@"+getLocation().toString();
351         }
352         return getTaskName()+"@"+String.valueOf(System.identityHashCode(this));
353     }
354
355
356     /**
357      * Returns the preferred failed-preference noise level. Returns
358      * <i>warning</i> if not defined in project property. Never returns
359      * <i>null</i>.
360      * @see AntX#PROPERTY_FALSE_PREFER_NOISELEVEL_PROP
361      * @param P [optional] project from which noiselevel property read
362      **/

363     public final static NoiseLevel getPreferenceMsgLevel(Project P)
364     {
365         String JavaDoc s = Tk.getTheProperty
366             (P, AntX.PROPERTY_FALSE_PREFER_NOISELEVEL_PROP);
367
368         NoiseLevel nl= NoiseLevel.WARNING;
369         if (s!=null) {
370             nl = NoiseLevel.from(s,nl);
371         }
372         return nl;
373     }
374
375
376 // ---------------------------------------------------------------------------------------
377
// Managing Rule's Conditions:
378
// ---------------------------------------------------------------------------------------
379

380     /**
381      * Returns the underlying conditions list. Never returns <i>null</i>.
382      **/

383     private List JavaDoc getConditionsList()
384     {
385         return m_rules;
386     }
387
388
389     /**
390      * Appends new condition to this rule's conditions sequence.
391      * @param c new condition (non-null)
392      * @.safety single
393      * @throws BuildException if this rule is frozen
394      **/

395     public void xaddCondition(Condition c)
396     {
397         require_(c!=null,"addInrRul- nonzro rul");
398         checkModify("addRul");
399
400         getConditionsList().add(c);
401     }
402
403
404     /**
405      * Adds the first and only condition of this rule. If other
406      * conditions already exist, this method returns <i>false</i>;
407      * otherwise, it returns <i>true</i>. (Caller is expected to react
408      * with appropriate exception if unable to add root condition.)
409      * @param c new root conditon (non-null)
410      * @return <i>true</i> if could add as root condition
411      * @.safety single
412      * @throws BuildException if this rule is frozen
413      **/

414     public boolean xaddRootCondition(Condition c)
415     {
416         require_(c!=null,"add1Rul- nonzro rul");
417         checkModify("add1Rul");
418
419         List JavaDoc l= getConditionsList();
420         if (!l.isEmpty()) {
421             return false;
422         }
423         l.add(c);
424         return true;
425     }
426
427
428     /**
429      * Returns a <em>readonly</em> view of this rule's underlying
430      * conditions sequence. Never returns <i>null</i>. For use by
431      * subclasses. While the list is readonly, its individual condition
432      * elements are not.
433      **/

434     protected final List JavaDoc getConditions()
435     {
436         return m_rulesRO;
437     }
438
439
440     /**
441      * Convenience method that returns <i>true</i> if this rule's
442      * underlying conditions list is empty.
443      **/

444     protected final boolean isEmpty()
445     {
446         return m_rulesRO.isEmpty();
447     }
448
449
450     /**
451      * Convenience method to return a supposedly single root condition.
452      * Returns <i>null</i> if this rule is empty or contains more than one
453      * condition (caller is expected to react with appropriate
454      * exception).
455      **/

456     protected final Condition getRootCondition()
457     {
458         List JavaDoc list= getConditions();
459         if (list.size()!=1) {
460             return null;
461         }
462         return (Condition)list.get(0);
463     }
464
465
466     /**
467      * Creates list of the first 'N' conditions in this rule. Returns
468      * the string "<i>none</i>" if this rule is empty or zero conditions
469      * requested.
470      * @param N number of conditions to include (1-based)
471      **/

472     protected String JavaDoc getConditionNames(final int N)
473     {
474         List JavaDoc cl= getConditionsList();
475         if (cl.isEmpty() || N==0) {
476             return Strings.NONE;
477         }
478         StringBuffer JavaDoc sb= new StringBuffer JavaDoc(300);
479         int i=0;
480         sb.append(getDefaultCombineOperator().getValue().toUpperCase());
481         sb.append('[');
482         Iterator JavaDoc itr= cl.iterator();
483         while (itr.hasNext()) {
484             if (i!=0) { sb.append(','); }
485             sb.append(Tk.leafNameFrom(itr.next().getClass()));
486             i++;
487             if (i==N) {
488                 break;
489             }
490         }
491         sb.append(']');
492         return sb.toString();
493     }
494
495
496     /**
497      * Freezes this rule against further modification. Caller should ensure
498      * that this rule has been fully configured <em>before</em> freezing it.
499      * Subclasses that override this method must call this inherited
500      * implementation <em>first</em>. Because of how Ant configures its
501      * objects, this method should never be called from a constructor.
502      **/

503     public void freezeDefinition()
504     {
505         setFrozen();
506     }
507
508
509     /**
510      * Toggles this rule's frozen flag on. This step is extracted to ensure
511      * a composite rule can first flag itself as frozen while it traverses
512      * its sub-rules. Once frozen a rule cannot be unfrozen.
513      **/

514     protected final void setFrozen()
515     {
516         m_isFrozen = true;
517     }
518
519
520     /**
521      * Returns <i>true</i> if this rule is already frozen.
522      **/

523     protected final boolean isFrozen()
524     {
525         return m_isFrozen;
526     }
527
528
529     /**
530      * Verifies that this rule isn't frozen against further changes.
531      * @throws IllegalStateException if this rule is frozen
532      **/

533     protected final void checkModify(String JavaDoc who)
534     {
535         require_(!m_isFrozen,who+"- not frozen");
536     }
537
538
539 // ---------------------------------------------------------------------------------------
540
// Evaluation Template Methods:
541
// ---------------------------------------------------------------------------------------
542

543     /**
544      * Required evaluation result handler method. Should be called
545      * post-evaluation before returning results.
546      * @param istrue result of evaluation
547      * @param listing listing of conditions executed to reach result
548      **/

549     protected abstract void setEvalResult(boolean istrue, String JavaDoc listing);
550
551
552
553     /**
554      * Hook to execute this rule as a standard Ant task. Exactly
555      * same as evaluation if this is not an embedded rule.
556      * @throws BuildException if this rule mis-configured
557      **/

558     public void execute() throws BuildException
559     {
560         if (!isEmbedded()) {
561             eval();
562         }
563     }
564
565
566 // ---------------------------------------------------------------------------------------
567
// Support for Cloneable datatype derivatives:
568
// ---------------------------------------------------------------------------------------
569

570     /**
571      * Creates an independent list of sub-conditions for the new
572      * cloned rule. The conditions are <em>not</em> themselves cloned.
573      * @.safety single
574      * @since JWare/AntX 0.3
575      **/

576     protected void cloneInternals(BooleanRule copy)
577     {
578         copy.m_rules = (ArrayList JavaDoc)m_rules.clone();
579         copy.m_rulesRO = Collections.unmodifiableList(m_rules);
580     }
581
582 // ---------------------------------------------------------------------------------------
583
// Seekrit Members:
584
// ---------------------------------------------------------------------------------------
585

586     /** Shared debug message bits for all only-one-root condition checks. **/
587     protected static final String JavaDoc ONLY_ONE= "- only one condition in rule";
588     private static final int INITIAL_CAPACITY=5;
589
590     private ArrayList JavaDoc m_rules;//NB:fixed by ctor|clone
591
private List JavaDoc m_rulesRO;//NB:fixed by ctor|clone
592

593     private Operator m_defaultOperator= Operator.AND;
594     private String JavaDoc m_updateProperty;//NB:none
595
private String JavaDoc m_updateVariable;//NB:none
596
private FlexString m_updateValue= new FlexString(Strings.TRUE);
597     private boolean m_embedded=true;//NB:set-once-at-ctor
598
private volatile boolean m_isFrozen;//NB:false
599
private boolean m_quickStop=true;//NB:stop-as-soon-as-can
600
}
601
602 /* end-of-BooleanRule.java */
603
Popular Tags