KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * $Id: BuildRule.java 180 2007-03-15 12:56:38Z ssmc $
3  * Copyright 2002-2005 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.Stack 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.ExportedProperties;
40 import com.idaremedia.antx.NoiseLevel;
41 import com.idaremedia.antx.apis.BuildAssertionException;
42 import com.idaremedia.antx.apis.Requester;
43 import com.idaremedia.antx.starters.StrictOuterTask;
44
45 /**
46  * A shareable build rule type; usually defined as &lt;rule&gt;.
47  * <p>
48  * <b>Usage Notes</b>(also apply to {@linkplain RuleMacroDef rule macros})<b>:</b><ul>
49  * <li>
50  * Generally build rules should be declared at the project level to ensure
51  * they're completely configured and added to the project's references before any task
52  * needs/uses it.
53  * <li>
54  * The combine logic of a build rule is always a logical '<i>and</i>'; the rule's evaluation
55  * is aborted on the first failed requirement. In other words, don't use rules to
56  * create 'is-present' properties; use a real target, the &lt;condition&gt; task,
57  * or the AntX &lt;tally&gt; task to implement this common function.
58  * <li>
59  * Empty rules always evaluate "<i>true</i>".
60  * <li>
61  * Build rules cannot refer-to other build rules (using the standard 'refid' attribute);
62  * this would just be weird. Build rules are, by definition, the common bits; other
63  * rules types (like asserts and prefers) refer to rules. Note a build rule's nested
64  * conditions <em>can</em> refer to other build rules.
65  * <li>
66  * A build rule is composed of one kind-of condition: either requirements or preferences.
67  * The two kinds cannot be mixed; this way the effect (on the build process) of a
68  * failed evaluation can be predicted with reasonable certainty. &lt;prefer&gt; tasks
69  * cannot refer to build rules whose effect is build failure. Likewise &lt;require&gt;
70  * tasks cannot refer to build rules whose effect are warnings.
71  * <li>
72  * Be careful when specifying individual update properties for a rule's 'require'
73  * items. If the enclosing rule is a global rule, these properties will be set <em>once</em>
74  * in a particular project (since a Project's properties are write-once). This effect
75  * shouldn't be problematic for requirements since the idea is to <b>fail</b> on a false
76  * evaluation.
77  * <li>
78  * Be <em>really really</em> careful when specifying individual default properties for
79  * a rule's 'prefer' items. If the preference evaluates false it will default the
80  * property for the current project (always) <em>and for any child projects created
81  * when using 'ant', 'antcall', 'call', 'callforeach' and 'foreach.'</em> You have been
82  * warned. Having said that, this "velcro-ism" is often exactly the effect you want when
83  * you use prefer with defaults-- some top-level target ensures the universe is happy
84  * for all of the sub-build bits by enforcing their pre-requisites.
85  * <li>
86  * </ul>
87  * <p>
88  * <b>Rules vs. Rule-Macros?:</b><ul>
89  * <li>
90  * What's the difference between a rule and a rule macro? Well you would use a rule
91  * macro if you wanted to parameterize a rule. A rule is a single entity; if you call
92  * it from multiple sources (includes parallel threads) you're reusing a single
93  * rule. Rule macros on the other hand, create a unique instance for each invocation.
94  * <li>
95  * Rules can define top-level parameters like failure messages, etc.; macros cannot.
96  * <li>
97  * Rule macros (<span class="src">&lt;ruledef&gt;</span>) are definition tasks and
98  * can be included in standard antlib definition files (like
99  * <span class="src">&lt;typedef&gt;</span> and
100  * <span class="src">&lt;typedef&gt;</span>; rules cannot. You can assign unique
101  * namespaces, etc. (Of course you an also import your common rules.)
102  * </ul>
103  * <p>
104  * <b>Thread-safety Notes:</b><ul>
105  * <li>
106  * A build rule's thread-safety is partially dependent on a
107  * subclass's agreement not to expose its conditions publicly (where they can be
108  * modified unsafely). The first time a build rule is evaluated it freezes itself from
109  * further modification (cannot add any more rules). Aside from this check at the
110  * 'eval' method, concurrent evaluations incur no locking overhead in the nested
111  * conditions.
112  * <li>
113  * A build rule's thread-safety is definitely dependent on the thread-safety of
114  * the standard Ant conditions it supports. Even if the AntX build and other custom
115  * conditions can be evaluated concurrently, some of the inherited Ant conditions
116  * cannot. The &lt;available&gt; task/condition for example is not safe for concurrent
117  * evaluation (for the correct eyeballs, see the toggling of an internal
118  * '<code>isTask</code>' flag).
119  * </ul>
120  * <p>
121  * <b>Examples:</b><pre>
122  * &lt;rule id="j2se14-available"&gt;
123  * &lt;require msgid="msg.no.j2se14"&gt;
124  * &lt;isclass name="java.lang.StrictMath"/&gt;
125  * &lt;isclass name="javax.naming.InitialContext"/&gt;
126  * &lt;isclass name="java.nio.Buffer"/&gt;
127  * &lt;/require&gt;
128  * &lt;/rule&gt;
129  *
130  * &lt;rule id="apis-java-available" msgid="msg.missing.required.apis"&gt;
131  * &lt;require ruleid="j2se14-available"/&gt;
132  * &lt;require isclass="org.apache.log4j.Logger" msgid="msg.no.log4j.12"/&gt;
133  * &lt;require isclass="junit.framework.Assert" msgid="msg.no.junit.37"/&gt;
134  * &lt;/rule&gt;
135  *
136  * &lt;rule id="doc-labels-available-internal"&gt;
137  * &lt;fixturecheck allset="module.name,module.version"/&gt;
138  * &lt;prefer isnotwhitespace="${module.doc.title}" msgid="warn.no.doc.title"
139  * property="module.doc.title" default="${module.name} API Documentation"/&gt;
140  * &lt;prefer isnotwhitespace="${module.doc.header}" msgid="warn.no.doc.header"
141  * property="module.doc.header" default="${module.name}-${module.version}"/&gt;
142  * &lt;prefer isnotwhitespace="${module.doc.footer}" msgid="warn.no.doc.footer"
143  * property="module.doc.footer" defaultproperty="module.doc.header"/&gt;
144  * &lt;/rule&gt;
145  * </pre>
146  *
147  * @since JWare/AntX 0.2
148  * @author ssmc, &copy;2002-2005 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
149  * @version 0.5
150  * @.safety guarded
151  * @.group api,infra
152  * @see AssertTask
153  * @see PreferTask
154  **/

155
156 public class BuildRule extends RuleType implements StrictOuterTask
157 {
158     /**
159      * Initializes a new build rule.
160      **/

161     public BuildRule()
162     {
163         super(AntX.rules);
164     }
165
166
167     /**
168      * Initializes a new CV-labeled build rule.
169      * @param iam CV-label (non-null)
170      **/

171     public BuildRule(String JavaDoc iam)
172     {
173         super(iam);
174     }
175
176
177 // ---------------------------------------------------------------------------------------
178
// Parameters, Nested Elements:
179
// ---------------------------------------------------------------------------------------
180

181     /**
182      * Adds a requirement to this rule.
183      * @return new requirement
184      **/

185     public BooleanRule createRequire()
186     {
187         Requirement requirement = new Requirement();
188         includeRule(requirement);
189         requirement.setEnclosingTask(this);
190         return requirement;
191     }
192
193
194     /**
195      * Adds a preference to this rule.
196      * @return new preference
197      **/

198     public BooleanRule createPrefer()
199     {
200         Preference preference = new Preference();
201         includeRule(preference);
202         preference.setEnclosingTask(this);
203         return preference;
204     }
205
206
207     /**
208      * Adds a fixture check to this rule. This object is not
209      * actually stored anywhere in this rule. Any false inlined condition
210      * applied to the fixture check will trigger a build failure.
211      * @return new fixturecheck
212      **/

213     public BooleanRule createFixtureCheck()
214     {
215         return new VerifyFixture(true/*force-fail-quick*/);
216     }
217
218
219     /**
220      * Returns the supposed effect if this rule evaluates
221      * <i>false</i>. Should be called after this rule is fully
222      * configured.
223      **/

224     public NoiseLevel getFailureEffect()
225     {
226         return m_failureEffect;
227     }
228
229
230     /**
231      * Adds a sub-rule to this build rule. If it is the first sub-rule
232      * it determines the kind of subsequent sub-rules allowed. Otherwise,
233      * the sub-rule must of the expected (dominant) type.
234      * @param rule sub-rule to be added
235      * @throws BuildException if rule of wrong kind
236      **/

237     private void includeRule(BooleanRule rule)
238         throws BuildException
239     {
240         boolean isRequire = (rule instanceof Requirement);
241         if (m_failureEffect!=null) {
242             checkAcceptable(this,isRequire,m_failureEffect);
243         } else if (isRequire) {
244             m_failureEffect = NoiseLevel.ERROR;
245             setStopQuickEvaluation(true);
246         } else {
247             m_failureEffect = NoiseLevel.WARNING;
248             setStopQuickEvaluation(false);
249         }
250         xaddCondition(rule);
251     }
252
253
254     /**
255      * Shared test for acceptability of nested requirements and
256      * preferences. This logic must be shared by rule definitions and
257      * rule macro definitions.
258      * @param failureEffect the effect under test (non-null)
259      **/

260     static void checkAcceptable(Task from, boolean isRequire,
261                                 NoiseLevel failureEffect)
262     {
263         if ((isRequire && (!failureEffect.isAsBadAs(NoiseLevel.ERROR))) ||
264             (!isRequire && (failureEffect.isAsBadAs(NoiseLevel.ERROR)))) { //only nest one kind
265
String JavaDoc id= from.getTaskName()!=null ? from.getTaskName() : "build-rules";
266             String JavaDoc ermsg = AntX.uistrs().get("brul.only.onekind",id);
267             from.log(ermsg, Project.MSG_ERR);
268             throw new BuildException(ermsg, from.getLocation());
269         }
270     }
271
272 // ---------------------------------------------------------------------------------------
273
// Evaluation:
274
// ---------------------------------------------------------------------------------------
275

276     /**
277      * Ensures this rule instance does not contain any circular
278      * references in its definition.
279      * @param stk stack of referred-to (or used) rules (non-null)
280      * @param clnt [optional] call controls
281      * @throws BuildException if circular dependency discovered
282      * @.impl sets latch after 1st successful call
283      **/

284     public void verifyNoCircularDependency(Stack JavaDoc stk, Requester clnt)
285     {
286         if (!m_circularityChecked) {
287             if (!isEmpty()) {
288                 Iterator JavaDoc itr= getConditions().iterator();
289                 if (clnt==null) {
290                     clnt = new Requester.ForComponent(this);
291                 }
292                 while (itr.hasNext()) {
293                     Stack JavaDoc itemstk = new Stack JavaDoc();
294                     itemstk.addAll(stk);
295                     Object JavaDoc oc = itr.next();
296                     if (oc instanceof BooleanRule) {
297                         ((BooleanRule)oc).verifyNoCircularDependency(itemstk, clnt);
298                     }
299                     itemstk.clear();
300                 }
301             }
302             m_circularityChecked = true;
303         }
304     }
305
306
307
308     /**
309      * No-op; build rules must be explicitly evaluated via their
310      * shareable condition APIs to ensure they're safe for calls
311      * from multiple threads. Build rules aren't nestable.
312      **/

313     public final boolean eval()
314     {
315         //burp...loudly
316
log(uistrs().get("brul.only.shareabl.apis"),Project.MSG_WARN);
317         return false;
318     }
319
320
321
322     /**
323      * Called to record this conditon's evaluation results. For requirements
324      * a <i>false</i> result is very bad. <i>true</i> results are basically
325      * ignored.
326      * @.impl Copied from AssertTask, ssmc
327      * @throws BuildException if effect is build failure and evaluated <i>false</i>
328      **/

329     protected void setEvalResult(boolean istrue, final String JavaDoc listing)
330         throws BuildException
331     {
332         boolean likePrefer= likePrefer();
333
334         if (!istrue) {
335             String JavaDoc what = getUpdatePropertyValue();
336             String JavaDoc prop;
337
338             prop = getUpdateProperty();
339             if (prop!=null) {
340                 if (likePrefer) {
341                     getProject().setInheritedProperty(prop,what);
342                 } else {
343                     checkIfProperty_(prop,true);
344                     getProject().setNewProperty(prop,what);
345                 }
346
347                 log("Build rule (preference="+likePrefer+") was false; have set '"
348                     +prop+"' property to "+what, Project.MSG_DEBUG);
349             }
350
351             prop = getUpdateVariable();
352             if (prop!=null) {
353                 log("Build rule (preference="+likePrefer+") was false; setting '"
354                     +prop+"' variable to "+what, Project.MSG_DEBUG);
355
356                 ExportedProperties.set(prop,what);
357             }
358
359             String JavaDoc errmsg;
360             if (getMsgId()==null) {
361                 errmsg = uistrs().get("brul.failed",getId(),listing);
362             } else {
363                 errmsg = getMsg(newMsgGetter(getId(),listing));
364             }
365
366             violationOccured(errmsg);
367
368             if (!likePrefer) {
369                 throw new BuildAssertionException(errmsg, getLocation());
370             }
371         }
372     }
373
374
375     /**
376      * Called whenever this rule's final evaluation is negative.
377      * Subclasses can extend the default response which simply logs
378      * an error message.
379      * @param ermsg error message (non-null)
380      **/

381     protected void violationOccured(String JavaDoc ermsg)
382     {
383         if (ermsg==null) {
384             ermsg= uistrs().get("brul.failed.default");
385         }
386
387         int noiselevel = getFailureEffect().isAsBadAs(NoiseLevel.ERROR)
388             ? Project.MSG_ERR
389             : BooleanRule.getPreferenceMsgLevel(getProject()).getNativeIndex();
390
391         log(ermsg, noiselevel);
392     }
393
394
395     /**
396      * Returns <i>true</i> if this rule is a preference-only based
397      * rule. Looks at the failure effect of this rule; if it's anything
398      * but a WARNING then it's not like a preference.
399      * @since JWare/AntX 0.3
400      **/

401     protected final boolean likePrefer()
402     {
403         return !isStopQuickEvaluation();
404     }
405
406
407 // ---------------------------------------------------------------------------------------
408
private NoiseLevel m_failureEffect=null;//NB: unknown->defined by 1st subrule
409
}
410
411 /* end-of-BuildRule.java */
412
Popular Tags