KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > feedback > EmitConfigureTask


1 /**
2  * $Id: EmitConfigureTask.java 180 2007-03-15 12:56:38Z ssmc $
3  * Copyright 2002-2003,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.feedback;
30
31 import org.apache.tools.ant.BuildException;
32 import org.apache.tools.ant.Project;
33 import org.apache.tools.ant.types.Reference;
34
35 import com.idaremedia.apis.DiagnosticsEmitter;
36 import com.idaremedia.apis.DiagnosticsEmitterFactory;
37
38 import com.idaremedia.antx.AntX;
39 import com.idaremedia.antx.FixtureOverlay;
40 import com.idaremedia.antx.NoiseLevel;
41 import com.idaremedia.antx.apis.BuildError;
42 import com.idaremedia.antx.apis.ProblemHandler;
43 import com.idaremedia.antx.helpers.Setting;
44 import com.idaremedia.antx.starters.TaskSet;
45
46 /**
47  * A scoped configuration task that defines default emit configuration for its enclosed
48  * tasks. The build script can inline the configuration definition using task parameters
49  * or through a previously declared {@linkplain EmitConfiguration} object (to which the
50  * task is made to refer).
51  * <p>
52  * <b>For example:</b><pre>
53  * &lt;<b>overlay-emit</b>
54  * from="builds.nightly.antx.compile"
55  * noiseLevel="verbose"
56  * echo="yes"
57  * timestamp="yes"
58  * properties="javac.debug,javac.opt,javac.depend,javac.classpath"
59  * emitterFactory="jware.antx.helpers.SilentEmitterFactory"
60  * timestampFormat="HH:MM:ss dd-MMM-YYYY"
61  * withDefaults="builds.nightly.log.configuration"&gt;
62  * &lt;emit msgid="BlastOff"/&gt;
63  * &lt;emitlogs&gt;
64  * ...
65  * &lt;/emitlogs&gt;
66  * &lt;/overlay-emit&gt;
67  *
68  * -OR- (better)
69  *
70  * &lt;emitconfiguration id="antx.nightly.builds"
71  * from="builds.nightly.antx.compile".../&gt;
72  * &lt;<b>overlay-emit</b> with="antx.nightly.builds"&gt;
73  * &lt;emit msgid="BlastOff"/&gt;
74  * &lt;emitlogs&gt;
75  * ...
76  * &lt;/emitlogs&gt;
77  * &lt;/overlay-emit&gt;
78  * </pre>
79  * <b>Implementation Notes:</b><br>
80  * EmitConfigureTasks change the current thread's iteration context. Their effect is
81  * determined by the addivity features of nested emit-aware tasks; for example, the
82  * default EmitTask will use an enclosing configuration to supply default settings
83  * if its own parameters have not be explicitly defined.
84  * <p>
85  * Using the <i>defaultEmitterfactory</i> option effectively re-roots this configuration's
86  * emitter to the root emitter returned by the custom factory. If a custom grouping
87  * is also specified (<i>defaultFrom</i>), then this configuration's emitter is
88  * obtained from the custom factory using the custom grouping. Any inherited emitter
89  * is ignored.
90  * <p>
91  * Currently most of an EmitConfigureTask's attributes are latches-- they can be
92  * modified repeatedly until the task is executed once. After the first execution,
93  * subsequent attribute changes are basically ignored as the first execution creates
94  * and caches several helpers that are never reset.
95  * <p>
96  * EmitConfigureTask is essentially a single-threaded object. Bad things will occur
97  * if a nested task calls back to this task's target from either another thread or
98  * from the same thread. In the case of a second thread, the second thread will be
99  * blocked waiting for the perform-lock to be released from the first thread (which in
100  * turn is waiting for the second thread to finish). In the case of a single thread
101  * an infinite call-back loop would have been created. Both these conditions are captured
102  * when a configure task is verified before execution; a BuildException is thrown iff
103  * duplicate instances of the same configure would end up on the iteration stack.
104  * <b>Note:</b> Nested parallel 'emit' tasks <em>can</em> happen-- accessing the
105  * configuration state concurrently is fine, re-executing the configure task concurrently
106  * is not.
107  *
108  * @since JWare/AntX 0.1
109  * @author ssmc, &copy;2002-2003,2005 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
110  * @version 0.5
111  * @.safety guarded (from EmitConfiguration interface once configured)
112  * @.group api,infra
113  * @see EmitTask
114  * @see DefaultEmitConfiguration
115  **/

116
117 public class EmitConfigureTask extends TaskSet
118     implements FixtureOverlay, EmitConfiguration, EmitConfigurable
119 {
120     /**
121      * Initializes a new EmitConfigureTask instance.
122      **/

123     public EmitConfigureTask()
124     {
125         super(AntX.feedback+"EmitConfigureTask:");
126         m_ecImpl.setController(this);
127     }
128
129
130     /**
131      * Initializes a new EmitConfigureTask subclass instance.
132      **/

133     protected EmitConfigureTask(String JavaDoc iam, boolean delayConfigure)
134     {
135         super(iam,delayConfigure);
136         m_ecImpl.setController(this);
137     }
138
139
140     /**
141      * Initializes the enclosing project of this task. Will
142      * also update the internal project-dependent elements.
143      **/

144     public void setProject(Project P)
145     {
146         super.setProject(P);
147         m_ecImpl.setProject(P);
148     }
149
150
151 //---------------------------------------------------------------------------------------------------------|
152
// Noise-level/Emitted-kruft management:
153
//---------------------------------------------------------------------------------------------------------|
154

155     /**
156      * Sets the list of property names automatically attached
157      * to any emitted messages within this configurations scope.
158      * @param nameList comma-delimited list of property names (non-null)
159      **/

160     public void setProperties(String JavaDoc nameList)
161     {
162         m_ecImpl.setProperties(nameList);
163     }
164
165
166     /**
167      * Returns name list of properties automatically included in any
168      * messages emitted within this configuration's scope. Returns
169      * <i>null</i> (for none) if never set.
170      **/

171     public String JavaDoc getDefaultProperties()
172     {
173         return m_ecImpl.getOwnProperties();
174     }
175
176
177     /**
178      * Adds any custom property names to list automatically included
179      * with messages emitted within this configuration's scope. Returns
180      * <i>false</i> (for none) if never nothing added. Uses comma as
181      * delimiter.
182      * @param list names buffer to update
183      * @return <i>true</i> if list buffer modified
184      **/

185     public boolean getPropertiesNameList(StringBuffer JavaDoc list)
186     {
187         return m_ecImpl.getPropertiesNameList(list);
188     }
189
190
191     /**
192      * Sets the default priority level of messages emitted within
193      * this configuration's scope.
194      * @param nl default message noise level (non-null)
195      **/

196     public void setNoiseLevel(NoiseLevel nl)
197     {
198         m_ecImpl.setNoiseLevel(nl);
199     }
200
201
202     /**
203      * Returns this configuration's default message priority level.
204      * Will return <i>null</i> if never set (this configuration's
205      * emitter can be queried directly).
206      **/

207     public NoiseLevel getDefaultNoiseLevel()
208     {
209         return m_ecImpl.getOwnNoiseLevel();
210     }
211
212
213     /**
214      * Returns this configuration's preferred noise level if one is
215      * defined for it or any of its enclosing configurations.
216      **/

217     public NoiseLevel getNoiseLevel()
218     {
219         NoiseLevel nl= getDefaultNoiseLevel();
220         if (nl==null) {
221             EmitConfiguration defaults= getDefaults();
222             //NB: We want callers to be able to slip project-based prefs between
223
// nothing(us) and the root-defaults for this attribute (ssmc)
224
if (defaults!=DefaultEmitConfiguration.INSTANCE) {
225                 nl= defaults.getNoiseLevel();
226             }
227         }
228         return nl;
229     }
230
231
232     /**
233      * Sets whether any emissions within this configuration's scope should
234      * also echo their messages to the standard Ant logging system.
235      * @param wantIt preference setting (yes,no,inherit) (non-null)
236      **/

237     public void setEcho(String JavaDoc wantIt)
238     {
239         m_ecImpl.setEcho(wantIt);
240     }
241
242
243     /**
244      * Returns the echo-to-Ant-log preference for this configuration.
245      * Will return <i>Setting.INHERITED</i> if never set.
246      **/

247     public Setting getDefaultEcho()
248     {
249         return m_ecImpl.getOwnEcho();
250     }
251
252
253     /**
254      * Returns <i>true</i> if emitted messages should echo their messages
255      * to the standard Ant logging system. Result is based on this
256      * configuration's settings and optionally its own inherited configuration.
257      * @.safety multiple for nested tasks or after configured
258      **/

259     public boolean shouldEcho()
260     {
261         return m_ecImpl.shouldEcho();
262     }
263
264 //---------------------------------------------------------------------------------------------------------|
265
// Grouping/Log4J Category management:
266
//---------------------------------------------------------------------------------------------------------|
267

268     /**
269      * Sets a custom emitter factory's grouping path separator.
270      * Only useful if the emitter factory is also customized.
271      * @since JWare/AntX 0.3
272      **/

273     public void setGroupingSeparator(String JavaDoc separator)
274     {
275         m_ecImpl.setGroupingSeparator(separator);
276     }
277
278
279     /**
280      * Returns the default emitter grouping item separator for this
281      * configuration.
282      * @since JWare/AntX 0.3
283      **/

284     public String JavaDoc getGroupingPathSeparator()
285     {
286         return m_ecImpl.getGroupingPathSeparator();
287     }
288
289
290     /**
291      * Sets the default grouping or log4j category of messages emitted by
292      * tasks nested within this configuration's scope. By default there
293      * is no scope and everything goes to the root emitter; this method
294      * sets this configuration's category explicitly.
295      * @param grpId this configuration's new default category
296      **/

297     public void setFrom(String JavaDoc grpId)
298     {
299         m_ecImpl.setFrom(grpId);
300     }
301
302
303     /**
304      * Returns the grouping or log4j category of this configuration.
305      * Will return <i>null</i> if no explicit scope defined.
306      * @since JWare/AntX 0.3
307      **/

308     public String JavaDoc getDefaultFrom()
309     {
310         return m_ecImpl.getOwnFrom();
311     }
312
313
314     /**
315      * Returns the calculated grouping for messages emitted by tasks
316      * nested within this configuration's scope.
317      **/

318     public String JavaDoc getFrom()
319     {
320         return m_ecImpl.getFrom();
321     }
322
323
324     /**
325      * Instructs this configuration to calculate its grouping relative
326      * to something else.
327      * @param wrt the something else (non-null)
328      * @since JWare/AntX 0.3
329      **/

330     public void setWrt(String JavaDoc wrt)
331     {
332         require_(wrt!=null,"setDfltWrt- nonzro wrt");
333         m_ecImpl.setWrt(wrt);
334     }
335
336
337     /**
338      * Returns what this configuration's grouping is relative to.
339      * Will return <i>null</i> if no explicit instruction defined
340      * @since JWare/AntX 0.3
341      **/

342     public String JavaDoc getDefaultWrt()
343     {
344         return m_ecImpl.getOwnWrt();
345     }
346
347 //---------------------------------------------------------------------------------------------------------|
348
// Emitter(Logger) management:
349
//---------------------------------------------------------------------------------------------------------|
350

351     /**
352      * Sets the custom emitter factory used by this configuration. By default
353      * a log4j-based emitter factory is used.
354      * @param emitterFactoryClass custom emitter factory implementation (non-null)
355      * @throws BuildException if unable to create a DiagnosticsEmitterFactory
356      * instance from given class instance
357      **/

358     public void setEmitterFactory(Class JavaDoc emitterFactoryClass)
359     {
360         m_ecImpl.setEmitterFactory(emitterFactoryClass);
361     }
362
363
364     /**
365      * Returns this configuration's custom emitter factory. Will return
366      * <i>null</i> if a custom emitter factory has not be defined.
367      * @see LJDiagnosticsEmitter#FACTORY
368      **/

369     public DiagnosticsEmitterFactory getDefaultEmitterFactory()
370     {
371         return m_ecImpl.getOwnEmitterFactory();
372     }
373
374
375     /**
376      * Returns this configuration's default emitter. Cached on execution
377      * for this taskset's scope.
378      * @see #setFrom
379      * @.safety multiple for nested tasks or after configured
380      **/

381     public DiagnosticsEmitter getEmitter()
382     {
383         ensure_(m_emitr!=null,"getEmtr- been exec'd at least once");
384         return m_emitr;
385     }
386
387
388     /**
389      * Returns a custom diagnostics emitter for specified grouping. If
390      * this configuration has a custom emitter factory it is used to produce
391      * the new emitter; otherwise, this configuration's inherited emitter
392      * factory is used.
393      * @param grpId category's name (non-null)
394      * @.safety multiple for nested tasks or after configured
395      **/

396     public DiagnosticsEmitter getCustomEmitter(String JavaDoc grpId)
397     {
398         return m_ecImpl.getCustomEmitter(grpId);
399     }
400
401
402     /**
403      * Setup this configuration's default emitter. Depending on whether
404      * a custom emitter factory and a default 'from' have been defined,
405      * this configuration's default emitter is either inherited or a
406      * custom instance.
407      **/

408     private void setupDefaultEmitter()
409     {
410         EmitConfiguration ec = ignoreAllInherited() ? null : m_inheritedInstance;
411         m_ecImpl.setDefaultConfiguration(ec);
412         m_emitr = m_ecImpl.getEmitter();
413     }
414
415
416 //---------------------------------------------------------------------------------------------------------|
417
// Timestamp management:
418
//---------------------------------------------------------------------------------------------------------|
419

420     /**
421      * Sets the default format of timestamps emitted by tasks nested within this
422      * configuration's scope. An {@linkplain EmitTask <i>emit</i>} task can
423      * define its own format as part of its definition to override this setting.
424      * @param format new timestamp format (non-null)
425      **/

426     public void setTimestampFormat(String JavaDoc format)
427     {
428         m_ecImpl.setTimestampFormat(format);
429     }
430
431
432     /**
433      * Returns the default format of timestamps emitted by tasks nested within
434      * this task's scope. Will return <i>null</i> if not set.
435      **/

436     public final String JavaDoc getDefaultTimestampFormat()
437     {
438         return m_ecImpl.getOwnTimestampFormat();
439     }
440
441
442     /**
443      * Creates readable date-time string of given timestamp (milliseconds).
444      * If this configuration's timestamp format has been set, the formatted
445      * string will be in this format; otherwise, a standard MEDIUM date/time
446      * formatted string is returned.
447      * @.safety guarded for nested tasks or after configured
448      **/

449     public String JavaDoc stampify(long ms)
450     {
451         return m_ecImpl.stampify(ms);
452     }
453
454
455     /**
456      * Sets the include-timestamp preference for this configuration.
457      * @param wantIt preference setting (yes,no,inherit) (non-null)
458      **/

459     public void setTimestamp(String JavaDoc wantIt)
460     {
461         m_ecImpl.setTimestamp(wantIt);
462     }
463
464
465     /**
466      * Returns the include-timestamp preference for this configuration.
467      * Returns <i>Setting.INHERITED</i> if never set.
468      **/

469     public final Setting getDefaultIncludeTimestamp()
470     {
471         return m_ecImpl.getOwnTimestamp();
472     }
473
474
475     /**
476      * Returns <i>true</i> if timestamp information should be included in
477      * any emitted messages. Result is based on this configuration's settings
478      * and optionally its own inherited configuration.
479      * @see #getDefaultIncludeTimestamp
480      * @.safety multiple for nested tasks or after configured
481      **/

482     public boolean wantTimestamp()
483     {
484         return m_ecImpl.wantTimestamp();
485     }
486
487
488 //---------------------------------------------------------------------------------------------------------|
489
// Taskset/controller management:
490
//---------------------------------------------------------------------------------------------------------|
491

492     /**
493      * Returns <i>true</i> if this configuration ignores its inherited
494      * configuration and returns its top-level defaults configuration.
495      * Is <i>false</i> by default.
496      * @see DefaultEmitConfiguration
497      **/

498     protected final boolean ignoreAllInherited()
499     {
500         return m_noInherited;
501     }
502
503
504     /**
505      * Set whether this configuration will use the configuration
506      * hierarchy or short-circuit directly to its top-level defaults
507      * configuration.
508      * @param passthru <i>false</i> if this configuration should ignore
509      * the preceding configuration hierarchy.
510      **/

511     public void setInheritance(boolean passthru)
512     {
513         m_noInherited = !passthru;
514     }
515
516
517     /**
518      * Set this configuration task to use a previously defined
519      * EmitConfiguration data object as it <em>full</em> definition.
520      * @param ecImplRef the configuration reference (non-null)
521      * @since JWare/AntX 0.3
522      **/

523     public void setWith(Reference ecImplRef)
524     {
525         require_(ecImplRef!=null,"setRef- nonzro ref");
526         m_ecImpl.setRefid(ecImplRef);
527         m_ecImplReference = ecImplRef;
528     }
529
530
531     /**
532      * Returns this configuration's delegate EmitConfiguration
533      * reference. Returns <i>null</i> if no such reference ever set.
534      * @since JWare/AntX 0.3
535      **/

536     public Reference getWith()
537     {
538         return m_ecImplReference;
539     }
540
541
542     /**
543      * Initializes this configuration's own defaults to an existing
544      * configuration's reference. Iff this configuration finds no
545      * enclosing context configuration, will it use this configuration's
546      * information. The reference id is evaluated at this task's
547      * execution time.
548      * @param dfltRef reference id of an EmitConfiguration (non-null)
549      **/

550     public void setWithDefaults(Reference dfltRef)
551     {
552         m_ecImpl.setDefaults(dfltRef);
553     }
554
555
556     /**
557      * Returns the reference of this configuration's default settings.
558      * Returns <i>null</i> if never set.
559      **/

560     public final Reference getWithDefaults()
561     {
562         return m_ecImpl.getOwnDefaults();
563     }
564
565
566     /**
567      * Verifies this configuration's references (if any defined).
568      * Ensures the refid refer to valid EmitConfiguration implementations.
569      * @since JWare/AntX 0.3
570      **/

571     protected final void verifyReferences()
572     {
573         if (getWith()!=null) {
574             EmitConfiguration definition = (EmitConfiguration)getReferencedObject
575                 (getProject(), getWith().getRefId(), EmitConfiguration.class);
576             if (definition==this) {//Whups!
577
String JavaDoc ermsg = uistrs().get("emit.circular.defaults");
578                 log(ermsg, Project.MSG_ERR);
579                 throw new BuildException(ermsg,getLocation());
580             }
581         }
582         if (getWithDefaults()!=null) {
583             EmitConfiguration defaults = (EmitConfiguration)getReferencedObject
584                 (getProject(), getWithDefaults().getRefId(), EmitConfiguration.class);
585             if (defaults==this) {//Whups!
586
String JavaDoc ermsg = uistrs().get("emit.circular.defaults");
587                 log(ermsg, Project.MSG_ERR);
588                 throw new BuildException(ermsg,getLocation());
589             }
590         }
591     }
592
593
594     /**
595      * Returns this task's closest inherited configuration or, if none,
596      * its default configuration. Can inherit from enclosing &ltemitconfigure&gt;
597      * taskset or the {@linkplain EmitContext#getDefaultConfiguration default
598      * configuration}.
599      * @see #setWithDefaults
600      * @.safety multiple for nested tasks or after configured
601      **/

602     public EmitConfiguration getDefaults()
603     {
604         EmitConfiguration ec = ignoreAllInherited() ? null : m_inheritedInstance;
605         if (ec==null) {
606             ec= m_ecImpl.getDefaults();
607         }
608         return ec;
609     }
610
611
612
613     /**
614      * Installs this configuration as the frontmost configuration within
615      * current thread's iteration environment before running nested tasks.
616      * When tasks have finished (or failed), uninstalls self from
617      * context stack.
618      * @throws BuildError if emit-context stack becomes corrupted
619      * @.safety guarded
620      **/

621     protected void performNestedTasks()
622         throws BuildException
623     {
624         synchronized(m_runlock) {
625             boolean installed=false;
626             try {
627                 //NB: The ordering is critical here-- must setup our emitter
628
// *before* we install ourselves; otherwise an infinite loop
629
// can occur during emitter resolution if 'wrt' is "enclosing" (ssmc)
630
m_inheritedInstance= EmitContext.getConfiguration();
631                 setupDefaultEmitter();
632                 EmitConfiguration cur= EmitContext.installConfiguration(this,m_problemHandler);
633                 installed=true;
634                 verify_(cur==m_inheritedInstance,"perform- same defaults");
635                 super.performNestedTasks();
636
637             } finally {
638                 if (installed) {
639                     m_inheritedInstance = null;
640                     EmitConfiguration ec = EmitContext.getConfiguration();
641                     if (ec!=this) {
642                         String JavaDoc ME= uistrs().dget("task.emit.whoami","EmitConfiguration");
643                         String JavaDoc ermsg = uistrs().get("context.stack.corrupted",ME);
644                         m_problemHandler.problem(ermsg, Project.MSG_ERR);
645                         throw new BuildError(ermsg,getLocation());
646                     }
647                     EmitContext.unwindConfiguration(m_problemHandler);
648                 }//installed
649
}
650         }
651     }
652
653
654     /**
655      * Verifies in valid target/project and pre-loads any defaults
656      * reference objects (latch) to ensure concurrent access by
657      * nested-tasks is OK.
658      **/

659     protected synchronized void verifyCanExecute_(String JavaDoc calr)
660     {
661         super.verifyCanExecute_(calr);
662
663         verifyReferences();
664     }
665
666
667
668     private EmitConfigurationType m_ecImpl= new EmitConfigurationType();
669     private Object JavaDoc m_runlock= new int[0];
670     private boolean m_noInherited;//NB:=>use inheritance hierarchy
671
private EmitConfiguration m_inheritedInstance;//NB:setup by 'perform'
672
private DiagnosticsEmitter m_emitr;//NB:setup by 'perform'
673
private Reference m_ecImplReference;//NB:=>inlined-definition
674

675
676     private ProblemHandler m_problemHandler = new ProblemHandler()
677     {//NB:must be safe w/o context
678
public void problem(Object JavaDoc nugget, int weight)
679         {
680             EmitConfigureTask.this.log(String.valueOf(nugget), weight);
681             Emit.broadcast(EmitConfigureTask.this.getDefaults().getEmitter(),
682                            nugget,null,NoiseLevel.fromNativeIndex(weight));
683         }
684     };
685 }
686
687 /* end-of-EmitConfigureTask.java */
688
Popular Tags