KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * $Id: EventEmitConduit.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.feedback;
30
31 import java.util.StringTokenizer JavaDoc;
32
33 import org.apache.tools.ant.BuildEvent;
34 import org.apache.tools.ant.Project;
35
36 import com.idaremedia.antx.AntX;
37 import com.idaremedia.antx.Iteration;
38 import com.idaremedia.antx.NoiseLevel;
39 import com.idaremedia.antx.apis.ProblemHandler;
40 import com.idaremedia.antx.helpers.Strings;
41 import com.idaremedia.antx.helpers.Tk;
42 import com.idaremedia.antx.ownhelpers.io.ErrOutHandle;
43 import com.idaremedia.antx.starters.BuildListenerSkeleton;
44 import com.idaremedia.apis.DiagnosticsEmitter;
45
46 /**
47  * Captures logged Ant messages and redirects them to any listening Log4J-based
48  * monitors.
49  * <p>
50  * Currently this class does some some work-arounds to cope with the situation
51  * where a single conduit is installed across multiple calls to independent child
52  * projects. This might occur, for example, if an &lt;emitlogs&gt; encloses one
53  * or more calls to &lt;antcall&gt; or a similar task.
54  * <p>
55  * This class tries to organize Ant logged messages into a minimal hierarchy for
56  * sanity's sake. More complex message-format based filtering can be done using
57  * standard Log4J facilities or AntX grouping mappings. While a conduit can be
58  * attached "as-is" to any Ant build-iteration using the standard Ant customization
59  * build-listener facilities, it is most effective when associated with an AntX
60  * build-iteration Iam task or a scoped taskset like {@linkplain EmitLogsTask}.
61  * Note that this listener <em>cannot</em> be used as a command-line based Ant
62  * listener (it requires project-based information that may not exist at Ant early
63  * startup time).
64  *
65  * @since JWare/AntX 0.3
66  * @author ssmc, &copy;2002-2005 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
67  * @version 0.5
68  * @.safety multiple
69  * @.group impl,helper
70  * @see EmitLogsTask
71  **/

72
73 public class EventEmitConduit extends BuildListenerSkeleton
74 {
75     /**
76      * Initializes a new EventEmitConduit instance.
77      **/

78     public EventEmitConduit()
79     {
80     }
81
82
83     /**
84      * Sets the callback problem handler for this conduit.
85      * This handler is used for errors this conduit isn't
86      * designed to handle itself.
87      * @param errH the problemm handler (use <i>null</i> to clear)
88      **/

89     public void setProblemHandler(ProblemHandler errH)
90     {
91         m_errHandler = errH;
92     }
93
94
95     /**
96      * Returns this conduit's callback problem handler. If
97      * an explicit handler has not been set for this conduit
98      * this method returns the current thread context default
99      * handler. Never returns <i>null</i>.
100      **/

101     public ProblemHandler getProblemHandler()
102     {
103         if (m_errHandler!=null) {
104             return m_errHandler;
105         }
106         return Iteration.problemsHandler();
107     }
108
109
110     /**
111      * Sets the default emit configuration for this conduit.
112      * This configuration is used to obtain information like
113      * grouping path separators, diagnostics emitters, etc.
114      * @param ec the configuration (use <i>null</i> to clear)
115      **/

116     public void setConfiguration(EmitConfiguration ec)
117     {
118         m_emitConfiguration = ec;
119     }
120
121
122     /**
123      * Returns this conduit's default emit configuration. If
124      * never set explicitly this method will return the current
125      * thread's default emit configuration. Never returns
126      * <i>null</i>.
127      **/

128     public EmitConfiguration getConfiguration()
129     {
130         if (m_emitConfiguration!=null) {
131             return m_emitConfiguration;
132         }
133         return EmitContext.getConfigurationNoNull();
134     }
135
136
137     /**
138      * Sets the default grouping mapper for this conduit.
139      * This mapper is used to transform each event into a
140      * diagnostics grouping (which is then used to determine
141      * the diagnostics emitter over which the Ant log message
142      * is broadcast).
143      * @param mapper the mapper (use <i>null</i> to clear)
144      **/

145     public void setGroupingMapper(GroupingMapper mapper)
146     {
147         if (mapper==null) {
148             m_mapper = getDefaultGroupingMapper();
149         } else {
150             m_mapper = mapper;
151         }
152     }
153
154
155     /**
156      * Returns this conduit's grouping mapper. If never set
157      * explicitly (or reset), this method will return a default
158      * mapper (zone/project/target/task). Never returns
159      * <i>null</i>.
160      **/

161     public final GroupingMapper getGroupingMapper()
162     {
163         return m_mapper;
164     }
165
166
167     /**
168      * Transforms a symbolic field name to its matching filter
169      * mask bit.
170      **/

171     private int includeFrom(String JavaDoc is)
172     {
173         if (is.startsWith("task")) {
174             return MainField.INCLUDE_TASK;
175         }
176         if (is.startsWith("target")) {
177             return MainField.INCLUDE_TARGET;
178         }
179         if (is.startsWith("nested")) {
180             return MainField.INCLUDE_NESTED;
181         }
182         if (is.startsWith("project")){
183             return MainField.INCLUDE_PROJECT;
184         }
185         return 0;
186     }
187
188
189     /**
190      * Sets a filter on the default groupings created by this conduit.
191      * Without any filters, this conduit will organize messages like:
192      * zone-name/project-name/target-name/task-name[/message]. Filters
193      * can be used to change this default path organization by eliminating
194      * one or more elements; for example: zone-name/project-name/target-name
195      * (no task-name grouping will be included). This method is usually
196      * called by the conduit's owning task's script-facing method.
197      * @param filterstring symbolic filter string for MainField.INCLUDE_*
198      **/

199     public void setIncludes(String JavaDoc filterstring)
200     {
201         if (filterstring==null) {
202             m_includesFilter = MainField.DEFAULT_FILTER;
203             m_filtersByName = Strings.DEFAULT;
204         }
205         else {
206             filterstring = Tk.lowercaseFrom(filterstring);
207             int i;
208             if (Strings.ALL.equals(filterstring)) {
209                 i= MainField.INCLUDE_ALL;
210             } else if (Strings.DEFAULT.equals(filterstring)) {
211                 i= MainField.DEFAULT_FILTER;
212             } else if (Strings.NONE.equals(filterstring)) {
213                 i= 0;
214             } else {
215                 if (filterstring.startsWith(Strings.ALL)) {
216                     i= MainField.INCLUDE_ALL;
217                     String JavaDoc minuslist = filterstring.substring(Strings.ALL.length());
218                     StringTokenizer JavaDoc st= new StringTokenizer JavaDoc(minuslist,"-");
219                     while (st.hasMoreTokens()) {
220                         i &= ~includeFrom(st.nextToken());
221                     }
222                 } else {
223                     i= 0;
224                     StringTokenizer JavaDoc st= new StringTokenizer JavaDoc(filterstring,",");
225                     while (st.hasMoreTokens()) {
226                         i |= includeFrom(st.nextToken());
227                     }
228                 }
229             }
230             m_includesFilter = i;
231             m_filtersByName = filterstring;
232         }
233     }
234
235
236     /**
237      * Returns this conduit's groupings filter string. Never returns
238      * <i>null</i>; returns "default" if never set.
239      **/

240     public final String JavaDoc getIncludes()
241     {
242         return m_filtersByName;
243     }
244
245
246     /**
247      * Like {@linkplain #setIncludes setIncludes(String)} but
248      * with direct filter and name information.
249      * @param mask filter mask (combination of MainField.INCLUDE_*)
250      * @param byName the string-version of mask (non-null)
251      * @see #setIncludes
252      **/

253     public final void setIncludesFilter(int mask, String JavaDoc byName)
254     {
255         if (byName==null) {
256             throw new IllegalArgumentException JavaDoc();
257         }
258         m_includesFilter = mask;
259         m_filtersByName = byName;
260     }
261
262
263     /**
264      * Returns this conduit's grouping filter as a mask.
265      **/

266     public final int getIncludesFilter()
267     {
268         return m_includesFilter;
269     }
270
271
272
273     /**
274      * The default mapper implements the fallback (builtin)
275      * grouping hierarchy (no user customization).
276      **/

277     private static final GroupingMapper sm_DefaultMapper =
278         new GroupingMapper();
279
280
281     /**
282      * Returns the default conduit mapper. Never returns
283      * <i>null</i>.
284      **/

285     public static final GroupingMapper getDefaultGroupingMapper()
286     {
287         return sm_DefaultMapper;
288     }
289
290
291 // ---------------------------------------------------------------------------------------
292
// Build Listener Impl:
293
// ---------------------------------------------------------------------------------------
294

295     /**
296      * Converts the message as logged to the Ant log infrastructure
297      * to a log4j event broadcast. Message emitted to any listening
298      * log4j monitors.
299      * @param e Ant log message event (non-null)
300      * @.impl This method must ensure nested log-calls don't trigger an
301      * infinite loopback condition
302      **/

303     public void messageLogged(BuildEvent e)
304     {
305         NoiseLevel nl = NoiseLevel.from(e);
306         if (m_suspendedLevel==0) {//NB:don't loop back onto self!
307
m_suspendedLevel++;
308
309             ErrOutHandle devnull= new ErrOutHandle();
310             devnull.install();
311
312             try {
313                 if (nl!=null) {
314                     IndicatorZone iz = IndicatorZone.from(nl);
315                     GroupingMapper mapper = getGroupingMapper();
316                     EmitConfiguration ini = getConfiguration();
317
318                     String JavaDoc evtpath = mapper.pathFrom
319                         (e, iz, getIncludesFilter(), ini.getGroupingPathSeparator());
320
321                     String JavaDoc msgpath = mapper.getLabel(MainField.MESSAGE,e,iz);
322                     if (msgpath!=null) {
323                         if (msgpath.startsWith(ini.getGroupingPathSeparator())) {
324                             evtpath += msgpath;
325                         } else {
326                             evtpath += ini.getGroupingPathSeparator() + msgpath;
327                         }
328                     }
329                     DiagnosticsEmitter route = ini.getCustomEmitter(evtpath);
330                     Emit.broadcast(route, e.getMessage(), e.getException(), nl);
331
332                 } else {
333                     handleUnknownNoiseLevel(e);
334                 }
335             } finally {
336                 devnull.uninstall(false,true);
337                 m_suspendedLevel--;
338             }
339         }
340     }
341
342
343     /**
344      * Called if this conduit cannot match the event's priority
345      * to noise level.
346      * @param e listener event (non-null)
347      **/

348     protected void handleUnknownNoiseLevel(BuildEvent e)
349     {
350         getProblemHandler().problem
351             (AntX.uistrs().get("emit.unknown.noiselevel",String.valueOf(e.getPriority())),
352              Project.MSG_WARN);//NB:careful of loopback here (ssmc)
353
}
354
355
356     private volatile int m_suspendedLevel;
357     private ProblemHandler m_errHandler;
358     private EmitConfiguration m_emitConfiguration;
359     private int m_includesFilter= MainField.DEFAULT_FILTER;
360     private String JavaDoc m_filtersByName= Strings.DEFAULT;
361     private GroupingMapper m_mapper = getDefaultGroupingMapper();
362 }
363
364 /* end-of-EventEmitConduit.java */
365
Popular Tags