KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * $Id: RuleTask.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.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Stack JavaDoc;
34
35 import org.apache.tools.ant.BuildException;
36 import org.apache.tools.ant.Location;
37 import org.apache.tools.ant.Project;
38 import org.apache.tools.ant.taskdefs.condition.Condition;
39 import org.apache.tools.ant.types.Reference;
40
41 import com.idaremedia.antx.AntX;
42 import com.idaremedia.antx.apis.Requester;
43
44 /**
45  * Rule that functions as a task such as an assertion or a tally. RuleTasks aren't
46  * usually embedded. This class implements support for the following:<ul>
47  * <li>Rule referrals (and all the pain that entails)
48  * <li>Template evaluation methods (single &amp; multiple conditions)
49  * </ul>
50  *
51  * @since JWare/AntX 0.2
52  * @author ssmc, &copy;2003-2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
53  * @version 0.5
54  * @.safety guarded (for evaluation <em>after</em> fully configured)
55  * @.group api,infra
56  * @see com.idaremedia.antx.condition.ShortHandConditions ShortHandConditions
57  **/

58
59 public abstract class RuleTask extends BooleanRule
60 {
61     /**
62      * Initializes a new RuleTask.
63      **/

64     protected RuleTask()
65     {
66         super(AntX.rules,false);
67     }
68
69
70     /**
71      * Initializes a new CV-labeled RuleTask.
72      * @param iam CV-label (non-null)
73      **/

74     protected RuleTask(String JavaDoc iam)
75     {
76         super(iam,false);
77     }
78
79
80     /**
81      * Initializes a new RuleTask subclass with custom embedded setting.
82      * Allows strict inner types (like Requirement) to reuse rule task's
83      * internals while being defined as a rule type.
84      * @param iam CV-label
85      * @param embed <i>true</i> if embedded
86      **/

87     protected RuleTask(String JavaDoc iam, boolean embed)
88     {
89         super(iam,embed);
90     }
91
92
93 // ---------------------------------------------------------------------------------------
94
// Managing Rule's Conditions:
95
// ---------------------------------------------------------------------------------------
96

97     /**
98      * Appends new condition to this rule's conditions sequence.
99      * @param c new condition (non-null)
100      * @.safety single
101      * @throws BuildException if this rule has a referral defined
102      * or is frozen
103      **/

104     public final void xaddCondition(Condition c)
105     {
106         if (isReferral()) {
107             throw new BuildException
108                 (uistrs().get("task.too.many.attrs"),getLocation());
109         }
110         super.xaddCondition(c);
111         edited("addCond");
112     }
113
114
115     /**
116      * Adds a single and only condition to this rule. If at least
117      * one other rule exists, this method returns <i>false</i>;
118      * otherwise, returns <i>true</i>. Caller is expected to react
119      * with appropriate exception if unable to add root condition.
120      * @param c new root conditon (non-null)
121      * @return <i>true</i> if could add as root condition
122      * @.safety single
123      * @throws BuildException if this rule has a referral defined
124      * or is frozen
125      **/

126     public final boolean xaddRootCondition(Condition c)
127     {
128         if (isReferral()) {
129             throw new BuildException
130                 (uistrs().get("task.too.many.attrs"),getLocation());
131         }
132         boolean ok = super.xaddRootCondition(c);
133         if (ok) {
134             edited("addCond");
135         }
136         return ok;
137     }
138
139 // ---------------------------------------------------------------------------------------
140
// Evaluation Template Methods:
141
// ---------------------------------------------------------------------------------------
142

143     /**
144      * Default evaluation result handler method. Assigns this rule's
145      * update-property value to this rule's update-property iff this
146      * property isn't already defined.
147      **/

148     protected void setEvalResult(boolean istrue, String JavaDoc listing)
149     {
150         String JavaDoc up = getUpdateProperty();
151         if (up!=null) {
152             if (istrue) {
153                 String JavaDoc upv = getUpdatePropertyValue();
154                 log("RuleTask's condition true; setting '"+up+ "' to "+upv,
155                     Project.MSG_DEBUG);
156
157                 checkIfProperty_(up,true);
158                 getProject().setNewProperty(up, upv);
159
160             } else {
161                 log("RuleTask's condition false; not setting '"+up+"'",
162                     Project.MSG_DEBUG);
163             }
164         }
165     }
166
167
168     /**
169      * Ensure this rule task does not contain any circular references
170      * in its definition.
171      * @param stk stack of referred-to (or used) rules (non-null)
172      * @param clnt call controls (non-null)
173      * @throws BuildException if circular dependency discovered
174      **/

175     public void verifyNoCircularDependency(Stack JavaDoc stk, Requester clnt)
176     {
177         if (!m_circularityChecked) {
178             if (isReferral()) {
179                 ShareableCondition referral= getReferral();
180                 if (stk.contains(referral)) {
181                     String JavaDoc refId = getReferralReference().getRefId();
182                     String JavaDoc ermsg = uistrs().get("brul.circular.referals",refId);
183                     clnt.problem(ermsg,Project.MSG_ERR);
184                     throw new BuildException(ermsg,clnt.getLocation());
185                 }
186                 stk.push(referral);
187                 if (referral instanceof BooleanRule) {
188                     ((BooleanRule)referral).verifyNoCircularDependency(stk,clnt);
189                 }
190                 stk.pop();
191             } else if (this instanceof ShareableCondition) {//NB:!yikes! an-error?
192
if (stk.contains(this)) {
193                     String JavaDoc ermsg = uistrs().get("brul.circular.referals",getId());
194                     clnt.problem(ermsg,Project.MSG_ERR);
195                     throw new BuildException(ermsg,clnt.getLocation());
196                 }
197             }
198             m_circularityChecked = true;
199         }
200     }
201
202
203     /**
204      * This rule task's default evaluation strategy for a single root
205      * condition. If this rule contains multiple or no conditions
206      * a build exception is thrown. Expects all execution
207      * pre-conditions have been evaluated by caller. An empty rule
208      * is considered a problem state.
209      * @see #getRootCondition
210      * @return condition evaluated value
211      * @throws BuildException if this rule is empty or has more than
212      * one condition
213      **/

214     protected final boolean defaultSingleConditionEval()
215         throws BuildException
216     {
217         Condition c = getRootCondition();
218
219         if (c==null) {
220             String JavaDoc msgid= isEmpty()
221                 ? "brul.err.atleast.one.condition"
222                 : "brul.err.only.one.condition";
223             String JavaDoc ermsg = uistrs().get(msgid);
224             log(ermsg,Project.MSG_ERR);
225             throw new BuildException(ermsg, getLocation());
226         }
227
228         boolean istrue = c.eval();
229         setEvalResult(istrue,getConditionNames(1));
230         return istrue;
231     }
232
233
234     /**
235      * This rule task's default evaluation strategy for multiple conditions
236      * with a single combining logic operator ('and' or 'or'). Expects
237      * all execution pre-conditions have been evaluated by caller. An empty
238      * rule is considered a problem state.
239      * @see #getDefaultCombineOperator
240      * @return condition evaluated value
241      * @throws BuildException if this rule is empty
242      **/

243     protected final boolean defaultMultipleConditionEval()
244         throws BuildException
245     {
246         List JavaDoc l= getConditions();
247
248         if (!l.isEmpty()) {
249
250             int N=0;
251             boolean stopASAP= isStopQuickEvaluation(); //@since AntX-0.3
252
Boolean JavaDoc answer = null;
253             boolean isOR = Operator.OR.equals(getDefaultCombineOperator());
254             boolean isAND = !isOR;
255
256             Iterator JavaDoc itr= l.iterator();
257             while (itr.hasNext()) {
258                 boolean t = ((Condition)itr.next()).eval();
259                 N++;
260                 if (t) {
261                     if (isOR) {
262                         answer=Boolean.TRUE;
263                         if (stopASAP) {
264                             break;//already ok
265
}
266                     }
267                 } else if (isAND) {
268                     answer= Boolean.FALSE;
269                     if (stopASAP) {
270                         break;//already busted
271
}
272                 }
273             }
274             boolean istrue;
275             if (answer!=null) {
276                 istrue= answer.booleanValue();
277             } else if (isOR) {
278                 istrue= N!=l.size();
279             } else {
280                 istrue= N==l.size();
281             }
282             setEvalResult(istrue,getConditionNames(N));
283             return istrue;
284         }
285
286         String JavaDoc ermsg= uistrs().get("brul.err.atleast.one.condition");
287         log(ermsg,Project.MSG_ERR);
288         throw new BuildException(ermsg, getLocation());
289     }
290
291
292     /**
293      * Helper to determine if this task should run as a referral.
294      * @.sideeffect if this rule is a referral this method ensures the referred-to
295      * rule is compatible with this task.
296      * @.sideeffect verify that there are no circular dependencies in
297      * this task's rule-chain
298      **/

299     protected final synchronized boolean runReferral()
300     {
301         if (isReferral()) {
302             if (!m_circularityChecked) {
303                 verifyNoCircularDependency(new Stack JavaDoc(),
304                     new Requester.ForComponent(this));
305             }
306             return true;
307
308         } else if (!m_circularityChecked) {
309             if (!isEmpty()) {
310                 Stack JavaDoc stk= new Stack JavaDoc();
311                 Iterator JavaDoc itr= getConditions().iterator();
312                 while (itr.hasNext()) {
313                     Object JavaDoc oc = itr.next();
314                     if (oc instanceof BooleanRule) {//=>We allow nested rules!
315
((BooleanRule)oc).verifyNoCircularDependency
316                             (stk, new Requester.ForComponent(this));
317                     }
318                     stk.clear();
319                 }
320             }
321             m_circularityChecked = true;
322         }
323         return false;
324     }
325
326 // ---------------------------------------------------------------------------------------
327
// Shared Rule Usage/Definition Support:
328
// ---------------------------------------------------------------------------------------
329

330     /**
331      * Converts a rule referral to a living-breathing-twitching rule.
332      * The reference must be a {@linkplain ShareableCondition shareable}
333      * rule.
334      * @param r the referenced rule
335      * @throws BuildException if reference is bogus
336      * @see #isIncompatibleReferral
337      **/

338     protected final ShareableCondition getReferencedReferral(Reference r)
339     {
340         require_(r!=null,"refToObj- nonzro refid");
341
342         Object JavaDoc object = r.getReferencedObject(getProject());
343         if (object instanceof ShareableCondition) {
344             return ((ShareableCondition)object);
345         }
346         String JavaDoc ermsg = uistrs().get("brul.bad.ruleid",r.getRefId());
347         log(ermsg,Project.MSG_ERR);
348         throw new BuildException(ermsg);
349     }
350
351
352
353     /**
354      * Determine if the given referral is compatible with this rule.
355      * @return <i>true</i> if the referred-to-rule is incompatible
356      **/

357     protected abstract boolean isIncompatibleReferral(ShareableCondition rule);
358
359
360
361     /**
362      * Setup this rule to evaluate as its own definition another
363      * shareable rule. Saves the referral's reference for conversion
364      * to a livin' rule object when needed.
365      * @param r referral's reference (non-null)
366      * @throws BuildException if this rule already has conditions
367      **/

368     protected final void setReferralReference(Reference r)
369     {
370         require_(r!=null,"setReferalId- nonzro ref");
371         checkModify("setReferalId");
372
373         if (isIndependentlyEdited() || !isEmpty()) {
374             throw new BuildException
375                 (uistrs().get("task.too.many.attrs"),getLocation());
376         }
377         m_referralReference = r;
378     }
379
380
381
382     /**
383      * Returns this task's referral's original reference. Returns
384      * <i>null</i> if no reference set.
385      **/

386     protected final Reference getReferralReference()
387     {
388         return m_referralReference;
389     }
390
391
392
393     /**
394      * Returns <i>true</i> if this rule should evaluate another rule
395      * as its own definition.
396      **/

397     protected boolean isReferral()
398     {
399         return getReferralReference()!=null;
400     }
401
402
403
404     /**
405      * Returns this rule's refer-to build rule reference. Returns
406      * <i>null</i> if this task does not have a referral.
407      * @see #isReferral
408      * @throws BuildException if live referral is incompatible with this task
409      **/

410     protected final synchronized ShareableCondition getReferral()
411     {
412         if (m_referral==null && m_referralReference!=null) {
413             ShareableCondition rule = getReferencedReferral(m_referralReference);
414             if (isIncompatibleReferral(rule)) {
415                 String JavaDoc ermsg = uistrs().get("brul.referal.mismatch",
416                                             m_referralReference.getRefId(),getTaskName());
417                 log(ermsg, Project.MSG_ERR);
418                 throw new BuildException(ermsg,getLocation());
419             }
420             m_referral = rule;
421         }
422         return m_referral;
423     }
424
425
426
427     /**
428      * Returns <i>true</i> if attributes other than the referral have
429      * been defined.
430      **/

431     protected final boolean isIndependentlyEdited()
432     {
433         return m_attrsEdited>0;
434     }
435
436
437
438     /**
439      * Increments the non-referral attribute modified count; if user tries
440      * to subsequently set this item to a referral, it veill die
441      * very big.
442      **/

443     protected void edited(String JavaDoc what)
444     {
445         m_attrsEdited++;
446     }
447
448
449 // ---------------------------------------------------------------------------------------
450

451     /**
452      * Adapter for a RuleTask that is itself a user of a shareable condition.
453      *
454      * @since JWare/AntX 0.2
455      * @author ssmc, &copy;2002-2003 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
456      * @version 0.5
457      * @.safety multiple
458      * @.group impl,infra
459      * @see RuleTask#setReferralReference
460      **/

461     public class Referee implements ShareableConditionUser
462     {
463         /**
464          * Initializes RuleTask that uses shared rules.
465          **/

466         public Referee()
467         { }
468
469         /**
470          * Returns the source rule task's msgid.
471          **/

472         public String JavaDoc getMsgId()
473         {
474             return RuleTask.this.getMsgId();
475         }
476
477         /**
478          * Returns the source rule task's location.
479          **/

480         public Location getLocation()
481         {
482             return RuleTask.this.getLocation();
483         }
484
485         /**
486          * Returns the source rule task's update property.
487          **/

488         public String JavaDoc getUpdateProperty()
489         {
490             return RuleTask.this.getUpdateProperty();
491         }
492
493         /**
494          * Returns the source rule task's update variable.
495          **/

496         public String JavaDoc getUpdateVariable()
497         {
498             return RuleTask.this.getUpdateVariable();
499         }
500
501         /**
502          * Returns the source rule task's update value.
503          **/

504         public String JavaDoc getUpdateValue()
505         {
506             return RuleTask.this.getUpdatePropertyValue();
507         }
508     }
509
510 // ---------------------------------------------------------------------------------------
511
// Seekrit Members:
512
// ---------------------------------------------------------------------------------------
513

514     private Reference m_referralReference;//NB:none
515
private ShareableCondition m_referral;//NB:none
516
private int m_attrsEdited;//NB: to zap refid+others
517

518     /** Latch that is <i>true</i> if already verified against circularity checks. **/
519     private boolean m_circularityChecked;//NB:nope
520
}
521
522 /* end-of-RuleTask.java */
523
Popular Tags