Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/rmi/runtime/Log.java
38829 views
/*1* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.rmi.runtime;2627import java.io.ByteArrayOutputStream;28import java.io.IOException;29import java.io.PrintStream;30import java.io.OutputStream;31import java.rmi.server.LogStream;32import java.util.logging.ConsoleHandler;33import java.util.logging.Handler;34import java.util.logging.Formatter;35import java.util.logging.SimpleFormatter;36import java.util.logging.StreamHandler;37import java.util.logging.Level;38import java.util.logging.Logger;39import java.util.logging.LogManager;40import java.util.logging.LogRecord;41import java.util.logging.StreamHandler;42import java.util.Map;43import java.util.HashMap;4445/**46* Utility which provides an abstract "logger" like RMI internal API47* which can be directed to use one of two types of logging48* infrastructure: the java.util.logging API or the49* java.rmi.server.LogStream API. The default behavior is to use the50* java.util.logging API. The LogStream API may be used instead by51* setting the system property sun.rmi.log.useOld to true.52*53* For backwards compatibility, supports the RMI system logging54* properties which pre-1.4 comprised the only way to configure RMI55* logging. If the java.util.logging API is used and RMI system log56* properties are set, the system properties override initial RMI57* logger values as appropriate. If the java.util.logging API is58* turned off, pre-1.4 logging behavior is used.59*60* @author Laird Dornin61* @since 1.462*/63@SuppressWarnings("deprecation")64public abstract class Log {6566/** Logger re-definition of old RMI log values */67public static final Level BRIEF = Level.FINE;68public static final Level VERBOSE = Level.FINER;6970/* selects log implementation */71private static final LogFactory logFactory;72static {73boolean useOld =74Boolean.valueOf(java.security.AccessController.75doPrivileged(new sun.security.action.GetPropertyAction(76"sun.rmi.log.useOld"))).booleanValue();7778/* set factory to select the logging facility to use */79logFactory = (useOld ? (LogFactory) new LogStreamLogFactory() :80(LogFactory) new LoggerLogFactory());81}8283/** "logger like" API to be used by RMI implementation */84public abstract boolean isLoggable(Level level);85public abstract void log(Level level, String message);86public abstract void log(Level level, String message, Throwable thrown);8788/** get and set the RMI server call output stream */89public abstract void setOutputStream(OutputStream stream);90public abstract PrintStream getPrintStream();9192/** factory interface enables Logger and LogStream implementations */93private static interface LogFactory {94Log createLog(String loggerName, String oldLogName, Level level);95}9697/* access log objects */9899/**100* Access log for a tri-state system property.101*102* Need to first convert override value to a log level, taking103* care to interpret a range of values between BRIEF, VERBOSE and104* SILENT.105*106* An override < 0 is interpreted to mean that the logging107* configuration should not be overridden. The level passed to the108* factories createLog method will be null in this case.109*110* Note that if oldLogName is null and old logging is on, the111* returned LogStreamLog will ignore the override parameter - the112* log will never log messages. This permits new logs that only113* write to Loggers to do nothing when old logging is active.114*115* Do not call getLog multiple times on the same logger name.116* Since this is an internal API, no checks are made to ensure117* that multiple logs do not exist for the same logger.118*/119public static Log getLog(String loggerName, String oldLogName,120int override)121{122Level level;123124if (override < 0) {125level = null;126} else if (override == LogStream.SILENT) {127level = Level.OFF;128} else if ((override > LogStream.SILENT) &&129(override <= LogStream.BRIEF)) {130level = BRIEF;131} else if ((override > LogStream.BRIEF) &&132(override <= LogStream.VERBOSE))133{134level = VERBOSE;135} else {136level = Level.FINEST;137}138return logFactory.createLog(loggerName, oldLogName, level);139}140141/**142* Access logs associated with boolean properties143*144* Do not call getLog multiple times on the same logger name.145* Since this is an internal API, no checks are made to ensure146* that multiple logs do not exist for the same logger.147*/148public static Log getLog(String loggerName, String oldLogName,149boolean override)150{151Level level = (override ? VERBOSE : null);152return logFactory.createLog(loggerName, oldLogName, level);153}154155/**156* Factory to create Log objects which deliver log messages to the157* java.util.logging API.158*/159private static class LoggerLogFactory implements LogFactory {160LoggerLogFactory() {}161162/*163* Accessor to obtain an arbitrary RMI logger with name164* loggerName. If the level of the logger is greater than the165* level for the system property with name, the logger level166* will be set to the value of system property.167*/168public Log createLog(final String loggerName, String oldLogName,169final Level level)170{171Logger logger = Logger.getLogger(loggerName);172return new LoggerLog(logger, level);173}174}175176/**177* Class specialized to log messages to the java.util.logging API178*/179private static class LoggerLog extends Log {180181/* alternate console handler for RMI loggers */182private static final Handler alternateConsole =183java.security.AccessController.doPrivileged(184new java.security.PrivilegedAction<Handler>() {185public Handler run() {186InternalStreamHandler alternate =187new InternalStreamHandler(System.err);188alternate.setLevel(Level.ALL);189return alternate;190}191});192193/** handler to which messages are copied */194private InternalStreamHandler copyHandler = null;195196/* logger to which log messages are written */197private final Logger logger;198199/* used as return value of RemoteServer.getLog */200private LoggerPrintStream loggerSandwich;201202/** creates a Log which will delegate to the given logger */203private LoggerLog(final Logger logger, final Level level) {204this.logger = logger;205206if (level != null){207java.security.AccessController.doPrivileged(208new java.security.PrivilegedAction<Void>() {209public Void run() {210if (!logger.isLoggable(level)) {211logger.setLevel(level);212}213logger.addHandler(alternateConsole);214return null;215}216}217);218}219}220221public boolean isLoggable(Level level) {222return logger.isLoggable(level);223}224225public void log(Level level, String message) {226if (isLoggable(level)) {227String[] source = getSource();228logger.logp(level, source[0], source[1],229Thread.currentThread().getName() + ": " + message);230}231}232233public void log(Level level, String message, Throwable thrown) {234if (isLoggable(level)) {235String[] source = getSource();236logger.logp(level, source[0], source[1],237Thread.currentThread().getName() + ": " +238message, thrown);239}240}241242/**243* Set the output stream associated with the RMI server call244* logger.245*246* Calling code needs LoggingPermission "control".247*/248public synchronized void setOutputStream(OutputStream out) {249if (out != null) {250if (!logger.isLoggable(VERBOSE)) {251logger.setLevel(VERBOSE);252}253copyHandler = new InternalStreamHandler(out);254copyHandler.setLevel(Log.VERBOSE);255logger.addHandler(copyHandler);256} else {257/* ensure that messages are not logged */258if (copyHandler != null) {259logger.removeHandler(copyHandler);260}261copyHandler = null;262}263}264265public synchronized PrintStream getPrintStream() {266if (loggerSandwich == null) {267loggerSandwich = new LoggerPrintStream(logger);268}269return loggerSandwich;270}271}272273/**274* Subclass of StreamHandler for redirecting log output. flush275* must be called in the publish and close methods.276*/277private static class InternalStreamHandler extends StreamHandler {278InternalStreamHandler(OutputStream out) {279super(out, new SimpleFormatter());280}281282public void publish(LogRecord record) {283super.publish(record);284flush();285}286287public void close() {288flush();289}290}291292/**293* PrintStream which forwards log messages to the logger. Class294* is needed to maintain backwards compatibility with295* RemoteServer.{set|get}Log().296*/297private static class LoggerPrintStream extends PrintStream {298299/** logger where output of this log is sent */300private final Logger logger;301302/** record the last character written to this stream */303private int last = -1;304305/** stream used for buffering lines */306private final ByteArrayOutputStream bufOut;307308private LoggerPrintStream(Logger logger)309{310super(new ByteArrayOutputStream());311bufOut = (ByteArrayOutputStream) super.out;312this.logger = logger;313}314315public void write(int b) {316if ((last == '\r') && (b == '\n')) {317last = -1;318return;319} else if ((b == '\n') || (b == '\r')) {320try {321/* write the converted bytes of the log message */322String message =323Thread.currentThread().getName() + ": " +324bufOut.toString();325logger.logp(Level.INFO, "LogStream", "print", message);326} finally {327bufOut.reset();328}329} else {330super.write(b);331}332last = b;333}334335public void write(byte b[], int off, int len) {336if (len < 0) {337throw new ArrayIndexOutOfBoundsException(len);338}339for (int i = 0; i < len; i++) {340write(b[off + i]);341}342}343344public String toString() {345return "RMI";346}347}348349/**350* Factory to create Log objects which deliver log messages to the351* java.rmi.server.LogStream API352*/353private static class LogStreamLogFactory implements LogFactory {354LogStreamLogFactory() {}355356/* create a new LogStreamLog for the specified log */357public Log createLog(String loggerName, String oldLogName,358Level level)359{360LogStream stream = null;361if (oldLogName != null) {362stream = LogStream.log(oldLogName);363}364return new LogStreamLog(stream, level);365}366}367368/**369* Class specialized to log messages to the370* java.rmi.server.LogStream API371*/372private static class LogStreamLog extends Log {373/** Log stream to which log messages are written */374private final LogStream stream;375376/** the level of the log as set by associated property */377private int levelValue = Level.OFF.intValue();378379private LogStreamLog(LogStream stream, Level level) {380if ((stream != null) && (level != null)) {381/* if the stream or level is null, don't log any382* messages383*/384levelValue = level.intValue();385}386this.stream = stream;387}388389public synchronized boolean isLoggable(Level level) {390return (level.intValue() >= levelValue);391}392393public void log(Level messageLevel, String message) {394if (isLoggable(messageLevel)) {395String[] source = getSource();396stream.println(unqualifiedName(source[0]) +397"." + source[1] + ": " + message);398}399}400401public void log(Level level, String message, Throwable thrown) {402if (isLoggable(level)) {403/*404* keep output contiguous and maintain the contract of405* RemoteServer.getLog406*/407synchronized (stream) {408String[] source = getSource();409stream.println(unqualifiedName(source[0]) + "." +410source[1] + ": " + message);411thrown.printStackTrace(stream);412}413}414}415416public PrintStream getPrintStream() {417return stream;418}419420public synchronized void setOutputStream(OutputStream out) {421if (out != null) {422if (VERBOSE.intValue() < levelValue) {423levelValue = VERBOSE.intValue();424}425stream.setOutputStream(out);426} else {427/* ensure that messages are not logged */428levelValue = Level.OFF.intValue();429}430}431432/*433* Mimic old log messages that only contain unqualified names.434*/435private static String unqualifiedName(String name) {436int lastDot = name.lastIndexOf(".");437if (lastDot >= 0) {438name = name.substring(lastDot + 1);439}440name = name.replace('$', '.');441return name;442}443}444445/**446* Obtain class and method names of code calling a log method.447*/448private static String[] getSource() {449StackTraceElement[] trace = (new Exception()).getStackTrace();450return new String[] {451trace[3].getClassName(),452trace[3].getMethodName()453};454}455}456457458