KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > AssertableTask


1 /**
2  * $Id: AssertableTask.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;
30
31 import java.text.MessageFormat JavaDoc;
32
33 import org.apache.tools.ant.BuildException;
34 import org.apache.tools.ant.Project;
35 import org.apache.tools.ant.Task;
36
37 import com.idaremedia.apis.UIStringManager;
38
39 import com.idaremedia.antx.apis.ProjectDependent;
40 import com.idaremedia.antx.apis.Reconfigurable;
41 import com.idaremedia.antx.apis.Requester;
42 import com.idaremedia.antx.apis.ScriptLocatable;
43 import com.idaremedia.antx.helpers.Tk;
44
45 /**
46  * Extension of basic Ant <i>Task</i> that adds builtin assertions and support for
47  * resource-bundle based messages.
48  *
49  * @since JWare/AntX 0.1
50  * @author ssmc, &copy;2002-2004,2007 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
51  * @version 0.5.1
52  * @.safety guarded
53  * @.group impl,infra
54  * @see AssertableProjectComponent
55  **/

56
57 public abstract class AssertableTask extends Task
58     implements ProjectDependent, ScriptLocatable
59 {
60     /**
61      * Initializes new unlabeled task.
62      **/

63     protected AssertableTask()
64     {
65         super();
66         Iam_="";
67     }
68
69
70
71     /**
72      * Initializes new CV-labeled task.
73      * @param iam CV-label (non-null)com.idare
74      **/

75     protected AssertableTask(String JavaDoc iam)
76     {
77         super();
78         Iam_= Tk.cvlabelFrom(iam);
79     }
80
81
82
83     /**
84      * Ensures this task's {@linkplain #initonce} method is called just
85      * once. Sometimes Ant introspection mechanisms trigger mulitple calls
86      * to init. This ensure that once-only initialization code is really
87      * only called once.
88      * @since JWare/AntX 0.5
89      **/

90     public void init()
91     {
92         super.init();
93        
94         if (!m_initedOnce) {
95             initonce();
96             m_initedOnce=true;
97         }
98     }
99
100
101
102     /**
103      * Initialization that must be done at most one time. Called by
104      * {@linkplain #init} once even if init is itself called multiple
105      * times.
106      * @throws BuildException if unable to initialize required bits
107      * @since JWare/AntX 0.5
108      **/

109     protected void initonce()
110     {
111     }
112
113
114
115     /**
116      * Resets this task's msgId attribute then reconfigures.
117      **/

118     public void reconfigure()
119     {
120         if (this instanceof Reconfigurable) {
121             unconfigure();
122         } else {
123             String JavaDoc alert = uistrs().get("cv.redoable",Iam_,getTaskType());
124             log(alert,Project.MSG_INFO);
125             this.unconfigure();
126         }
127         super.reconfigure();
128         m_configuredOnce=false;
129     }
130  
131  
132  
133     /**
134      * Resets this task as if never configured. Allows reconfigurable tasks
135      * to be re-run many times. We just unset our <span class="src">msgId</span>
136      * setting.
137      * @since JWare/AntX 0.5
138      */

139     public void unconfigure()
140     {
141         m_msgId = null;
142     }
143
144
145
146     /**
147      * Workaround NPE triggered problem in super.maybeConfigure since Ant 1&#46;7.
148      * @since JWare/AntX 0.5.1
149      */

150     public void maybeConfigure()
151     {
152         if (!m_configuredOnce) {
153             super.maybeConfigure();
154             this.m_configuredOnce = true;
155         }
156     }
157
158
159
160     /**
161      * Ensures a child or contained item has the same owning target
162      * as this item if the child's is unassigned.
163      * @param newitem child item (can be <i>null</i>)
164      * @since JWare/AntX 0.5
165      **/

166     protected final void syncChildTargetIfNull(Object JavaDoc newitem)
167     {
168         //NB: necessary because of the way Ant's introspective creators
169
// work-- they do not sync parent/child target informaton!
170
if (newitem instanceof Task) {
171             Task t = (Task)newitem;
172             if (t.getOwningTarget()==null) {
173                 t.setOwningTarget(getOwningTarget());
174             }
175         }
176     }
177
178
179
180     /**
181      * Shortcut that returns this task's internal component UI
182      * strings manager. Never returns <i>null</i>. By default returns
183      * the current iteration's UI strings manager.
184      * @see Iteration#uistrs
185      **/

186     public final UIStringManager uistrs()
187     {
188         return Iteration.uistrs();
189     }
190
191
192 // ---------------------------------------------------------------------------------------
193
// (AntX) Universal Task Log Conversion (make events useful):
194
// ---------------------------------------------------------------------------------------
195

196     /**
197      * Indicate this task as source of logged message.
198      **/

199     public void log(String JavaDoc msg, int msgLevel)
200     {
201         if (getProject()!=null) {
202             getProject().log(this,msg,msgLevel);
203         } else {
204             if (msgLevel >= Project.MSG_INFO) { //NB: works around bug in Task.log!
205
System.err.println(msg);
206             }
207         }
208     }
209
210 // ---------------------------------------------------------------------------------------
211
// (AntX) Universal Task Assertion Facilities:
212
// ---------------------------------------------------------------------------------------
213

214
215     /**
216      * Returns this task's CV-label. Never <i>null</i>.
217      **/

218     public final String JavaDoc cvlabel_()
219     {
220         return Iam_;
221     }
222
223
224     /**
225      * Throws assertion error if pre-condtion is not met.
226      * @param c pre-condition
227      * @param msg [optional] failure message (if not met)
228      * @throws IllegalArgumentException if condition not met
229      **/

230     protected final void require_(boolean c, String JavaDoc msg)
231     {
232         if (!c) {
233             String JavaDoc ermsg = uistrs().get("cv.require",Iam_,msg);
234             log(ermsg, Project.MSG_ERR);
235             throw new IllegalArgumentException JavaDoc(ermsg);
236         }
237     }
238
239
240     /**
241      * Throws assertion error if post-condition is not met. Used
242      * for post-condition verification.
243      * @param c post-condition
244      * @param msg [optional] failure message (if not met)
245      * @throws IllegalStateException if condition not met
246      **/

247     protected final void ensure_(boolean c, String JavaDoc msg)
248     {
249         if (!c) {
250             String JavaDoc ermsg = uistrs().get("cv.ensure",Iam_,msg);
251             log(ermsg, Project.MSG_ERR);
252             throw new IllegalStateException JavaDoc(ermsg);
253         }
254     }
255
256
257     /**
258      * Throws assertion error if condition is not met. Used for
259      * block and invariant verification.
260      * @param c condition
261      * @param msg [optional] failure message (if not met)
262      * @throws IllegalStateException if condition not met
263      **/

264     protected final void verify_(boolean c, String JavaDoc msg)
265     {
266         if (!c) {
267             String JavaDoc ermsg = uistrs().get("cv.verify",Iam_,msg);
268             log(ermsg, Project.MSG_ERR);
269             throw new IllegalStateException JavaDoc(ermsg);
270         }
271     }
272
273
274     /**
275      * Notes an unexpected but manageable problem has occured.
276      * Just logs a warning by default.
277      * @param t [optional] causing throwable
278      * @param msg caller's additional (context) message
279      **/

280     protected final void unexpected_(Throwable JavaDoc t, String JavaDoc msg)
281     {
282         String JavaDoc ermsg = uistrs().get("cv.unexpected",Iam_,msg,t);
283         log(ermsg, Project.MSG_WARN);
284     }
285
286
287     /**
288      * Verifies we're in a live project (created from build process).
289      * @throws IllegalStateException if not in project
290      **/

291     protected final void verifyInProject_(String JavaDoc calr)
292     {
293         if (getProject()==null) {
294             String JavaDoc ermsg = uistrs().get("cv.verifyInP",Iam_,calr);
295             log(ermsg, Project.MSG_ERR);
296             throw new IllegalStateException JavaDoc(ermsg);
297         }
298     }
299
300
301     /**
302      * Verifies we're in a live target and project (created from
303      * build process).
304      * @throws IllegalStateException if not in target
305      **/

306     protected final void verifyInTarget_(String JavaDoc calr)
307     {
308         if (getOwningTarget()==null) {
309             String JavaDoc ermsg = uistrs().get("cv.verifyInT",Iam_,calr);
310             log(ermsg, Project.MSG_ERR);
311             throw new IllegalStateException JavaDoc(ermsg);
312         }
313         verifyInProject_(calr);
314     }
315
316
317     /**
318      * Called by '<i>execute</i>' on entry to verify that all required
319      * options have been specified for correct execution of this task.
320      * By default just verifies this task is associated with an enclosing
321      * project.
322      * @param calr calling method (usually 'execute' or 'run')
323      * @throws BuildException if unable to execute
324      * @throws IllegalStateException if improperly configured
325      **/

326     protected void verifyCanExecute_(String JavaDoc calr)
327         throws BuildException
328     {
329         verifyInProject_(calr);
330     }
331
332
333
334     /**
335      * Check whether a project property already exists and optionally
336      * barfs if it does. Instance-level wrapper for generic
337      * {@linkplain FixtureExaminer#checkIfProperty FixtureExaminer}
338      * method.
339      * @param property name of property to check
340      * @param warn <i>true</i> if only issue a warning <em>otherwise can fail</em>
341      * @return <i>true</i> if property already exists
342      * @throws BuildException if property exists and isn't a warning
343      * @since JWare/AntX 0.3
344      **/

345     protected final boolean checkIfProperty_(String JavaDoc property, boolean warn)
346     {
347         require_(property!=null,"chkProp- nonzro nam");
348
349         return FixtureExaminer.checkIfProperty(getProject(),
350             new Requester.ForComponent(this), property, warn);
351     }
352
353
354
355     /**
356      * Check whether a project reference already exists and optionally
357      * barfs if it does. Instance-level wrapper for generic
358      * {@linkplain FixtureExaminer#checkIfReference FixtureExaminer}
359      * method.
360      * @param refid name of reference to check
361      * @param warn <i>true</i> if only issue a warning <em>otherwise can fail</em>
362      * @return <i>true</i> if reference already exists
363      * @throws BuildException if reference exists and isn't a warning
364      * @since JWare/AntX 0.4
365      **/

366     protected final boolean checkIfReference_(String JavaDoc refid, boolean warn)
367     {
368         require_(refid!=null,"chkRef- nonzro refid");
369
370         return FixtureExaminer.checkIfReference(getProject(),
371             new Requester.ForComponent(this), refid, warn);
372     }
373
374
375     /**
376      * Returns the type-checked referenced object. Common utility that
377      * generates resource bundle based messages if reference broken.
378      * @param theProject the source project (null=> this task's project)
379      * @param refid the referred-to thing's identifier (non-null)
380      * @param requiredClass the required class of referred-to thing (non-null)
381      * @throws BuildException if no such reference or object is not compatible
382      * @since JWare/AntX 0.3
383      **/

384     public final Object JavaDoc getReferencedObject(Project theProject, String JavaDoc refid,
385                                             Class JavaDoc requiredClass)
386     {
387         require_(refid!=null,"getRefObj- nonzro id");
388
389         if (theProject==null) {
390             theProject= getProject();
391             verify_(theProject!=null,"getRefObj- hav project");
392         }
393
394         return FixtureExaminer.getReferencedObject(theProject,
395             new Requester.ForComponent(this), refid, requiredClass);
396     }
397
398 // ---------------------------------------------------------------------------------------
399
// (AntX) Universal UI strings management:
400
// ---------------------------------------------------------------------------------------
401

402
403     /**
404      * Determine whether to check msgId against project properties
405      * before checking UIStringManager. By default this task's msgid
406      * is checked against its project's properties.
407      **/

408     protected void setIgnoreProjectProperties(boolean ignored)
409     {
410         m_ignorePP= ignored ? Boolean.TRUE : Boolean.FALSE;
411     }
412
413
414     /**
415      * Returns <i>true</i> if project properties are ignored in the
416      * lookup of this task's messages.
417      * @see AntX#PROPERTY_MSGIDS_PROP
418      * @.impl Note the property is defined as positive if the build
419      * <em>allows</em> property-based msgids
420      **/

421     protected final boolean ignoreProjectProperties()
422     {
423         if (m_ignorePP==null) {
424             if (getProject()!=null) {
425                 String JavaDoc s = getProject().getProperty(AntX.PROPERTY_MSGIDS_PROP);
426                 Boolean JavaDoc B = Tk.string2PosBool(s);
427                 if (B!=null) {
428                     return !B.booleanValue();//NB: true=>allow, so ignore=>!allow
429
}
430             }
431             return true;//the-default-setting
432
}
433         return m_ignorePP.booleanValue();
434     }
435
436
437     /**
438      * Sets this task's default response message identifier.
439      * This identifer is used with a {@linkplain UIStringManager} in
440      * the ultimate concrete task subclass.
441      **/

442     public void setMsgId(String JavaDoc msgid)
443     {
444         m_msgId= msgid;
445     }
446
447
448     /**
449      * Returns this task's default response message identifier.
450      * Can return <i>null</i> if never set.
451      **/

452     public String JavaDoc getMsgId()
453     {
454         return m_msgId;
455     }
456
457
458     /**
459      * Returns the localized message associated with given id. Looks for
460      * messages using following steps:<ol>
461      * <li>Checks if msgid is a property with associated value; if
462      * value exists, it's returned. This step is skipped if this task's
463      * 'ignoreProjectProperties' flag has been set to <i>true</i>.
464      * <li>Checks if there's a message in this task's default UI strings;
465      * if message exists, it's returned.
466      * <li>Returns msgid itself. This is useful instead of using a
467      * blank string since the msgid usually reflects some semantic
468      * meaning and it notifies the builder that the message is
469      * missing.
470      * </ol>
471      * @param msgId the message id (non-null)
472      * @param getr retrieve UISM-based message (specific to API+args)
473      * @see #getUISM
474      * @see #getUISMArgs
475      * @see #setIgnoreProjectProperties
476      **/

477     public String JavaDoc getMsg(String JavaDoc msgId, MsgGetter getr)
478     {
479         require_(msgId!=null && getr!=null,"getmsg- nonzro args");
480         verifyInProject_("getMsg");
481
482         //1. local-defn
483
String JavaDoc msg = ignoreProjectProperties() ? null : getProject().getProperty(msgId);
484         if (msg==null) {
485
486             //2. uism-defn
487
msg = getr.get(msgId);
488             if (Tk.isWhitespace(msg)) {
489
490                 //3. fallback
491
msg = msgId;
492             }
493         } else if (msg.indexOf("{")>=0) {//=> a MessageFormat template
494
msg = MessageFormat.format(msg,getUISMArgs());
495         }
496
497         return msg;
498     }
499
500
501     /**
502      * Same as {@linkplain #getMsg(String, MsgGetter) getMsg(String,MsgGetter)}
503      * but with only the default message template variables inserted. Never
504      * returns <i>null</i> but can return the empty string. The default formatting
505      * automatically passes this task's name and build-file file/line information
506      * to the MessageFormat.
507      * @param getr the UIStringManager 'get' method pointer
508      **/

509     public String JavaDoc getMsg(MsgGetter getr)
510     {
511         String JavaDoc msgId = getMsgId();
512         if (msgId==null) {
513             return "";
514         }
515         return getMsg(msgId, getr);
516     }
517
518
519     /**
520      * Shortcut {@linkplain #getMsg(MsgGetter) getMsg} that returns
521      * the default msgid set on this task. Never returns <i>null</i> but
522      * can return the empty string.
523      * @see #getMsgId
524      **/

525     public String JavaDoc getMsg()
526     {
527         return getMsg(new MsgGetter() {
528                 public String JavaDoc get(String JavaDoc msgId) {
529                     return getUISM().mget(msgId,m_UISMargs,"");
530                 }
531             });
532     }
533
534
535     /**
536      * Helper that returns this task's (class) default msg noise level
537      * as if its never been specified. Subclass can change what's returned
538      * to elevate or lower the default. Never returns <i>null</i>.
539      **/

540     public NoiseLevel getDefaultMsgLevel()
541     {
542         return NoiseLevel.getDefault(getProject());
543     }
544
545
546     /**
547      * Initializes this task's default UISM arguments (taskname, location).
548      **/

549     private void getUISMDefaultArgs()
550     {
551         boolean shorten= Iteration.defaultdefaults().isShortLocationsEnabled();
552         String JavaDoc locstr= Tk.shortStringFrom(shorten, getLocation());
553         m_UISMargs= new Object JavaDoc[]{getTaskName(), locstr};
554     }
555
556
557     /**
558      * Determines this task's target UIStringManager. Looks in the current
559      * thread's iteration information for an activated UIStringManager. If
560      * one not found, defaults to the currently installed root UIStringManager;
561      * the default string manager is used only if no other string manager
562      * is installed.
563      * @see Iteration#stringManager
564      **/

565     public final UIStringManager getUISM()
566     {
567         synchronized (this) {
568             if (m_UISMargs==null) {
569                 getUISMDefaultArgs();
570             }
571         }
572         return Iteration.stringManager();
573     }
574
575
576     /**
577      * Returns a copy of this task's always-on UIStringManager arguments.
578      **/

579     public final Object JavaDoc[] getUISMArgs()
580     {
581         synchronized (this) {
582             if (m_UISMargs==null) {
583                 getUISMDefaultArgs();
584             }
585         }
586         return new Object JavaDoc[] {m_UISMargs[0],m_UISMargs[1]};
587     }
588
589
590     /**
591      * Helper that returns a new msg getter that uses UIStringManager
592      * API for one additional non-standard argument. Task's name is always
593      * for location {0} and task's declaration location is location {1}.
594      * @param arg3 1st additional argument, template location {2}
595      **/

596     public final MsgGetter newMsgGetter(final String JavaDoc arg3)
597     {
598         return new MsgGetter() {
599                 public String JavaDoc get(String JavaDoc msgId) {
600                     return getUISM().mget
601                         (msgId, new Object JavaDoc[] {m_UISMargs[0],m_UISMargs[1],
602                                               arg3});
603                 }
604             };
605     }
606
607
608     /**
609      * Helper that returns a new msg getter that uses UIStringManager
610      * API for two additional arguments.
611      * @param arg3 1st additional argument, template location {2}
612      * @param arg4 2nd additional argument, template location {3}
613      * @see #newMsgGetter(java.lang.String)
614      **/

615     public final MsgGetter newMsgGetter(final String JavaDoc arg3, final String JavaDoc arg4)
616     {
617         return new MsgGetter() {
618                 public String JavaDoc get(String JavaDoc msgId) {
619                     return getUISM().mget
620                         (msgId, new Object JavaDoc[] {m_UISMargs[0],m_UISMargs[1],
621                                               arg3, arg4});
622                 }
623             };
624     }
625
626
627     /**
628      * Helper that returns a new msg getter that uses UIStringManager
629      * API for three additional arguments.
630      * @param arg3 1st additional argument, template location {2}
631      * @param arg4 2nd additional argument, template location {3}
632      * @param arg5 3rd additional argument, template location {4}
633      * @see #newMsgGetter(java.lang.String)
634      **/

635     public final MsgGetter newMsgGetter(final String JavaDoc arg3, final String JavaDoc arg4,
636                                         final String JavaDoc arg5)
637     {
638         return new MsgGetter() {
639                 public String JavaDoc get(String JavaDoc msgId) {
640                     return getUISM().mget
641                         (msgId, new Object JavaDoc[] {m_UISMargs[0],m_UISMargs[1],
642                                               arg3, arg4, arg5});
643                 }
644             };
645     }
646
647
648     /**
649      * Returns instance of an <em>internal JWare/AntX</em> string or if
650      * not found, the message identifier itself (as a placeholder).
651      * @param msgId AntX message id (non-null)
652      * @see #uistrs
653      **/

654     public final String JavaDoc getAntXMsg(String JavaDoc msgId)
655     {
656         require_(msgId!=null,"getAntXMsg- nonzro msgId");
657         String JavaDoc msg = uistrs().get(msgId);
658         if (Tk.isWhitespace(msg)) {
659             msg = msgId;
660         }
661         return msg;
662     }
663
664
665     /**
666      * Returns instance of a custom <em>internal JWare/AntX</em> string
667      * or if not found the message identifier itself (as a placeholder).
668      * @param msgId message id
669      * @param arg1 additional argument, template location {0}
670      **/

671     public final String JavaDoc getAntXMsg(String JavaDoc msgId, String JavaDoc arg1)
672     {
673         require_(msgId!=null,"getAntXMsg- nonzro msgId");
674         String JavaDoc msg = uistrs().get(msgId, arg1);
675         if (Tk.isWhitespace(msg)) {
676             msg = msgId;
677         }
678         return msg;
679     }
680
681
682     /**
683      * Returns instance of a custom <em>internal JWare/AntX</em> string
684      * or if not found the message identifier itself (as a placeholder).
685      * @param msgId message id
686      * @param arg1 1st additional argument, template location {0}
687      * @param arg2 2nd additional argument, template location {1}
688
689      **/

690     public final String JavaDoc getAntXMsg(String JavaDoc msgId, String JavaDoc arg1, String JavaDoc arg2)
691     {
692         require_(msgId!=null,"getAntXMsg- nonzro msgId");
693         String JavaDoc msg = uistrs().get(msgId, arg1,arg2);
694         if (Tk.isWhitespace(msg)) {
695             msg = msgId;
696         }
697         return msg;
698     }
699
700
701     /**
702      * Returns instance of a custom <em>internal JWare/AntX</em> string
703      * or if not found the message identifier itself (as a placeholder).
704      * @param msgId message id
705      * @param arg1 1st additional argument, template location {0}
706      * @param arg2 2nd additional argument, template location {1}
707      * @param arg3 3rd additional argument, template location {2}
708
709      **/

710     public final String JavaDoc getAntXMsg(String JavaDoc msgId, String JavaDoc arg1, String JavaDoc arg2, String JavaDoc arg3)
711     {
712         require_(msgId!=null,"getAntXMsg- nonzro msgId");
713         String JavaDoc msg = uistrs().get(msgId, arg1,arg2,arg3);
714         if (Tk.isWhitespace(msg)) {
715             msg = msgId;
716         }
717         return msg;
718     }
719
720
721     private final String JavaDoc Iam_;
722     private String JavaDoc m_msgId;
723     private Object JavaDoc[] m_UISMargs;
724     private Boolean JavaDoc m_ignorePP=null;//NB:true => don't ask Project.properties
725
private boolean m_initedOnce;
726     private boolean m_configuredOnce;//Ant 1.7 pains
727
}
728
729 /* end-of-AssertableTask.java */
730
Popular Tags