Save This Page
Home » openjdk-7 » sun.rmi » runtime » [javadoc | source]
    1   /*
    2    * Copyright 2001-2002 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package sun.rmi.runtime;
   27   
   28   import java.io.ByteArrayOutputStream;
   29   import java.io.IOException;
   30   import java.io.PrintStream;
   31   import java.io.OutputStream;
   32   import java.rmi.server.LogStream;
   33   import java.util.logging.ConsoleHandler;
   34   import java.util.logging.Handler;
   35   import java.util.logging.Formatter;
   36   import java.util.logging.SimpleFormatter;
   37   import java.util.logging.StreamHandler;
   38   import java.util.logging.Level;
   39   import java.util.logging.Logger;
   40   import java.util.logging.LogManager;
   41   import java.util.logging.LogRecord;
   42   import java.util.logging.StreamHandler;
   43   import java.util.Map;
   44   import java.util.HashMap;
   45   
   46   /**
   47    * Utility which provides an abstract "logger" like RMI internal API
   48    * which can be directed to use one of two types of logging
   49    * infrastructure: the java.util.logging API or the
   50    * java.rmi.server.LogStream API.  The default behavior is to use the
   51    * java.util.logging API.  The LogStream API may be used instead by
   52    * setting the system property sun.rmi.log.useOld to true.
   53    *
   54    * For backwards compatibility, supports the RMI system logging
   55    * properties which pre-1.4 comprised the only way to configure RMI
   56    * logging.  If the java.util.logging API is used and RMI system log
   57    * properties are set, the system properties override initial RMI
   58    * logger values as appropriate. If the java.util.logging API is
   59    * turned off, pre-1.4 logging behavior is used.
   60    *
   61    * @author Laird Dornin
   62    * @since 1.4
   63    */
   64   public abstract class Log {
   65   
   66       /** Logger re-definition of old RMI log values */
   67       public static final Level BRIEF = Level.FINE;
   68       public static final Level VERBOSE = Level.FINER;
   69   
   70       /* selects log implementation */
   71       private static final LogFactory logFactory;
   72       static {
   73           boolean useOld =
   74               Boolean.valueOf(java.security.AccessController.
   75                   doPrivileged(new sun.security.action.GetPropertyAction(
   76                       "sun.rmi.log.useOld"))).booleanValue();
   77   
   78           /* set factory to select the logging facility to use */
   79           logFactory = (useOld ? (LogFactory) new LogStreamLogFactory() :
   80                         (LogFactory) new LoggerLogFactory());
   81       }
   82   
   83       /** "logger like" API to be used by RMI implementation */
   84       public abstract boolean isLoggable(Level level);
   85       public abstract void log(Level level, String message);
   86       public abstract void log(Level level, String message, Throwable thrown);
   87   
   88       /** get and set the RMI server call output stream */
   89       public abstract void setOutputStream(OutputStream stream);
   90       public abstract PrintStream getPrintStream();
   91   
   92       /** factory interface enables Logger and LogStream implementations */
   93       private static interface LogFactory {
   94           Log createLog(String loggerName, String oldLogName, Level level);
   95       }
   96   
   97       /* access log objects */
   98   
   99       /**
  100        * Access log for a tri-state system property.
  101        *
  102        * Need to first convert override value to a log level, taking
  103        * care to interpret a range of values between BRIEF, VERBOSE and
  104        * SILENT.
  105        *
  106        * An override < 0 is interpreted to mean that the logging
  107        * configuration should not be overridden. The level passed to the
  108        * factories createLog method will be null in this case.
  109        *
  110        * Note that if oldLogName is null and old logging is on, the
  111        * returned LogStreamLog will ignore the override parameter - the
  112        * log will never log messages.  This permits new logs that only
  113        * 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 ensure
  117        * that multiple logs do not exist for the same logger.
  118        */
  119       public static Log getLog(String loggerName, String oldLogName,
  120                                int override)
  121       {
  122           Level level;
  123   
  124           if (override < 0) {
  125               level = null;
  126           } else if (override == LogStream.SILENT) {
  127               level = Level.OFF;
  128           } else if ((override > LogStream.SILENT) &&
  129                      (override <= LogStream.BRIEF)) {
  130               level = BRIEF;
  131           } else if ((override > LogStream.BRIEF) &&
  132                      (override <= LogStream.VERBOSE))
  133           {
  134               level = VERBOSE;
  135           } else {
  136               level = Level.FINEST;
  137           }
  138           return logFactory.createLog(loggerName, oldLogName, level);
  139       }
  140   
  141       /**
  142        * Access logs associated with boolean properties
  143        *
  144        * Do not call getLog multiple times on the same logger name.
  145        * Since this is an internal API, no checks are made to ensure
  146        * that multiple logs do not exist for the same logger.
  147        */
  148       public static Log getLog(String loggerName, String oldLogName,
  149                                boolean override)
  150       {
  151           Level level = (override ? VERBOSE : null);
  152           return logFactory.createLog(loggerName, oldLogName, level);
  153       }
  154   
  155       /**
  156        * Factory to create Log objects which deliver log messages to the
  157        * java.util.logging API.
  158        */
  159       private static class LoggerLogFactory implements LogFactory {
  160           LoggerLogFactory() {}
  161   
  162           /*
  163            * Accessor to obtain an arbitrary RMI logger with name
  164            * loggerName.  If the level of the logger is greater than the
  165            * level for the system property with name, the logger level
  166            * will be set to the value of system property.
  167            */
  168           public Log createLog(final String loggerName, String oldLogName,
  169                                final Level level)
  170           {
  171               Logger logger = Logger.getLogger(loggerName);
  172               return new LoggerLog(logger, level);
  173           }
  174       }
  175   
  176       /**
  177        * Class specialized to log messages to the java.util.logging API
  178        */
  179       private static class LoggerLog extends Log {
  180   
  181           /* alternate console handler for RMI loggers */
  182           private static final Handler alternateConsole =
  183                   java.security.AccessController.doPrivileged(
  184                   new java.security.PrivilegedAction<Handler>() {
  185                       public Handler run() {
  186                               InternalStreamHandler alternate =
  187                                   new InternalStreamHandler(System.err);
  188                               alternate.setLevel(Level.ALL);
  189                               return alternate;
  190                           }
  191                   });
  192   
  193           /** handler to which messages are copied */
  194           private InternalStreamHandler copyHandler = null;
  195   
  196           /* logger to which log messages are written */
  197           private final Logger logger;
  198   
  199           /* used as return value of RemoteServer.getLog */
  200           private LoggerPrintStream loggerSandwich;
  201   
  202           /** creates a Log which will delegate to the given logger */
  203           private LoggerLog(final Logger logger, final Level level) {
  204               this.logger = logger;
  205   
  206               if (level != null){
  207                   java.security.AccessController.doPrivileged(
  208                       new java.security.PrivilegedAction<Void>() {
  209                           public Void run() {
  210                               if (!logger.isLoggable(level)) {
  211                                   logger.setLevel(level);
  212                               }
  213                               logger.addHandler(alternateConsole);
  214                               return null;
  215                           }
  216                       }
  217                   );
  218               }
  219           }
  220   
  221           public boolean isLoggable(Level level) {
  222               return logger.isLoggable(level);
  223           }
  224   
  225           public void log(Level level, String message) {
  226               if (isLoggable(level)) {
  227                   String[] source = getSource();
  228                   logger.logp(level, source[0], source[1],
  229                              Thread.currentThread().getName() + ": " + message);
  230               }
  231           }
  232   
  233           public void log(Level level, String message, Throwable thrown) {
  234               if (isLoggable(level)) {
  235                   String[] source = getSource();
  236                   logger.logp(level, source[0], source[1],
  237                       Thread.currentThread().getName() + ": " +
  238                              message, thrown);
  239               }
  240           }
  241   
  242           /**
  243            * Set the output stream associated with the RMI server call
  244            * logger.
  245            *
  246            * Calling code needs LoggingPermission "control".
  247            */
  248           public synchronized void setOutputStream(OutputStream out) {
  249               if (out != null) {
  250                   if (!logger.isLoggable(VERBOSE)) {
  251                       logger.setLevel(VERBOSE);
  252                   }
  253                   copyHandler = new InternalStreamHandler(out);
  254                   copyHandler.setLevel(Log.VERBOSE);
  255                   logger.addHandler(copyHandler);
  256               } else {
  257                   /* ensure that messages are not logged */
  258                   if (copyHandler != null) {
  259                       logger.removeHandler(copyHandler);
  260                   }
  261                   copyHandler = null;
  262               }
  263           }
  264   
  265           public synchronized PrintStream getPrintStream() {
  266               if (loggerSandwich == null) {
  267                   loggerSandwich = new LoggerPrintStream(logger);
  268               }
  269               return loggerSandwich;
  270           }
  271       }
  272   
  273       /**
  274        * Subclass of StreamHandler for redirecting log output.  flush
  275        * must be called in the publish and close methods.
  276        */
  277       private static class InternalStreamHandler extends StreamHandler {
  278           InternalStreamHandler(OutputStream out) {
  279               super(out, new SimpleFormatter());
  280           }
  281   
  282           public void publish(LogRecord record) {
  283               super.publish(record);
  284               flush();
  285           }
  286   
  287           public void close() {
  288               flush();
  289           }
  290       }
  291   
  292       /**
  293        * PrintStream which forwards log messages to the logger.  Class
  294        * is needed to maintain backwards compatibility with
  295        * RemoteServer.{set|get}Log().
  296        */
  297       private static class LoggerPrintStream extends PrintStream {
  298   
  299           /** logger where output of this log is sent */
  300           private final Logger logger;
  301   
  302           /** record the last character written to this stream */
  303           private int last = -1;
  304   
  305           /** stream used for buffering lines */
  306           private final ByteArrayOutputStream bufOut;
  307   
  308           private LoggerPrintStream(Logger logger)
  309           {
  310               super(new ByteArrayOutputStream());
  311               bufOut = (ByteArrayOutputStream) super.out;
  312               this.logger = logger;
  313           }
  314   
  315           public void write(int b) {
  316               if ((last == '\r') && (b == '\n')) {
  317                   last = -1;
  318                   return;
  319               } else if ((b == '\n') || (b == '\r')) {
  320                   try {
  321                       /* write the converted bytes of the log message */
  322                       String message =
  323                           Thread.currentThread().getName() + ": " +
  324                           bufOut.toString();
  325                       logger.logp(Level.INFO, "LogStream", "print", message);
  326                   } finally {
  327                       bufOut.reset();
  328                   }
  329               } else {
  330                   super.write(b);
  331               }
  332               last = b;
  333           }
  334   
  335           public void write(byte b[], int off, int len) {
  336               if (len < 0) {
  337                   throw new ArrayIndexOutOfBoundsException(len);
  338               }
  339               for (int i = 0; i < len; i++) {
  340                   write(b[off + i]);
  341               }
  342           }
  343   
  344           public String toString() {
  345               return "RMI";
  346           }
  347       }
  348   
  349       /**
  350        * Factory to create Log objects which deliver log messages to the
  351        * java.rmi.server.LogStream API
  352        */
  353       private static class LogStreamLogFactory implements LogFactory {
  354           LogStreamLogFactory() {}
  355   
  356           /* create a new LogStreamLog for the specified log */
  357           public Log createLog(String loggerName, String oldLogName,
  358                                Level level)
  359           {
  360               LogStream stream = null;
  361               if (oldLogName != null) {
  362                   stream = LogStream.log(oldLogName);
  363               }
  364               return new LogStreamLog(stream, level);
  365           }
  366       }
  367   
  368       /**
  369        * Class specialized to log messages to the
  370        * java.rmi.server.LogStream API
  371        */
  372       private static class LogStreamLog extends Log {
  373           /** Log stream to which log messages are written */
  374           private final LogStream stream;
  375   
  376           /** the level of the log as set by associated property */
  377           private int levelValue = Level.OFF.intValue();
  378   
  379           private LogStreamLog(LogStream stream, Level level) {
  380               if ((stream != null) && (level != null)) {
  381                   /* if the stream or level is null, dont log any
  382                    * messages
  383                    */
  384                   levelValue = level.intValue();
  385               }
  386               this.stream = stream;
  387           }
  388   
  389           public synchronized boolean isLoggable(Level level) {
  390               return (level.intValue() >= levelValue);
  391           }
  392   
  393           public void log(Level messageLevel, String message) {
  394               if (isLoggable(messageLevel)) {
  395                   String[] source = getSource();
  396                   stream.println(unqualifiedName(source[0]) +
  397                                  "." + source[1] + ": " + message);
  398               }
  399           }
  400   
  401           public void log(Level level, String message, Throwable thrown) {
  402               if (isLoggable(level)) {
  403                   /*
  404                    * keep output contiguous and maintain the contract of
  405                    * RemoteServer.getLog
  406                    */
  407                   synchronized (stream) {
  408                       String[] source = getSource();
  409                       stream.println(unqualifiedName(source[0]) + "." +
  410                                      source[1] + ": " + message);
  411                       thrown.printStackTrace(stream);
  412                   }
  413               }
  414           }
  415   
  416           public PrintStream getPrintStream() {
  417               return stream;
  418           }
  419   
  420           public synchronized void setOutputStream(OutputStream out) {
  421               if (out != null) {
  422                   if (VERBOSE.intValue() < levelValue) {
  423                       levelValue = VERBOSE.intValue();
  424                   }
  425                   stream.setOutputStream(out);
  426               } else {
  427                   /* ensure that messages are not logged */
  428                   levelValue = Level.OFF.intValue();
  429               }
  430           }
  431   
  432           /*
  433            * Mimic old log messages that only contain unqualified names.
  434            */
  435           private static String unqualifiedName(String name) {
  436               int lastDot = name.lastIndexOf(".");
  437               if (lastDot >= 0) {
  438                   name = name.substring(lastDot + 1);
  439               }
  440               name = name.replace('$', '.');
  441               return name;
  442           }
  443       }
  444   
  445       /**
  446        * Obtain class and method names of code calling a log method.
  447        */
  448       private static String[] getSource() {
  449           StackTraceElement[] trace = (new Exception()).getStackTrace();
  450           return new String[] {
  451               trace[3].getClassName(),
  452               trace[3].getMethodName()
  453           };
  454       }
  455   }

Save This Page
Home » openjdk-7 » sun.rmi » runtime » [javadoc | source]