• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id$
20  */
21 
22 /*
23  *
24  * LoggingErrorListener.java
25  *
26  */
27 package org.apache.qetest.trax;
28 
29 import javax.xml.transform.ErrorListener;
30 import javax.xml.transform.TransformerException;
31 
32 import org.apache.qetest.Logger;
33 import org.apache.qetest.LoggingHandler;
34 
35 /**
36  * Cheap-o ErrorListener for use by API tests.
37  * <p>Implements javax.xml.transform.ErrorListener and dumps
38  * everything to a Logger; is separately settable as
39  * to when it will throw an exception; also separately settable
40  * as to when we should validate specific events that we handle.</p>
41  * //@todo try calling getLocator() and asking it for info directly
42  * @author shane_curcuru@lotus.com
43  * @version $Id$
44  */
45 public class LoggingErrorListener extends LoggingHandler implements ErrorListener
46 {
47 
48     /** No-op ctor seems useful. */
LoggingErrorListener()49     public LoggingErrorListener()
50     {
51         setLogger(getDefaultLogger());
52     }
53 
54     /**
55      * Ctor that calls setLogger automatically.
56      *
57      * @param l Logger we should log to
58      */
LoggingErrorListener(Logger l)59     public LoggingErrorListener(Logger l)
60     {
61         setLogger(l);
62     }
63 
64 
65     /**
66      * Constants determining when we should throw exceptions.
67      * <ul>Flags are combineable like a bitfield.
68      * <li>THROW_NEVER - never ever (always continue - note this
69      * may have unexpected effects when fatalErrors happen, see
70      * {@link javax.xml.transform.ErrorListener#fatalError(javax.xml.transform.TransformerException)}</li>
71      * <li>THROW_ON_WARNING - throw only on warnings</li>
72      * <li>THROW_ON_ERROR - throw only on errors</li>
73      * <li>THROW_ON_FATAL - throw only on fatalErrors - default</li>
74      * <li>THROW_ALWAYS - always throw exceptions</li>
75      * </ul>
76      */
77     public static final int THROW_NEVER = 0;
78 
79     /** THROW_ON_WARNING - throw only on warnings.  */
80     public static final int THROW_ON_WARNING = 1;
81 
82     /** THROW_ON_ERROR - throw only on errors.  */
83     public static final int THROW_ON_ERROR = 2;
84 
85     /** THROW_ON_FATAL - throw only on fatalErrors - default.  */
86     public static final int THROW_ON_FATAL = 4;
87 
88     /** THROW_ALWAYS - always throw exceptions.   */
89     public static final int THROW_ALWAYS = THROW_ON_WARNING & THROW_ON_ERROR
90                                            & THROW_ON_FATAL;
91 
92     /** If we should throw an exception for each message type. */
93     protected int throwWhen = THROW_ON_FATAL;
94 
95     /**
96      * Tells us when we should re-throw exceptions.
97      *
98      * @param t THROW_WHEN_* constant as to when we should re-throw
99      * an exception when we are called
100      */
setThrowWhen(int t)101     public void setThrowWhen(int t)
102     {
103         throwWhen = t;
104     }
105 
106     /**
107      * Tells us when we should re-throw exceptions.
108      *
109      * @return THROW_WHEN_* constant as to when we should re-throw
110      * an exception when we are called
111      */
getThrowWhen()112     public int getThrowWhen()
113     {
114         return throwWhen;
115     }
116 
117     /** Constant for items returned in getCounters: messages.  */
118     public static final int TYPE_WARNING = 0;
119 
120     /** Constant for items returned in getCounters: errors.  */
121     public static final int TYPE_ERROR = 1;
122 
123     /** Constant for items returned in getCounters: fatalErrors.  */
124     public static final int TYPE_FATALERROR = 2;
125 
126     /**
127      * Counters for how many events we've handled.
128      * Index into array are the TYPE_* constants.
129      */
130     protected int[] counters =
131     {
132         0, /* warning */
133         0, /* error */
134         0  /* fatalError */
135     };
136 
137 
138     /**
139      * Get a list of counters of all items we've logged.
140      * Returned as warnings, errors, fatalErrors
141      * Index into array are the TYPE_* constants.
142      *
143      * @return array of int counters for each item we log
144      */
getCounters()145     public int[] getCounters()
146     {
147         return counters;
148     }
149 
150     /** Prefixed to all logger msg output. */
151     public static final String prefix = "LEL:";
152 
153 
154     /**
155      * Really Cheap-o string representation of our state.
156      *
157      * @return String of getCounters() rolled up in minimal space
158      */
getQuickCounters()159     public String getQuickCounters()
160     {
161         return (prefix + "(" + counters[TYPE_WARNING] + ", "
162                 + counters[TYPE_ERROR] + ", " + counters[TYPE_FATALERROR] + ")");
163     }
164 
165 
166     /** Cheap-o string representation of last warn/error/fatal we got. */
167     protected String lastItem = NOTHING_HANDLED;
168 
169     /**
170      * Sets a String representation of last item we handled.
171      *
172      * @param s set into lastItem for retrieval with getLast()
173      */
setLastItem(String s)174     protected void setLastItem(String s)
175     {
176         lastItem = s;
177     }
178 
179     /**
180      * Get a string representation of last item we logged.
181      *
182      * @return String of the last item handled
183      */
getLast()184     public String getLast()
185     {
186         return lastItem;
187     }
188 
189 
190     /** Expected values for events we may handle, default=ITEM_DONT_CARE. */
191     protected String[] expected =
192     {
193         ITEM_DONT_CARE, /* warning */
194         ITEM_DONT_CARE, /* error */
195         ITEM_DONT_CARE  /* fatalError */
196     };
197 
198 
199     /**
200      * Ask us to report checkPass/Fail for certain events we handle.
201      * Since we may have to handle many events between when a test
202      * will be able to call us, testers can set this to have us
203      * automatically call checkPass when we see an item that matches,
204      * or to call checkFail when we get an unexpected item.
205      * Generally, we only call check* methods when:
206      * <ul>
207      * <li>containsString is not set, reset, or is ITEM_DONT_CARE,
208      * we do nothing (i.e. never call check* for this item)</li>
209      * <li>containsString is ITEM_CHECKFAIL, we will always call
210      * checkFail with the contents of any item if it occours</li>
211      * <li>containsString is anything else, we will grab a String
212      * representation of every item of that type that comes along,
213      * and if the containsString is found, case-sensitive, within
214      * the handled item's string, call checkPass, otherwise
215      * call checkFail</li>
216      * <ul>
217      * Note that any time we handle a particular event that was
218      * expected, we un-set the expected value for that item.  This
219      * means that you can only ask us to validate one occourence
220      * of any particular event; all events after that one will
221      * be treated as ITEM_DONT_CARE.  Callers can of course call
222      * setExpected again, of course, but this covers the case where
223      * we handle multiple events in a single block, perhaps out of
224      * the caller's direct control.
225      * Note that we first store the event via setLast(), then we
226      * validate the event as above, and then we potentially
227      * re-throw the exception as by setThrowWhen().
228      *
229      * @param itemType which of the various types of items we might
230      * handle; should be defined as a constant by subclasses
231      * @param containsString a string to look for within whatever
232      * item we handle - usually checked for by seeing if the actual
233      * item we handle contains the containsString
234      */
setExpected(int itemType, String containsString)235     public void setExpected(int itemType, String containsString)
236     {
237         // Default to don't care on null
238         if (null == containsString)
239             containsString = ITEM_DONT_CARE;
240 
241         try
242         {
243             expected[itemType] = containsString;
244         }
245         catch (ArrayIndexOutOfBoundsException aioobe)
246         {
247             // Just log it for callers reference and continue anyway
248             logger.logMsg(level, prefix + " setExpected called with illegal type:" + itemType);
249         }
250     }
251 
252 
253     /**
254      * Reset all items or counters we've handled.
255      */
reset()256     public void reset()
257     {
258         setLastItem(NOTHING_HANDLED);
259         for (int i = 0; i < counters.length; i++)
260         {
261             counters[i] = 0;
262         }
263         for (int j = 0; j < expected.length; j++)
264         {
265             expected[j] = ITEM_DONT_CARE;
266         }
267     }
268 
269 
270     /**
271      * Grab basic info out of a TransformerException.
272      * Worker method to hide implementation; currently just calls
273      * exception.getMessageAndLocation().
274      *
275      * @param exception to get information from
276      * @return simple string describing the exception (getMessageAndLocation())
277      */
getTransformerExceptionInfo(TransformerException exception)278     public String getTransformerExceptionInfo(TransformerException exception)
279     {
280 
281         if (exception == null)
282             return "";  // Don't return null, just to make other code here simpler
283 
284         return exception.getMessageAndLocation();
285     }
286 
287 
288     /**
289      * Implementation of warning; calls logMsg with info contained in exception.
290      *
291      * @param exception provided by Transformer
292      * @exception TransformerException thrown only if asked to or if loggers are bad
293      */
warning(TransformerException exception)294     public void warning(TransformerException exception) throws TransformerException
295     {
296 
297         // Increment counter and save the exception
298         counters[TYPE_WARNING]++;
299 
300         String exInfo = getTransformerExceptionInfo(exception);
301 
302         setLastItem(exInfo);
303 
304         // Log or validate the exception
305         logOrCheck(TYPE_WARNING, "warning", exInfo);
306 
307         // Also re-throw the exception if asked to
308         if ((throwWhen & THROW_ON_WARNING) == THROW_ON_WARNING)
309         {
310             // Note: re-throw the SAME exception, not a new one!
311             throw exception;
312         }
313     }
314 
315     /**
316      * Implementation of error; calls logMsg with info contained in exception.
317      * Only ever throws an exception itself if asked to or if loggers are bad.
318      *
319      * @param exception provided by Transformer
320      * @exception TransformerException thrown only if asked to or if loggers are bad
321      */
error(TransformerException exception)322     public void error(TransformerException exception) throws TransformerException
323     {
324 
325         // Increment counter, save the exception, and log what we got
326         counters[TYPE_ERROR]++;
327 
328         String exInfo = getTransformerExceptionInfo(exception);
329 
330         setLastItem(exInfo);
331 
332         // Log or validate the exception
333         logOrCheck(TYPE_ERROR, "error", exInfo);
334 
335         // Also re-throw the exception if asked to
336         if ((throwWhen & THROW_ON_ERROR) == THROW_ON_ERROR)
337         {
338             // Note: re-throw the SAME exception, not a new one!
339             throw exception;
340         }
341     }
342 
343     /**
344      * Implementation of error; calls logMsg with info contained in exception.
345      * Only ever throws an exception itself if asked to or if loggers are bad.
346      * Note that this may cause unusual behavior since we may not actually
347      * re-throw the exception, even though it was 'fatal'.
348      *
349      * @param exception provided by Transformer
350      * @exception TransformerException thrown only if asked to or if loggers are bad
351      */
fatalError(TransformerException exception)352     public void fatalError(TransformerException exception) throws TransformerException
353     {
354 
355         // Increment counter, save the exception, and log what we got
356         counters[TYPE_FATALERROR]++;
357 
358         String exInfo = getTransformerExceptionInfo(exception);
359 
360         setLastItem(exInfo);
361 
362         // Log or validate the exception
363         logOrCheck(TYPE_FATALERROR, "fatalError", exInfo);
364 
365         // Also re-throw the exception if asked to
366         if ((throwWhen & THROW_ON_FATAL) == THROW_ON_FATAL)
367         {
368             // Note: re-throw the SAME exception, not a new one!
369             throw exception;
370         }
371     }
372 
373 
374     /**
375      * Worker method to either log or call check* for this event.
376      * A simple way to validate for any kind of event.
377      *
378      * @param type of message (warning/error/fatalerror)
379      * @param desc description of this kind of message
380      * @param exInfo String representation of current exception
381      */
logOrCheck(int type, String desc, String exInfo)382     protected void logOrCheck(int type, String desc, String exInfo)
383     {
384         String tmp = getQuickCounters() + " " + desc;
385         // Either log the exception or call checkPass/checkFail
386         //  as requested by setExpected for this type
387         if (ITEM_DONT_CARE == expected[type])
388         {
389             // We don't care about this, just log it
390             logger.logMsg(level, desc + " threw: " + exInfo);
391         }
392         else if (ITEM_CHECKFAIL == expected[type])
393         {
394             // We shouldn't have been called here, so fail
395             logger.checkFail(desc + " threw-unexpected: " + exInfo);
396         }
397         else if (exInfo.indexOf(expected[type]) > -1)
398         {
399             // We got a warning the user expected, so pass
400             logger.checkPass(desc + " threw-matching: " + exInfo);
401             // Also reset this counter
402             //@todo needswork: this is very state-dependent, and
403             //  might not be what the user expects, but at least it
404             //  won't give lots of extra false fails or passes
405             expected[type] = ITEM_DONT_CARE;
406         }
407         else
408         {
409             // We got a warning the user didn't expect, so fail
410             logger.checkFail(desc + " threw-notmatching: " + exInfo);
411             // Also reset this counter
412             expected[type] = ITEM_DONT_CARE;
413         }
414     }
415 }
416