/* * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.rmi.runtime; import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.PrintStream;import java.io.OutputStream;import java.rmi.server.LogStream;import java.util.logging.ConsoleHandler;import java.util.logging.Handler;import java.util.logging.Formatter;import java.util.logging.SimpleFormatter;import java.util.logging.StreamHandler;import java.util.logging.Level;import java.util.logging.Logger;import java.util.logging.LogManager;import java.util.logging.LogRecord;import java.util.logging.StreamHandler;import java.util.Map;import java.util.HashMap; /** * Utility which provides an abstract "logger" like RMI internal API * which can be directed to use one of two types of logging * infrastructure: the java.util.logging API or the * java.rmi.server.LogStream API. The default behavior is to use the * java.util.logging API. The LogStream API may be used instead by * setting the system property sun.rmi.log.useOld to true. * * For backwards compatibility, supports the RMI system logging * properties which pre-1.4 comprised the only way to configure RMI * logging. If the java.util.logging API is used and RMI system log * properties are set, the system properties override initial RMI * logger values as appropriate. If the java.util.logging API is * turned off, pre-1.4 logging behavior is used. * * @author Laird Dornin * @since 1.4 */public abstract class Log { /** Logger re-definition of old RMI log values */ public static final Level BRIEF = Level.FINE; public static final Level VERBOSE = Level.FINER; /* selects log implementation */ private static final LogFactory logFactory; static { boolean useOld = Boolean.valueOf(java.security.AccessController. doPrivileged(new sun.security.action.GetPropertyAction( "sun.rmi.log.useOld"))).booleanValue(); /* set factory to select the logging facility to use */ logFactory = (useOld ? (LogFactory) new LogStreamLogFactory() : (LogFactory) new LoggerLogFactory()); } /** "logger like" API to be used by RMI implementation */ public abstract boolean isLoggable(Level level); public abstract void log(Level level, String message); public abstract void log(Level level, String message, Throwable thrown); /** get and set the RMI server call output stream */ public abstract void setOutputStream(OutputStream stream); public abstract PrintStream getPrintStream(); /** factory interface enables Logger and LogStream implementations */ private static interface LogFactory { Log createLog(String loggerName, String oldLogName, Level level); } /* access log objects */ /** * Access log for a tri-state system property. * * Need to first convert override value to a log level, taking * care to interpret a range of values between BRIEF, VERBOSE and * SILENT. * * An override < 0 is interpreted to mean that the logging * configuration should not be overridden. The level passed to the * factories createLog method will be null in this case. * * Note that if oldLogName is null and old logging is on, the * returned LogStreamLog will ignore the override parameter - the * log will never log messages. This permits new logs that only * write to Loggers to do nothing when old logging is active. * * Do not call getLog multiple times on the same logger name. * Since this is an internal API, no checks are made to ensure * that multiple logs do not exist for the same logger. */ public static Log getLog(String loggerName, String oldLogName, int override) { Level level; if (override < 0) { level = null; } else if (override == LogStream.SILENT) { level = Level.OFF; } else if ((override > LogStream.SILENT) && (override <= LogStream.BRIEF)) { level = BRIEF; } else if ((override > LogStream.BRIEF) && (override <= LogStream.VERBOSE)) { level = VERBOSE; } else { level = Level.FINEST; } return logFactory.createLog(loggerName, oldLogName, level); } /** * Access logs associated with boolean properties * * Do not call getLog multiple times on the same logger name. * Since this is an internal API, no checks are made to ensure * that multiple logs do not exist for the same logger. */ public static Log getLog(String loggerName, String oldLogName, boolean override) { Level level = (override ? VERBOSE : null); return logFactory.createLog(loggerName, oldLogName, level); } /** * Factory to create Log objects which deliver log messages to the * java.util.logging API. */ private static class LoggerLogFactory implements LogFactory { LoggerLogFactory() {} /* * Accessor to obtain an arbitrary RMI logger with name * loggerName. If the level of the logger is greater than the * level for the system property with name, the logger level * will be set to the value of system property. */ public Log createLog(final String loggerName, String oldLogName, final Level level) { Logger logger = Logger.getLogger(loggerName); return new LoggerLog(logger, level); } } /** * Class specialized to log messages to the java.util.logging API */ private static class LoggerLog extends Log { /* alternate console handler for RMI loggers */ private static final Handler alternateConsole = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Handler>() { public Handler run() { InternalStreamHandler alternate = new InternalStreamHandler(System.err); alternate.setLevel(Level.ALL); return alternate; } }); /** handler to which messages are copied */ private InternalStreamHandler copyHandler = null; /* logger to which log messages are written */ private final Logger logger; /* used as return value of RemoteServer.getLog */ private LoggerPrintStream loggerSandwich; /** creates a Log which will delegate to the given logger */ private LoggerLog(final Logger logger, final Level level) { this.logger = logger; if (level != null){ java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { if (!logger.isLoggable(level)) { logger.setLevel(level); } logger.addHandler(alternateConsole); return null; } } ); } } public boolean isLoggable(Level level) { return logger.isLoggable(level); } public void log(Level level, String message) { if (isLoggable(level)) { String[] source = getSource(); logger.logp(level, source[0], source[1], Thread.currentThread().getName() + ": " + message); } } public void log(Level level, String message, Throwable thrown) { if (isLoggable(level)) { String[] source = getSource(); logger.logp(level, source[0], source[1], Thread.currentThread().getName() + ": " + message, thrown); } } /** * Set the output stream associated with the RMI server call * logger. * * Calling code needs LoggingPermission "control". */ public synchronized void setOutputStream(OutputStream out) { if (out != null) { if (!logger.isLoggable(VERBOSE)) { logger.setLevel(VERBOSE); } copyHandler = new InternalStreamHandler(out); copyHandler.setLevel(Log.VERBOSE); logger.addHandler(copyHandler); } else { /* ensure that messages are not logged */ if (copyHandler != null) { logger.removeHandler(copyHandler); } copyHandler = null; } } public synchronized PrintStream getPrintStream() { if (loggerSandwich == null) { loggerSandwich = new LoggerPrintStream(logger); } return loggerSandwich; } } /** * Subclass of StreamHandler for redirecting log output. flush * must be called in the publish and close methods. */ private static class InternalStreamHandler extends StreamHandler { InternalStreamHandler(OutputStream out) { super(out, new SimpleFormatter()); } public void publish(LogRecord record) { super.publish(record); flush(); } public void close() { flush(); } } /** * PrintStream which forwards log messages to the logger. Class * is needed to maintain backwards compatibility with * RemoteServer.{set|get}Log(). */ private static class LoggerPrintStream extends PrintStream { /** logger where output of this log is sent */ private final Logger logger; /** record the last character written to this stream */ private int last = -1; /** stream used for buffering lines */ private final ByteArrayOutputStream bufOut; private LoggerPrintStream(Logger logger) { super(new ByteArrayOutputStream()); bufOut = (ByteArrayOutputStream) super.out; this.logger = logger; } public void write(int b) { if ((last == '\r') && (b == '\n')) { last = -1; return; } else if ((b == '\n') || (b == '\r')) { try { /* write the converted bytes of the log message */ String message = Thread.currentThread().getName() + ": " + bufOut.toString(); logger.logp(Level.INFO, "LogStream", "print", message); } finally { bufOut.reset(); } } else { super.write(b); } last = b; } public void write(byte b[], int off, int len) { if (len < 0) { throw new ArrayIndexOutOfBoundsException(len); } for (int i = 0; i < len; i++) { write(b[off + i]); } } public String toString() { return "RMI"; } } /** * Factory to create Log objects which deliver log messages to the * java.rmi.server.LogStream API */ private static class LogStreamLogFactory implements LogFactory { LogStreamLogFactory() {} /* create a new LogStreamLog for the specified log */ public Log createLog(String loggerName, String oldLogName, Level level) { LogStream stream = null; if (oldLogName != null) { stream = LogStream.log(oldLogName); } return new LogStreamLog(stream, level); } } /** * Class specialized to log messages to the * java.rmi.server.LogStream API */ private static class LogStreamLog extends Log { /** Log stream to which log messages are written */ private final LogStream stream; /** the level of the log as set by associated property */ private int levelValue = Level.OFF.intValue(); private LogStreamLog(LogStream stream, Level level) { if ((stream != null) && (level != null)) { /* if the stream or level is null, dont log any * messages */ levelValue = level.intValue(); } this.stream = stream; } public synchronized boolean isLoggable(Level level) { return (level.intValue() >= levelValue); } public void log(Level messageLevel, String message) { if (isLoggable(messageLevel)) { String[] source = getSource(); stream.println(unqualifiedName(source[0]) + "." + source[1] + ": " + message); } } public void log(Level level, String message, Throwable thrown) { if (isLoggable(level)) { /* * keep output contiguous and maintain the contract of * RemoteServer.getLog */ synchronized (stream) { String[] source = getSource(); stream.println(unqualifiedName(source[0]) + "." + source[1] + ": " + message); thrown.printStackTrace(stream); } } } public PrintStream getPrintStream() { return stream; } public synchronized void setOutputStream(OutputStream out) { if (out != null) { if (VERBOSE.intValue() < levelValue) { levelValue = VERBOSE.intValue(); } stream.setOutputStream(out); } else { /* ensure that messages are not logged */ levelValue = Level.OFF.intValue(); } } /* * Mimic old log messages that only contain unqualified names. */ private static String unqualifiedName(String name) { int lastDot = name.lastIndexOf("."); if (lastDot >= 0) { name = name.substring(lastDot + 1); } name = name.replace('$', '.'); return name; } } /** * Obtain class and method names of code calling a log method. */ private static String[] getSource() { StackTraceElement[] trace = (new Exception()).getStackTrace(); return new String[] { trace[3].getClassName(), trace[3].getMethodName() }; }}
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.rmi.runtime;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.OutputStream;
import java.rmi.server.LogStream;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Formatter;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;
import java.util.Map;
import java.util.HashMap;
/**
* Utility which provides an abstract "logger" like RMI internal API
* which can be directed to use one of two types of logging
* infrastructure: the java.util.logging API or the
* java.rmi.server.LogStream API. The default behavior is to use the
* java.util.logging API. The LogStream API may be used instead by
* setting the system property sun.rmi.log.useOld to true.
*
* For backwards compatibility, supports the RMI system logging
* properties which pre-1.4 comprised the only way to configure RMI
* logging. If the java.util.logging API is used and RMI system log
* properties are set, the system properties override initial RMI
* logger values as appropriate. If the java.util.logging API is
* turned off, pre-1.4 logging behavior is used.
*
* @author Laird Dornin
* @since 1.4
*/
public abstract class Log {
/** Logger re-definition of old RMI log values */
public static final Level BRIEF = Level.FINE;
public static final Level VERBOSE = Level.FINER;
/* selects log implementation */
private static final LogFactory logFactory;
static {
boolean useOld =
Boolean.valueOf(java.security.AccessController.
doPrivileged(new sun.security.action.GetPropertyAction(
"sun.rmi.log.useOld"))).booleanValue();
/* set factory to select the logging facility to use */
logFactory = (useOld ? (LogFactory) new LogStreamLogFactory() :
(LogFactory) new LoggerLogFactory());
}
/** "logger like" API to be used by RMI implementation */
public abstract boolean isLoggable(Level level);
public abstract void log(Level level, String message);
public abstract void log(Level level, String message, Throwable thrown);
/** get and set the RMI server call output stream */
public abstract void setOutputStream(OutputStream stream);
public abstract PrintStream getPrintStream();
/** factory interface enables Logger and LogStream implementations */
private static interface LogFactory {
Log createLog(String loggerName, String oldLogName, Level level);
}
/* access log objects */
/**
* Access log for a tri-state system property.
*
* Need to first convert override value to a log level, taking
* care to interpret a range of values between BRIEF, VERBOSE and
* SILENT.
*
* An override < 0 is interpreted to mean that the logging
* configuration should not be overridden. The level passed to the
* factories createLog method will be null in this case.
*
* Note that if oldLogName is null and old logging is on, the
* returned LogStreamLog will ignore the override parameter - the
* log will never log messages. This permits new logs that only
* write to Loggers to do nothing when old logging is active.
*
* Do not call getLog multiple times on the same logger name.
* Since this is an internal API, no checks are made to ensure
* that multiple logs do not exist for the same logger.
*/
public static Log getLog(String loggerName, String oldLogName,
int override)
{
Level level;
if (override < 0) {
level = null;
} else if (override == LogStream.SILENT) {
level = Level.OFF;
} else if ((override > LogStream.SILENT) &&
(override <= LogStream.BRIEF)) {
level = BRIEF;
} else if ((override > LogStream.BRIEF) &&
(override <= LogStream.VERBOSE))
{
level = VERBOSE;
} else {
level = Level.FINEST;
}
return logFactory.createLog(loggerName, oldLogName, level);
}
/**
* Access logs associated with boolean properties
*
* Do not call getLog multiple times on the same logger name.
* Since this is an internal API, no checks are made to ensure
* that multiple logs do not exist for the same logger.
*/
public static Log getLog(String loggerName, String oldLogName,
boolean override)
{
Level level = (override ? VERBOSE : null);
return logFactory.createLog(loggerName, oldLogName, level);
}
/**
* Factory to create Log objects which deliver log messages to the
* java.util.logging API.
*/
private static class LoggerLogFactory implements LogFactory {
LoggerLogFactory() {}
/*
* Accessor to obtain an arbitrary RMI logger with name
* loggerName. If the level of the logger is greater than the
* level for the system property with name, the logger level
* will be set to the value of system property.
*/
public Log createLog(final String loggerName, String oldLogName,
final Level level)
{
Logger logger = Logger.getLogger(loggerName);
return new LoggerLog(logger, level);
}
}
/**
* Class specialized to log messages to the java.util.logging API
*/
private static class LoggerLog extends Log {
/* alternate console handler for RMI loggers */
private static final Handler alternateConsole =
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Handler>() {
public Handler run() {
InternalStreamHandler alternate =
new InternalStreamHandler(System.err);
alternate.setLevel(Level.ALL);
return alternate;
}
});
/** handler to which messages are copied */
private InternalStreamHandler copyHandler = null;
/* logger to which log messages are written */
private final Logger logger;
/* used as return value of RemoteServer.getLog */
private LoggerPrintStream loggerSandwich;
/** creates a Log which will delegate to the given logger */
private LoggerLog(final Logger logger, final Level level) {
this.logger = logger;
if (level != null){
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
if (!logger.isLoggable(level)) {
logger.setLevel(level);
}
logger.addHandler(alternateConsole);
return null;
}
}
);
}
}
public boolean isLoggable(Level level) {
return logger.isLoggable(level);
}
public void log(Level level, String message) {
if (isLoggable(level)) {
String[] source = getSource();
logger.logp(level, source[0], source[1],
Thread.currentThread().getName() + ": " + message);
}
}
public void log(Level level, String message, Throwable thrown) {
if (isLoggable(level)) {
String[] source = getSource();
logger.logp(level, source[0], source[1],
Thread.currentThread().getName() + ": " +
message, thrown);
}
}
/**
* Set the output stream associated with the RMI server call
* logger.
*
* Calling code needs LoggingPermission "control".
*/
public synchronized void setOutputStream(OutputStream out) {
if (out != null) {
if (!logger.isLoggable(VERBOSE)) {
logger.setLevel(VERBOSE);
}
copyHandler = new InternalStreamHandler(out);
copyHandler.setLevel(Log.VERBOSE);
logger.addHandler(copyHandler);
} else {
/* ensure that messages are not logged */
if (copyHandler != null) {
logger.removeHandler(copyHandler);
}
copyHandler = null;
}
}
public synchronized PrintStream getPrintStream() {
if (loggerSandwich == null) {
loggerSandwich = new LoggerPrintStream(logger);
}
return loggerSandwich;
}
}
/**
* Subclass of StreamHandler for redirecting log output. flush
* must be called in the publish and close methods.
*/
private static class InternalStreamHandler extends StreamHandler {
InternalStreamHandler(OutputStream out) {
super(out, new SimpleFormatter());
}
public void publish(LogRecord record) {
super.publish(record);
flush();
}
public void close() {
flush();
}
}
/**
* PrintStream which forwards log messages to the logger. Class
* is needed to maintain backwards compatibility with
* RemoteServer.{set|get}Log().
*/
private static class LoggerPrintStream extends PrintStream {
/** logger where output of this log is sent */
private final Logger logger;
/** record the last character written to this stream */
private int last = -1;
/** stream used for buffering lines */
private final ByteArrayOutputStream bufOut;
private LoggerPrintStream(Logger logger)
{
super(new ByteArrayOutputStream());
bufOut = (ByteArrayOutputStream) super.out;
this.logger = logger;
}
public void write(int b) {
if ((last == '\r') && (b == '\n')) {
last = -1;
return;
} else if ((b == '\n') || (b == '\r')) {
try {
/* write the converted bytes of the log message */
String message =
Thread.currentThread().getName() + ": " +
bufOut.toString();
logger.logp(Level.INFO, "LogStream", "print", message);
} finally {
bufOut.reset();
}
} else {
super.write(b);
}
last = b;
}
public void write(byte b[], int off, int len) {
if (len < 0) {
throw new ArrayIndexOutOfBoundsException(len);
}
for (int i = 0; i < len; i++) {
write(b[off + i]);
}
}
public String toString() {
return "RMI";
}
}
/**
* Factory to create Log objects which deliver log messages to the
* java.rmi.server.LogStream API
*/
private static class LogStreamLogFactory implements LogFactory {
LogStreamLogFactory() {}
/* create a new LogStreamLog for the specified log */
public Log createLog(String loggerName, String oldLogName,
Level level)
{
LogStream stream = null;
if (oldLogName != null) {
stream = LogStream.log(oldLogName);
}
return new LogStreamLog(stream, level);
}
}
/**
* Class specialized to log messages to the
* java.rmi.server.LogStream API
*/
private static class LogStreamLog extends Log {
/** Log stream to which log messages are written */
private final LogStream stream;
/** the level of the log as set by associated property */
private int levelValue = Level.OFF.intValue();
private LogStreamLog(LogStream stream, Level level) {
if ((stream != null) && (level != null)) {
/* if the stream or level is null, dont log any
* messages
*/
levelValue = level.intValue();
}
this.stream = stream;
}
public synchronized boolean isLoggable(Level level) {
return (level.intValue() >= levelValue);
}
public void log(Level messageLevel, String message) {
if (isLoggable(messageLevel)) {
String[] source = getSource();
stream.println(unqualifiedName(source[0]) +
"." + source[1] + ": " + message);
}
}
public void log(Level level, String message, Throwable thrown) {
if (isLoggable(level)) {
/*
* keep output contiguous and maintain the contract of
* RemoteServer.getLog
*/
synchronized (stream) {
String[] source = getSource();
stream.println(unqualifiedName(source[0]) + "." +
source[1] + ": " + message);
thrown.printStackTrace(stream);
}
}
}
public PrintStream getPrintStream() {
return stream;
}
public synchronized void setOutputStream(OutputStream out) {
if (out != null) {
if (VERBOSE.intValue() < levelValue) {
levelValue = VERBOSE.intValue();
}
stream.setOutputStream(out);
} else {
/* ensure that messages are not logged */
levelValue = Level.OFF.intValue();
}
}
/*
* Mimic old log messages that only contain unqualified names.
*/
private static String unqualifiedName(String name) {
int lastDot = name.lastIndexOf(".");
if (lastDot >= 0) {
name = name.substring(lastDot + 1);
}
name = name.replace('$', '.');
return name;
}
}
/**
* Obtain class and method names of code calling a log method.
*/
private static String[] getSource() {
StackTraceElement[] trace = (new Exception()).getStackTrace();
return new String[] {
trace[3].getClassName(),
trace[3].getMethodName()
};
}
}