KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > codecoverage > v2 > logger > CoverageLogger


1 /*
2  * @(#)CoverageLogger.java
3  *
4  * Copyright (C) 2002-2004 Matt Albrecht
5  * groboclown@users.sourceforge.net
6  * http://groboutils.sourceforge.net
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */

26
27 package net.sourceforge.groboutils.codecoverage.v2.logger;
28
29 import java.io.InputStream JavaDoc;
30 import java.util.Properties JavaDoc;
31
32 import net.sourceforge.groboutils.codecoverage.v2.IChannelLogger;
33 import net.sourceforge.groboutils.codecoverage.v2.IChannelLoggerFactory;
34
35
36 /**
37  * The singleton invoked at runtime to log each marked bytecode instruction
38  * covered.
39  * <P>
40  * This class needs to be fast, efficient, thread-safe, and classloader-safe.
41  * "Classloader-safe" means that it needs to be resiliant to multiple instances
42  * of this class being loaded, and possibly interfering with each other.
43  * <P>
44  * As of 12-Feb-2003, this class loads up its properties from a property
45  * file, in the same way that Log4J loads its properties. It attempts to
46  * load the property file "/grobocoverage.properties" from the system
47  * resources. If the file cannot be found, then a warning is displayed
48  * to STDERR.
49  *
50  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
51  * @version $Date: 2004/05/14 21:12:11 $
52  * @since December 15, 2002
53  */

54 public final class CoverageLogger implements ICoverageLoggerConst
55 {
56     private static final String JavaDoc PROP_FILE_NAME = "grobocoverage.properties";
57     private static final String JavaDoc PROP_FILE_RES = '/' + PROP_FILE_NAME;
58     
59     private static final boolean DEBUG = false;
60     
61     private static final String JavaDoc FACTORY_PROP = "factory";
62     private static final String JavaDoc CHANNEL_COUNT_PROP = "channel-count";
63     private static final String JavaDoc LOGGER_INIT_BASE_PROP = "logger.";
64     private static final int DEFAULT_CHANNEL_COUNT = 0;
65     private static final Class JavaDoc DEFAULT_CHANNEL_FACTORY =
66             NoOpChannelLoggerFactory.class;
67
68     // this must be defined before initBase(), and shouldn't set the loggers
69
// to anything, due to the static processing order
70
// of Java. We avoid the null pointer checking by using the loggers count
71
// field.
72
private static IChannelLogger LOGGERS[];
73     private static short LOGGERS_COUNT = (short)0;
74
75     /**
76      * Initialize the logger on class loading.
77      */

78     static {
79         initBase();
80     }
81     
82     
83     
84     
85     /**
86      * The primary entry method. This must be lean, mean, thread-safe,
87      * and classloader-safe.
88      */

89     public static final void cover( String JavaDoc classSig, short methodIndex,
90             short channel, short markIndex )
91     {
92         if (channel >= 0 && channel < LOGGERS_COUNT)
93         {
94             //debug( "Logging ["+classSig+";"+methodIndex+":"+channel+
95
// "-"+markIndex+"]" );
96
//error( "Logging ["+classSig+";"+methodIndex+":"+channel+
97
// "-"+markIndex+"]" );
98
LOGGERS[ (int)channel ].cover( classSig, methodIndex, markIndex );
99         }
100         /*
101         else
102         {
103             if (LOGGERS == null)
104             {
105                 debug( "Couldn't log ["+classSig+";"+channel+":"+methodIndex+"."+
106                     "-"+markIndex+"]: LOGGERS=null" );
107             }
108             else
109             {
110                 debug( "Couldn't log ["+classSig+";"+channel+":"+methodIndex+"."+
111                     "-"+markIndex+"]: LOGGERS length="+LOGGERS.length );
112             }
113         }
114         */

115     }
116     
117     
118     /**
119      * Initializes or reinitializes the static logger object based on the
120      * logger property file, which will be used as the argument to
121      * <tt>init( Properties )</tt>. If no such file is found, then a
122      * warning is reported to STDERR, and the System properties are passed
123      * into the <tt>init</tt> method.
124      */

125     public static final void initBase()
126     {
127         // make sure we set the loggers count to 0 before we get started.
128
// this way, we don't have to deal with LOGGERS null checking.
129
LOGGERS_COUNT = (short)0;
130         
131         Properties JavaDoc props = null;
132         try
133         {
134             InputStream JavaDoc is = CoverageLogger.class.getResourceAsStream(
135                 PROP_FILE_RES );
136             if (is == null)
137             {
138                 is = ClassLoader.getSystemResourceAsStream( PROP_FILE_NAME );
139             }
140             if (is != null)
141             {
142                 debug( "Loading "+PROP_FILE_NAME );
143                 props = new Properties JavaDoc();
144                 props.load( is );
145             }
146             else
147             {
148                 error( "No resource named "+PROP_FILE_NAME+"." );
149             }
150         }
151         catch (ThreadDeath JavaDoc td)
152         {
153             // never catch these
154
throw td;
155         }
156         catch (Throwable JavaDoc t)
157         {
158             error( t.toString() );
159             // ignore
160
}
161         
162         if (props == null)
163         {
164             props = System.getProperties();
165             error( "Please create and/or add the file "+PROP_FILE_NAME+
166                 " to the classpath." );
167             if (DEBUG)
168             {
169                 System.exit(1);
170             }
171         }
172         init( props );
173     }
174     
175     
176     /**
177      * Initializes or reinitializes the static logger object with a specific
178      * set of properties.
179      *
180      * @param props collection of properties used to discover the channel
181      * logger factory, and to initialize the new channel logger.
182      */

183     public static final void init( Properties JavaDoc props )
184     {
185         // start out by saying that there are no loggers. This will only
186
// change if we get to the end without errors.
187
LOGGERS_COUNT = (short)0;
188         
189         if (props == null)
190         {
191             error( "Encountered null properties instance." );
192             return;
193         }
194         
195         short channelCount = getChannelCount( props );
196         IChannelLoggerFactory factory = getChannelLoggerFactory( props );
197         if (factory != null)
198         {
199             // only assign the loggers at the end, after we've created
200
// everything
201

202             IChannelLogger ls[] = new IChannelLogger[ channelCount ];
203             for (short i = 0; i < channelCount; ++i)
204             {
205                 ls[ (int)i ] = factory.
206                     createChannelLogger( LOGGER_INIT_BASE_PROP, props, i );
207                 debug( "Logger "+i+" = "+ls[(int)i] );
208             }
209             
210             LOGGERS = ls;
211             
212         }
213         // else keep the loggers list as it was.
214

215         if (LOGGERS == null)
216         {
217             debug( "Logger list is null." );
218             LOGGERS = new IChannelLogger[ 0 ];
219         }
220         
221         LOGGERS_COUNT = (short)LOGGERS.length;
222     }
223     
224     
225     private static final short getChannelCount( Properties JavaDoc props )
226     {
227         short channelCount = DEFAULT_CHANNEL_COUNT;
228         String JavaDoc countStr = props.getProperty( CHANNEL_COUNT_PROP );
229         if (countStr != null && countStr.length() > 0)
230         {
231             try
232             {
233                 // if this line throws an exception, it will not
234
// disturb the default count.
235
int i = Integer.parseInt( countStr );
236
237                 if (i < 0 || i > Short.MAX_VALUE)
238                 {
239                     error( "Channel count is outside range [0.."+
240                         Short.MAX_VALUE+"]. Using default." );
241                 }
242                 else
243                 {
244                     // no exception was thrown, so assign the new count.
245
channelCount = (short)i;
246                 }
247             }
248             catch (NumberFormatException JavaDoc ex)
249             {
250                 error( "Trouble translating channel count ('"+countStr+
251                     "') to a number. Using default." );
252             }
253         }
254         debug( "Channel Count = "+channelCount );
255         return channelCount;
256     }
257     
258     
259     private static final IChannelLoggerFactory getChannelLoggerFactory(
260             Properties JavaDoc props )
261     {
262         String JavaDoc factoryClassName = props.getProperty( FACTORY_PROP );
263         Class JavaDoc factoryClass = DEFAULT_CHANNEL_FACTORY;
264         IChannelLoggerFactory factory = null;
265         
266         if (factoryClassName != null)
267         {
268             try
269             {
270                 // if this line throws an exception, it will not
271
// disturb the factoryClass object.
272
Class JavaDoc c = Class.forName( factoryClassName );
273                 
274                 // no exception was thrown, so assign the new class.
275
factoryClass = c;
276             }
277             catch (ThreadDeath JavaDoc td)
278             {
279                 // never catch these
280
throw td;
281             }
282             catch (Throwable JavaDoc t)
283             {
284                 error( "Could not load factory class '"+factoryClassName+
285                     "'. Using default." );
286             }
287         }
288         
289         try
290         {
291             factory = (IChannelLoggerFactory)factoryClass.newInstance();
292         }
293         catch (ThreadDeath JavaDoc td)
294         {
295             // never catch these
296
throw td;
297         }
298         catch (Throwable JavaDoc t)
299         {
300             error( "Couldn't create a new factory or cast it to a "+
301                 (IChannelLoggerFactory.class.getName())+
302                 ". Not using a logger." );
303         }
304         
305         debug( "Factory = "+factory );
306         return factory;
307     }
308
309     
310     
311     private static final void error( String JavaDoc message )
312     {
313         System.err.println( CoverageLogger.class.getName()+": "+message );
314     }
315     
316     
317     private static final void debug( String JavaDoc message )
318     {
319         if (DEBUG)
320         {
321             System.out.println( "DEBUG ["+
322                 CoverageLogger.class.getName()+"]: "+message );
323         }
324     }
325 }
326
327
Popular Tags