/**
* JADE - Java Agent DEvelopment Framework is a framework to develop
* multi-agent systems in compliance with the FIPA specifications.
* Copyright (C) 2000 CSELT S.p.A.
* Copyright (C) 2001,2002 TILab S.p.A.
*
* GNU Lesser General Public License
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package jade.util;
import jade.util.leap.Properties;
import jade.util.leap.Serializable;
import java.util.Hashtable;
import java.io.*;
//#J2ME_EXCLUDE_BEGIN
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.Map;
import java.util.HashMap;
//#J2ME_EXCLUDE_END
/*#MIDP_INCLUDE_BEGIN
import javax.microedition.rms.RecordStore;
#MIDP_INCLUDE_END*/
/**
* This class provides a uniform API to produce logs
* over a set of different and device-dependent logging mechanisms.
* Different implementations of this class are
* provided according to the target environment (J2SE, pJava, MIDP), but all
* of them offer the same API. Finally the MIDP implementation redirects
* logging printouts on a MIDP RecordStore where they can be later inspected
* by means of the OutputViewer MIDlet distributed with the LEAP add-on.
* <br>
* See also this
* <a href="../../../tutorials/logging/JADELoggingService.html"> tutorial </a>
* for an overview of the JADE Logging Service.
* <br>
* Logging levels can be used to control logging output.
* According to java logging philosophy, several logging levels can be set.
* The levels in descending order are: <p>
* SEVERE (highest value) <br>
* WARNING <br>
* INFO <br>
* CONFIG <br>
* FINE <br>
* FINER <br>
* FINEST (lowest value)
* <p> In addition, there is a level OFF that can be used to turn off logging, and a level ALL that can be used to enable logging of all messages.
* <p>
* Notice that re-definition of logging levels was necessary in order to allow
* portability of calling code in PersonalJava e MIDP environments.
* <p>
* For instance, in order to log the warning message "Attention!", the
* following code should be used, independently of the target device: <br><br>
*
* <code>Logger logger = Logger.getMyLogger(this.getClass().getName());</code><br>
* <code>if (logger.isLoggable(logger.WARNING)) </code>
* <br> <code>logger.log(Logger.WARNING,"Attention!"); </code>
* <p>
* Notice that the test <code>isLoggable</code> allows just to improve performance, but
* it has no side-effect.
* <p> <b>J2SE</b><br>
* The J2SE implementation is a pure
* extension of the <code>java.util.logging.Logger</code> class and
* it provides the whole set of
* functionalities of java.util.logging.
* <p> In the J2SE environment, the logging configuration can be initialized by using a logging
* configuration file that will be read at startup. This file is in standard
* java.util.Properties format. The default logging configuration,
* that is part of the JRE distribution,
* can be overridden by setting the java.util.logging.config.file
* system property, like the following example: <br>
* <code>java -Djava.util.logging.config.file=mylogging.properties jade.Boot </code>
*
* <p><b>PersonaJava</b><br>
* In the PJava implementation of the <code>Logger</code> class (available in
* the LEAP add-on) calls to the
* <code>log()</code> method result in calls to <code>System.out.println()</code>.
* Alternatively it is possible to redirect logging printouts to a text file
* by setting the <code>-jade_util_Logger_logfile</code> option. Note that,
* in order to face resource limitations, it is not possible to redirect
* logging printouts produced by different Logger objects to different files.
*
* <p><b>MIDP</b><br>
* In the MIDP implementation of the <code>Logger</code> class (available in
* the LEAP add-on) logging printouts are redirected to a MIDP RecordStore so
* that they can be later viewed
* by means of the <code>jade.util.leap.OutputViewer</code> MIDlet included
* in the LEAP add-on.<br>
* <br>
* The default level for logging is set to INFO, all messages of higher level
* will be logged by default.
* In MIDP and PJava the logging level for a Logger object registererd with
* name x.y.z can be configured by setting the configuration option
* <code>x_y_z_loglevel</code> to one of <code>severe, warning, info, config,
* fine, finer, finest, all</code>. See the LEAP user guide for details about
* how to set JADE configuration options in MIDP and PJava.
*
* @author Rosalba Bochicchio - TILAB
* @author Nicolas Lhuillier - Motorola (MIDP version)
*/
public class Logger
//#J2ME_EXCLUDE_BEGIN
extends java.util.logging.Logger
//#J2ME_EXCLUDE_END
implements Serializable
{
//#J2ME_EXCLUDE_BEGIN
/**
* SEVERE is a message level indicating a serious failure.
**/
public static final Level SEVERE = Level.SEVERE;
/**
* WARNING is a message level indicating a potential problem.
**/
public static final Level WARNING = Level.WARNING;
/**
* INFO is a message level for informational messages.
**/
public static final Level INFO = Level.INFO;
/**
* CONFIG is a message level for static configuration messages.
**/
public static final Level CONFIG = Level.CONFIG;
/**
* FINE is a message level providing tracing information.
**/
public static final Level FINE = Level.FINE;
/**
* FINER indicates a fairly detailed tracing message.
**/
public static final Level FINER = Level.FINER;
/**
* FINEST indicates a highly detailed tracing message
**/
public static final Level FINEST = Level.FINEST;
/**
*ALL indicates that all messages should be logged.
**/
public static final Level ALL = Level.ALL;
/**
* Special level to be used to turn off logging
**/
public static final Level OFF = Level.OFF;
private static Map wrappers = new HashMap();
/**
* Private method to construct a logger for a named subsystem.
* @param name A name for the logger
* @param resourceBundleName Name of ResourceBundle to be used for localizing messages for this logger. May be null if none of the messages require localization.
*/
private Logger(String name,String resourceBundleName){
super(name,resourceBundleName);
}
//////////////////////////////////////////////
// This section is for serialization purposes
//////////////////////////////////////////////
private Object writeReplace() throws ObjectStreamException {
return new DummyLogger(getName());
}
private static class DummyLogger implements Serializable {
private String name;
public DummyLogger(String n) {
name = n;
}
private Object readResolve() throws ObjectStreamException {
return new Logger(name, null);
}
}
//////////////////////////////////////////////
/**
Find or create a logger for a named subsystem.
@param name The name of the logger.
@return the instance of the Logger.
*/
public synchronized static Logger getMyLogger(String name) {
java.util.logging.LogManager mng = java.util.logging.LogManager.getLogManager();
java.util.logging.Logger lg = mng.getLogger(name);
if (lg == null) {
lg = new Logger(name, (String)null);
mng.addLogger(lg);
lg = mng.getLogger(name);
}
else if (!(lg instanceof Logger)) {
// Someone created a java logger for the named subsystem before this method is invoked
lg = getWrapper(lg);
}
return (Logger) lg;
}
private static Logger getWrapper(java.util.logging.Logger lg) {
Logger jadeLogger = (Logger) wrappers.get(lg.getName());
if (jadeLogger == null) {
jadeLogger = new LoggerWrapper(lg);
wrappers.put(lg.getName(), jadeLogger);
}
return jadeLogger;
}
/**
* Inner class LoggerWrapper
*/
private static class LoggerWrapper extends Logger {
private java.util.logging.Logger realLogger;
private LoggerWrapper(java.util.logging.Logger lg) {
super(lg.getName(), (String) null);
realLogger = lg;
}
public void log(LogRecord r) {
realLogger.log(r);
}
}
/**
Initialize the logging mechanism.
This method makes sense only in a PJAVA or MIDP environment,
but is available in J2SE too (where it does nothing) to provide
a uniform interface over the different Java environments.
*/
public static void initialize(Properties pp) {
}
//#J2ME_EXCLUDE_END
private static PrintStream logStream = System.out;
public static void println(String log) {
logStream.println(log);
/*#MIDP_INCLUDE_BEGIN
try {
write(log);
}
catch (Throwable t){
// Maybe the record-store has been closed from the outside. Retry.
theRecordStore = null;
try {
write(log);
}
catch (Throwable t1) {
t.printStackTrace();
theRecordStore = null;
}
}
#MIDP_INCLUDE_END*/
}
/*#J2ME_INCLUDE_BEGIN
//SEVERE is a message level indicating a serious failure.
public static final int SEVERE = 10;
//WARNING is a message level indicating a potential problem.
public static final int WARNING = 9;
//INFO is a message level for informational messages
public static final int INFO = 8;
//CONFIG is a message level for static configuration messages.
public static final int CONFIG = 7;
//FINE is a message level providing tracing information.
public static final int FINE = 5;
//FINER indicates a fairly detailed tracing message.
public static final int FINER = 4;
//FINEST indicates a highly detailed tracing message
public static final int FINEST = 3;
//ALL indicates that all messages should be logged.
public static final int ALL = -2147483648;
//Special level to be used to turn off logging
public static final int OFF = 2147483647;
private static Properties verbosityLevels = null;
private static Hashtable loggers = new Hashtable();
private int myLevel = INFO;
private String myName;
public synchronized static Logger getMyLogger(String name){
Logger l = (Logger) loggers.get(name);
if (l == null) {
StringBuffer sb = new StringBuffer(name.replace('.', '_'));
sb.append("_loglevel");
String key = sb.toString();
int level = INFO;
if (verbosityLevels != null) {
try {
level = getLevel(verbosityLevels.getProperty(key));
}
catch (Exception e) {
// Keep default
}
}
l = new Logger(name, level);
loggers.put(name, l);
}
return l;
}
public static void initialize(Properties pp) {
if (pp != null) {
PrintStream ps = initLogStream(pp);
if (ps != null) {
logStream = ps;
}
verbosityLevels = pp;
}
else {
verbosityLevels = new Properties();
}
}
private static int getLevel(String level) {
if (level != null) {
try {
return Integer.parseInt(level);
}
catch (Exception e) {
if (level.equals("severe"))
return SEVERE;
if (level.equals("warning"))
return WARNING;
if (level.equals("info"))
return INFO;
if (level.equals("config"))
return CONFIG;
if (level.equals("fine"))
return FINE;
if (level.equals("finer"))
return FINER;
if (level.equals("finest"))
return FINEST;
if (level.equals("all"))
return ALL;
if (level.equals("off"))
return OFF;
}
}
// If we get here either nothing or a wrong value was specified --> use default
return INFO;
}
// Private constructor. The getMyLogger() static method must be used
private Logger(String name, int level) {
myName = name;
myLevel = level;
}
// Check if the current level is loggable
public boolean isLoggable(int level){
if(level >= myLevel) {
return true;
}
else {
return false;
}
}
public void log(int level, String msg) {
log(level, msg, null);
}
public void log(int level, String msg, Throwable t) {
if(level >= myLevel){
StringBuffer sb = new StringBuffer(myName);
sb.append(": ");
sb.append(msg);
if (t != null) {
sb.append('[');
sb.append(t);
sb.append(']');
}
println(sb.toString());
}
}
#J2ME_INCLUDE_END*/
/*#PJAVA_INCLUDE_BEGIN
private static PrintStream initLogStream(Properties pp) {
String logprefix = pp.getProperty("jade_util_Logger_logfile");
if (logprefix != null) {
try {
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("ddMMyyyy");
String logfile = logprefix + sdf.format(new java.util.Date()) + ".txt";
return new PrintStream(new FileOutputStream(logfile, true)) {
private java.text.SimpleDateFormat hourFormatter = new java.text.SimpleDateFormat("HH:mm:ss");
public void println(String s) {
s = hourFormatter.format(new java.util.Date()) + " " + s;
super.println(s);
}
};
}
catch (Exception e) {
println("Cannot initialize log stream. "+e);
}
}
return null;
}
#PJAVA_INCLUDE_END*/
/*#MIDP_INCLUDE_BEGIN
private static final String OUTPUT = "OUTPUT";
private static RecordStore theRecordStore;
private static volatile int cnt = 0;
static {
try {
RecordStore.deleteRecordStore(OUTPUT);
}
catch (Exception e) {
// The RS does not exist yet --> No need to reset it
}
}
private static void write(String msg) throws Throwable {
if (theRecordStore == null) {
theRecordStore = RecordStore.openRecordStore(OUTPUT, true);
}
StringBuffer sb = new StringBuffer();
sb.append(cnt);
cnt++;
sb.append(") ");
sb.append(msg);
byte[] bb = sb.toString().getBytes();
theRecordStore.addRecord(bb,0,bb.length);
}
private static PrintStream initLogStream(Properties pp) {
return null;
}
#MIDP_INCLUDE_END*/
}