KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > logging > StandardLogger


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: StandardLogger.java,v 1.2 2005/03/24 10:51:25 slobodan Exp $
22  */

23 package com.lutris.logging;
24
25 import java.io.File JavaDoc;
26 import java.io.FileInputStream JavaDoc;
27 import java.io.FileOutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.PrintWriter JavaDoc;
30 import java.util.Hashtable JavaDoc;
31
32 import com.lutris.util.Config;
33 import com.lutris.util.ConfigException;
34 import com.lutris.util.ConfigFile;
35 import com.lutris.util.KeywordValueException;
36
37 /**
38  * Standard implementation of the <CODE>Logger</CODE>. This is
39  * general-purpose logging facility. A client that needs additional
40  * functionality can either extend this class or provide there own
41  * implementationm of <CODE>Logger</CODE>. <P>
42  *
43  * Currently this is a bare-bones class that writes INFO and above
44  * levels to stderr and all others to a log file.
45  *
46  * @author Mark Diekhans
47  * @see com.lutris.logging.Logger
48  * @see com.lutris.logging.LogChannel
49  * @see com.lutris.logging.StandardLogChannel
50  */

51 public class StandardLogger extends Logger {
52     
53     private static final String JavaDoc LOG_SECTION = "Server";
54     private static final String JavaDoc LOG_FILE = "LogFile";
55     private static final String JavaDoc LOG_TO_FILE = "LogToFile";
56     private static final String JavaDoc LOG_TO_STDERR = "LogToStderr";
57     
58     /**
59      * Table of level names to level numbers. While level configuration
60      * is local to a facility, a global table is kept assigning numbers
61      * to each level name.
62      */

63     private Hashtable JavaDoc levelNumbers = new Hashtable JavaDoc();
64
65     /**
66      * Table translating level number to name and the largest entry in the
67      * array that is valid. Will be expanded if needed.
68      */

69     protected String JavaDoc[] levelNames = new String JavaDoc[MAX_STD_LEVEL * 2];
70     protected int numLevels = 0;
71
72     /**
73      * Table of levels that are to be enabled.
74      * Accessed directly by the channel. If null, ignored.
75      */

76     protected boolean[] enabledLevelFlags = null;
77
78     /**
79      * Table of levels that are to be written to the log file.
80      * Accessed directly by the channel. If null, ignored.
81      */

82     protected boolean[] logFileLevelFlags = null;
83
84     /**
85      * Table of levels that are to be written to stderr
86      * Accessed directly by the channel. If null, then
87      * the default behavior of writing serious standard
88      * levels to stderr is in affect.
89      */

90     protected boolean[] stderrLevelFlags = null;
91
92     /**
93      * Log file name.
94      */

95     File JavaDoc activeLogFile;
96
97     /**
98      * Log file writter. Use directly by channels.
99      */

100     PrintWriter JavaDoc logFileStream;
101
102     /**
103      * Stderr writter. Use directly by channels.
104      */

105     PrintWriter JavaDoc stderrStream;
106
107     /**
108      * Table of <CODE>StandardLogChannel<CODE> objects, indexed by facility
109      * name.
110      */

111     private Hashtable JavaDoc logChannels = new Hashtable JavaDoc();
112
113     /**
114      * Construct a new logger. Configuration is not done now, to allow
115      * the logger to be created very early.
116      *
117      * @param makeCentral Make this object the central logging object.
118      */

119     public StandardLogger(boolean makeCentral) {
120         int level;
121
122         for (level = 0; level <= MAX_STD_LEVEL; level++) {
123             String JavaDoc name = standardLevelNames[level];
124
125             levelNumbers.put(name, new Integer JavaDoc(level));
126             levelNames[level] = name;
127         }
128         numLevels = level;
129         if (makeCentral) {
130             centralLogger = this;
131         }
132     }
133
134     /**
135      * Get maximum level number in a set of level names.
136      *
137      * @param levels String names of levels.
138      * @return The maximum level number
139      */

140     private int getMaxLevel(String JavaDoc[] levels) {
141         int levelNum;
142         int maxLevelNum = 0;
143
144         for (int idx = 0; idx < levels.length; idx++) {
145             levelNum = getLevel(levels[idx]);
146             if (levelNum > maxLevelNum) {
147                 maxLevelNum = levelNum;
148             }
149         }
150         return maxLevelNum;
151     }
152
153     /**
154      * Generate a boolean array for all of the listed levels, indicating
155      * if they are enabled.
156      *
157      * @param levels String names of levels.
158      * @param maxLevelNum Size to make the array.
159      */

160     private boolean[] getLevelStateArray(String JavaDoc[] levels, int maxLevelNum) {
161         int levelNum;
162         // Initialize the stated.
163
boolean[] levelNums = new boolean[maxLevelNum + 1];
164
165         for (int idx = 0; idx < levels.length; idx++) {
166             levelNums[getLevel(levels[idx])] = true;
167         }
168         return levelNums;
169     }
170
171     /**
172      * Switch a log file; replacing the old one with a new one.
173      *
174      *
175      * @param logFile The new log file.
176      * @return The File object for the previous log file, or null if there
177      * wasn't one.
178      * @exception java.io.IOException If an error occurs opening the log file.
179      */

180     public synchronized File JavaDoc switchLogFile(File JavaDoc logFile)
181         throws java.io.IOException JavaDoc {
182         PrintWriter JavaDoc oldLogFileStream = logFileStream;
183         File JavaDoc oldActiveLogFile = activeLogFile;
184         // Append output stream without auto-flush (we do it explictly).
185
FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(logFile.getPath(),
186                 true);
187
188         logFileStream = new PrintWriter JavaDoc(out, false);
189         activeLogFile = logFile;
190         // Close old, if it exists. Waiting for any accessors.
191
if (oldLogFileStream != null) {
192             synchronized (oldLogFileStream) {
193                 oldLogFileStream.close();
194             }
195         }
196         return oldActiveLogFile;
197     }
198
199     /**
200      * Configure the logger. All current configuration is discarded.
201      * This is a simplistic initial implementation that just allows
202      * directing to a single log file or stderr on a level basis.
203      * A more complete interface will be provided in the future.
204      *
205      * @param logFile The log file to write to.
206      * @param fileLevels List of levels that will be written to the file.
207      * @param stderrLevels List of levels that will be written to stderr.
208      * The same level may appear in both lists.
209      * @exception java.io.IOException If an error occurs opening the log file.
210      */

211     public synchronized void configure(File JavaDoc logFile,
212             String JavaDoc[] fileLevels,
213             String JavaDoc[] stderrLevels)
214         throws java.io.IOException JavaDoc {
215         // Ensure that the directory exists.
216
if (logFile.getParent() != null) {
217             new File JavaDoc(logFile.getParent()).mkdirs();
218         }
219         // Output streams without auto-flush (we do it explictly).
220
switchLogFile(logFile);
221         stderrStream = new PrintWriter JavaDoc(System.err, false);
222
223         /*
224          * Tables must be created after streams, as they are
225          * the checked before accessing the stream. Care is taken
226          * that all three arrays that are indexed by level are of
227          * the same size and never shrink on reconfigure. This
228          * mean no synchronization is required to access them. Also
229          * enabled table must be done last.
230          */

231         int maxLevelNum;
232         int levelNum;
233
234         if (enabledLevelFlags != null) {
235             maxLevelNum = enabledLevelFlags.length - 1;
236         } else {
237             maxLevelNum = MAX_STD_LEVEL;
238         }
239         levelNum = getMaxLevel(fileLevels);
240         if (levelNum > maxLevelNum) {
241             maxLevelNum = levelNum;
242         }
243         levelNum = getMaxLevel(stderrLevels);
244         if (levelNum > maxLevelNum) {
245             maxLevelNum = levelNum;
246         }
247         // Build boolean tables.
248
logFileLevelFlags = getLevelStateArray(fileLevels, maxLevelNum);
249         stderrLevelFlags = getLevelStateArray(stderrLevels, maxLevelNum);
250         enabledLevelFlags = new boolean[maxLevelNum + 1];
251         for (int idx = 0; idx < logFileLevelFlags.length; idx++) {
252             if (logFileLevelFlags[idx]) {
253                 enabledLevelFlags[idx] = true;
254             }
255         }
256         for (int idx = 0; idx < stderrLevelFlags.length; idx++) {
257             if (stderrLevelFlags[idx]) {
258                 enabledLevelFlags[idx] = true;
259             }
260         }
261     }
262
263     /**
264      * Create a log channel.
265      */

266     private synchronized StandardLogChannel createChannel(String JavaDoc facility) {
267         StandardLogChannel channel
268                 = (StandardLogChannel) logChannels.get(facility);
269
270         if (channel == null) {
271             channel = new StandardLogChannel(facility, this);
272             logChannels.put(facility, channel);
273         }
274         return channel;
275     }
276
277     /**
278      * Get the log channel object for a facility. For a given facility,
279      * the same object is always returned.
280      *
281      * @param facility Facility the channel is associated with.
282      */

283     public LogChannel getChannel(String JavaDoc facility) {
284         StandardLogChannel channel
285                 = (StandardLogChannel) logChannels.get(facility);
286
287         if (channel == null) {
288             // Slow path, synchronized
289
channel = createChannel(facility);
290         }
291         return channel;
292     }
293
294     /**
295      * Create a log level.
296      */

297     private synchronized Integer JavaDoc createLevel(String JavaDoc level) {
298         Integer JavaDoc intLevel = (Integer JavaDoc) levelNumbers.get(level);
299
300         if (intLevel == null) {
301             intLevel = new Integer JavaDoc(numLevels);
302             levelNames[numLevels] = level;
303             levelNumbers.put(level, intLevel);
304             numLevels++;
305         }
306         return intLevel;
307     }
308
309     /**
310      * Convert a symbolic level to an integer identifier,
311      * creating it if it doesn't exist
312      *
313      * @param level Symbolic level that is to be checked.
314      * @return The numeric level identifier
315      */

316     public synchronized int getLevel(String JavaDoc level) {
317         Integer JavaDoc intLevel = (Integer JavaDoc) levelNumbers.get(level);
318
319         if (intLevel == null) {
320             // Slow path, synchronized
321
intLevel = createLevel(level);
322         }
323         return intLevel.intValue();
324     }
325
326     /**
327      * Convert an int to a symbolic level name.
328      *
329      * @param level an int level.
330      * @return The String symolic level name or null if there is not one.
331      */

332     public String JavaDoc getLevelName(int level) {
333         if ((level >= 0) && (level < numLevels)) {
334             return levelNames[level];
335         } else {
336             return null;
337         }
338     }
339     
340     /**
341      * Configure Logger with given config file, interpreting of config file is
342      * logger implementation specific.
343      *
344      * @param confFilePath Path to configuration file.
345      */

346     public void configure(String JavaDoc confFilePath) throws ConfigException {
347         try {
348             FileInputStream JavaDoc configFIS = new FileInputStream JavaDoc(confFilePath);
349             ConfigFile cFile = new ConfigFile(configFIS);
350             Config config = cFile.getConfig();
351
352             configFIS.close();
353             Config logConfig = (Config) config.getSection(LOG_SECTION);
354
355             configure(logConfig);
356         } catch (KeywordValueException kve) {
357             throw new ConfigException("Error parsing configuration for logger.",
358                     kve);
359         } catch (IOException JavaDoc ioe) {
360             throw new ConfigException("Error configuring logger.", ioe);
361         }
362     }
363
364     /**
365      * Configure Logger with given config section
366      *
367      * @param logConfig containing parameters for configuring logger
368      */

369     public void configure(Config logConfig) throws ConfigException {
370         if (logConfig == null) {
371             throw new ConfigException("Cannot configure logger. Config is null.");
372         } else {
373             String JavaDoc logFile = null;
374
375             logFile = logConfig.getString(LOG_FILE);
376             String JavaDoc[] toFile = null;
377
378             toFile = logConfig.getStrings(LOG_TO_FILE);
379             String JavaDoc[] toStderr = null;
380
381             toStderr = logConfig.getStrings(LOG_TO_STDERR);
382             File JavaDoc theLogFile = new File JavaDoc(logFile);
383
384             try {
385                 configure(theLogFile, toFile, toStderr);
386             } catch (IOException JavaDoc ioe) {
387                 throw new ConfigException("Error configuring logger.",
388                         ioe);
389             }
390         }
391     }
392 }
393
Popular Tags