mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			522 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			522 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* StreamHandler.java --
 | |
|    A class for publishing log messages to instances of java.io.OutputStream
 | |
|    Copyright (C) 2002 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath 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 for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package java.util.logging;
 | |
| 
 | |
| import java.io.OutputStream;
 | |
| import java.io.OutputStreamWriter;
 | |
| import java.io.UnsupportedEncodingException;
 | |
| import java.io.Writer;
 | |
| 
 | |
| /**
 | |
|  * A <code>StreamHandler</code> publishes <code>LogRecords</code> to
 | |
|  * a instances of <code>java.io.OutputStream</code>.
 | |
|  *
 | |
|  * @author Sascha Brawer (brawer@acm.org)
 | |
|  */
 | |
| public class StreamHandler
 | |
|   extends Handler
 | |
| {
 | |
|   private OutputStream  out;
 | |
|   private Writer        writer;
 | |
| 
 | |
| 
 | |
|  /**
 | |
|   * Indicates the current state of this StreamHandler.  The value
 | |
|   * should be one of STATE_FRESH, STATE_PUBLISHED, or STATE_CLOSED.
 | |
|   */
 | |
|   private int streamState = STATE_FRESH;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * streamState having this value indicates that the StreamHandler
 | |
|    * has been created, but the publish(LogRecord) method has not been
 | |
|    * called yet.  If the StreamHandler has been constructed without an
 | |
|    * OutputStream, writer will be null, otherwise it is set to a
 | |
|    * freshly created OutputStreamWriter.
 | |
|    */
 | |
|   private static final int STATE_FRESH = 0;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * streamState having this value indicates that the publish(LocRecord)
 | |
|    * method has been called at least once.
 | |
|    */
 | |
|   private static final int STATE_PUBLISHED = 1;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * streamState having this value indicates that the close() method
 | |
|    * has been called.
 | |
|    */
 | |
|   private static final int STATE_CLOSED = 2;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Creates a <code>StreamHandler</code> without an output stream.
 | |
|    * Subclasses can later use {@link
 | |
|    * #setOutputStream(java.io.OutputStream)} to associate an output
 | |
|    * stream with this StreamHandler.
 | |
|    */
 | |
|   public StreamHandler()
 | |
|   {
 | |
|     this(null, null);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Creates a <code>StreamHandler</code> that formats log messages
 | |
|    * with the specified Formatter and publishes them to the specified
 | |
|    * output stream.
 | |
|    *
 | |
|    * @param out the output stream to which the formatted log messages
 | |
|    *     are published.
 | |
|    *
 | |
|    * @param formatter the <code>Formatter</code> that will be used
 | |
|    *     to format log messages.
 | |
|    */
 | |
|   public StreamHandler(OutputStream out, Formatter formatter)
 | |
|   {
 | |
|     this(out, "java.util.logging.StreamHandler", Level.INFO,
 | |
|          formatter, SimpleFormatter.class);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   StreamHandler(
 | |
|     OutputStream out,
 | |
|     String propertyPrefix,
 | |
|     Level defaultLevel,
 | |
|     Formatter formatter, Class defaultFormatterClass)
 | |
|   {
 | |
|     this.level = LogManager.getLevelProperty(propertyPrefix + ".level",
 | |
|                                              defaultLevel);
 | |
| 
 | |
|     this.filter = (Filter) LogManager.getInstanceProperty(
 | |
|       propertyPrefix + ".filter",
 | |
|       /* must be instance of */       Filter.class,
 | |
|       /* default: new instance of */  null);
 | |
| 
 | |
|     if (formatter != null)
 | |
|       this.formatter = formatter;
 | |
|     else
 | |
|       this.formatter = (Formatter) LogManager.getInstanceProperty(
 | |
|         propertyPrefix + ".formatter",
 | |
|         /* must be instance of */       Formatter.class,
 | |
|         /* default: new instance of */  defaultFormatterClass);
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       String enc = LogManager.getLogManager().getProperty(propertyPrefix
 | |
|                                                           + ".encoding");
 | |
| 
 | |
|       /* make sure enc actually is a valid encoding */
 | |
|       if ((enc != null) && (enc.length() > 0))
 | |
|         new String(new byte[0], enc);
 | |
| 
 | |
|       this.encoding = enc;
 | |
|     }
 | |
|     catch (Exception _)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     if (out != null)
 | |
|     {
 | |
|       try
 | |
|       {
 | |
|         changeWriter(out, getEncoding());
 | |
|       }
 | |
|       catch (UnsupportedEncodingException uex)
 | |
|       {
 | |
|         /* This should never happen, since the validity of the encoding
 | |
|          * name has been checked above.
 | |
|          */
 | |
|         throw new RuntimeException(uex.getMessage());
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   private void checkOpen()
 | |
|   {
 | |
|     if (streamState == STATE_CLOSED)
 | |
|       throw new IllegalStateException(this.toString() + " has been closed");
 | |
|   }
 | |
| 
 | |
|   private void checkFresh()
 | |
|   {
 | |
|     checkOpen();
 | |
|     if (streamState != STATE_FRESH)
 | |
|       throw new IllegalStateException("some log records have been published to " + this);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   private void changeWriter(OutputStream out, String encoding)
 | |
|     throws UnsupportedEncodingException
 | |
|   {
 | |
|     OutputStreamWriter writer;
 | |
| 
 | |
|     /* The logging API says that a null encoding means the default
 | |
|      * platform encoding. However, java.io.OutputStreamWriter needs
 | |
|      * another constructor for the default platform encoding,
 | |
|      * passing null would throw an exception.
 | |
|      */
 | |
|     if (encoding == null)
 | |
|       writer = new OutputStreamWriter(out);
 | |
|     else
 | |
|       writer = new OutputStreamWriter(out, encoding);
 | |
| 
 | |
|     /* Closing the stream has side effects -- do this only after
 | |
|      * creating a new writer has been successful.
 | |
|      */
 | |
|     if ((streamState != STATE_FRESH) || (this.writer != null))
 | |
|       close();
 | |
| 
 | |
|     this.writer = writer;
 | |
|     this.out = out;
 | |
|     this.encoding = encoding;
 | |
|     streamState = STATE_FRESH;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Sets the character encoding which this handler uses for publishing
 | |
|    * log records.  The encoding of a <code>StreamHandler</code> must be
 | |
|    * set before any log records have been published.
 | |
|    *
 | |
|    * @param encoding the name of a character encoding, or <code>null</code>
 | |
|    *            for the default encoding.
 | |
|    *
 | |
|    * @throws SecurityException if a security manager exists and
 | |
|    *     the caller is not granted the permission to control the
 | |
|    *     the logging infrastructure.
 | |
|    *
 | |
|    * @exception IllegalStateException if any log records have been
 | |
|    *     published to this <code>StreamHandler</code> before.  Please
 | |
|    *     be aware that this is a pecularity of the GNU implementation.
 | |
|    *     While the API specification indicates that it is an error
 | |
|    *     if the encoding is set after records have been published,
 | |
|    *     it does not mandate any specific behavior for that case.
 | |
|    */
 | |
|   public void setEncoding(String encoding)
 | |
|     throws SecurityException, UnsupportedEncodingException
 | |
|   {
 | |
|     /* The inherited implementation first checks whether the invoking
 | |
|      * code indeed has the permission to control the logging infra-
 | |
|      * structure, and throws a SecurityException if this was not the
 | |
|      * case.
 | |
|      *
 | |
|      * Next, it verifies that the encoding is supported and throws
 | |
|      * an UnsupportedEncodingExcpetion otherwise. Finally, it remembers
 | |
|      * the name of the encoding.
 | |
|      */
 | |
|     super.setEncoding(encoding);
 | |
| 
 | |
|     checkFresh();
 | |
| 
 | |
|     /* If out is null, setEncoding is being called before an output
 | |
|      * stream has been set. In that case, we need to check that the
 | |
|      * encoding is valid, and remember it if this is the case.  Since
 | |
|      * this is exactly what the inherited implementation of
 | |
|      * Handler.setEncoding does, we can delegate.
 | |
|      */
 | |
|     if (out != null)
 | |
|     {
 | |
|       /* The logging API says that a null encoding means the default
 | |
|        * platform encoding. However, java.io.OutputStreamWriter needs
 | |
|        * another constructor for the default platform encoding, passing
 | |
|        * null would throw an exception.
 | |
|        */
 | |
|       if (encoding == null)
 | |
|         writer = new OutputStreamWriter(out);
 | |
|       else
 | |
|         writer = new OutputStreamWriter(out, encoding);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Changes the output stream to which this handler publishes
 | |
|    * logging records.
 | |
|    *
 | |
|    * @throws SecurityException if a security manager exists and
 | |
|    *         the caller is not granted the permission to control
 | |
|    *         the logging infrastructure.
 | |
|    *
 | |
|    * @throws NullPointerException if <code>out</code>
 | |
|    *         is <code>null</code>.
 | |
|    */
 | |
|   protected void setOutputStream(OutputStream out)
 | |
|     throws SecurityException
 | |
|   {
 | |
|     LogManager.getLogManager().checkAccess();
 | |
| 
 | |
|     /* Throw a NullPointerException if out is null. */
 | |
|     out.getClass();
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       changeWriter(out, getEncoding());
 | |
|     }
 | |
|     catch (UnsupportedEncodingException ex)
 | |
|     {
 | |
|       /* This seems quite unlikely to happen, unless the underlying
 | |
|        * implementation of java.io.OutputStreamWriter changes its
 | |
|        * mind (at runtime) about the set of supported character
 | |
|        * encodings.
 | |
|        */
 | |
|       throw new RuntimeException(ex.getMessage());
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Publishes a <code>LogRecord</code> to the associated output
 | |
|    * stream, provided the record passes all tests for being loggable.
 | |
|    * The <code>StreamHandler</code> will localize the message of the
 | |
|    * log record and substitute any message parameters.
 | |
|    *
 | |
|    * <p>Most applications do not need to call this method directly.
 | |
|    * Instead, they will use use a {@link Logger}, which will create
 | |
|    * LogRecords and distribute them to registered handlers.
 | |
|    *
 | |
|    * <p>In case of an I/O failure, the <code>ErrorManager</code>
 | |
|    * of this <code>Handler</code> will be informed, but the caller
 | |
|    * of this method will not receive an exception.
 | |
|    *
 | |
|    * <p>If a log record is being published to a
 | |
|    * <code>StreamHandler</code> that has been closed earlier, the Sun
 | |
|    * J2SE 1.4 reference can be observed to silently ignore the
 | |
|    * call. The GNU implementation, however, intentionally behaves
 | |
|    * differently by informing the <code>ErrorManager</code> associated
 | |
|    * with this <code>StreamHandler</code>.  Since the condition
 | |
|    * indicates a programming error, the programmer should be
 | |
|    * informed. It also seems extremely unlikely that any application
 | |
|    * would depend on the exact behavior in this rather obscure,
 | |
|    * erroneous case -- especially since the API specification does not
 | |
|    * prescribe what is supposed to happen.
 | |
|    *
 | |
|    * @param record the log event to be published.
 | |
|    */
 | |
|   public void publish(LogRecord record)
 | |
|   {
 | |
|     String formattedMessage;
 | |
| 
 | |
|     if (!isLoggable(record))
 | |
|       return;
 | |
| 
 | |
|     if (streamState == STATE_FRESH)
 | |
|     {
 | |
|       try
 | |
|       {
 | |
|         writer.write(formatter.getHead(this));
 | |
|       }
 | |
|       catch (java.io.IOException ex)
 | |
|       {
 | |
|         reportError(null, ex, ErrorManager.WRITE_FAILURE);
 | |
|         return;
 | |
|       }
 | |
|       catch (Exception ex)
 | |
|       {
 | |
|         reportError(null, ex, ErrorManager.GENERIC_FAILURE);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       streamState = STATE_PUBLISHED;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       formattedMessage = formatter.format(record);
 | |
|     }
 | |
|     catch (Exception ex)
 | |
|     {
 | |
|       reportError(null, ex, ErrorManager.FORMAT_FAILURE);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       writer.write(formattedMessage);
 | |
|     }
 | |
|     catch (Exception ex)
 | |
|     {
 | |
|       reportError(null, ex, ErrorManager.WRITE_FAILURE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Checks whether or not a <code>LogRecord</code> would be logged
 | |
|    * if it was passed to this <code>StreamHandler</code> for publication.
 | |
|    *
 | |
|    * <p>The <code>StreamHandler</code> implementation first checks
 | |
|    * whether a writer is present and the handler's level is greater
 | |
|    * than or equal to the severity level threshold.  In a second step,
 | |
|    * if a {@link Filter} has been installed, its {@link
 | |
|    * Filter#isLoggable(LogRecord) isLoggable} method is
 | |
|    * invoked. Subclasses of <code>StreamHandler</code> can override
 | |
|    * this method to impose their own constraints.
 | |
|    *
 | |
|    * @param record the <code>LogRecord</code> to be checked.
 | |
|    *
 | |
|    * @return <code>true</code> if <code>record</code> would
 | |
|    *         be published by {@link #publish(LogRecord) publish},
 | |
|    *         <code>false</code> if it would be discarded.
 | |
|    *
 | |
|    * @see #setLevel(Level)
 | |
|    * @see #setFilter(Filter)
 | |
|    * @see Filter#isLoggable(LogRecord)
 | |
|    *
 | |
|    * @throws NullPointerException if <code>record</code> is
 | |
|    *         <code>null</code>.  */
 | |
|   public boolean isLoggable(LogRecord record)
 | |
|   {
 | |
|     return (writer != null) && super.isLoggable(record);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Forces any data that may have been buffered to the underlying
 | |
|    * output device.
 | |
|    *
 | |
|    * <p>In case of an I/O failure, the <code>ErrorManager</code>
 | |
|    * of this <code>Handler</code> will be informed, but the caller
 | |
|    * of this method will not receive an exception.
 | |
|    *
 | |
|    * <p>If a <code>StreamHandler</code> that has been closed earlier
 | |
|    * is closed a second time, the Sun J2SE 1.4 reference can be
 | |
|    * observed to silently ignore the call. The GNU implementation,
 | |
|    * however, intentionally behaves differently by informing the
 | |
|    * <code>ErrorManager</code> associated with this
 | |
|    * <code>StreamHandler</code>.  Since the condition indicates a
 | |
|    * programming error, the programmer should be informed. It also
 | |
|    * seems extremely unlikely that any application would depend on the
 | |
|    * exact behavior in this rather obscure, erroneous case --
 | |
|    * especially since the API specification does not prescribe what is
 | |
|    * supposed to happen.
 | |
|    */
 | |
|   public void flush()
 | |
|   {
 | |
|     try
 | |
|     {
 | |
|       checkOpen();
 | |
|       if (writer != null)
 | |
|         writer.flush();
 | |
|     }
 | |
|     catch (Exception ex)
 | |
|     {
 | |
|       reportError(null, ex, ErrorManager.FLUSH_FAILURE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Closes this <code>StreamHandler</code> after having forced any
 | |
|    * data that may have been buffered to the underlying output
 | |
|    * device.
 | |
|    *
 | |
|    * <p>As soon as <code>close</code> has been called,
 | |
|    * a <code>Handler</code> should not be used anymore. Attempts
 | |
|    * to publish log records, to flush buffers, or to modify the
 | |
|    * <code>Handler</code> in any other way may throw runtime
 | |
|    * exceptions after calling <code>close</code>.</p>
 | |
|    *
 | |
|    * <p>In case of an I/O failure, the <code>ErrorManager</code>
 | |
|    * of this <code>Handler</code> will be informed, but the caller
 | |
|    * of this method will not receive an exception.</p>
 | |
|    *
 | |
|    * <p>If a <code>StreamHandler</code> that has been closed earlier
 | |
|    * is closed a second time, the Sun J2SE 1.4 reference can be
 | |
|    * observed to silently ignore the call. The GNU implementation,
 | |
|    * however, intentionally behaves differently by informing the
 | |
|    * <code>ErrorManager</code> associated with this
 | |
|    * <code>StreamHandler</code>.  Since the condition indicates a
 | |
|    * programming error, the programmer should be informed. It also
 | |
|    * seems extremely unlikely that any application would depend on the
 | |
|    * exact behavior in this rather obscure, erroneous case --
 | |
|    * especially since the API specification does not prescribe what is
 | |
|    * supposed to happen.
 | |
|    *
 | |
|    * @throws SecurityException if a security manager exists and
 | |
|    *         the caller is not granted the permission to control
 | |
|    *         the logging infrastructure.
 | |
|    */
 | |
|   public void close()
 | |
|     throws SecurityException
 | |
|   {
 | |
|     LogManager.getLogManager().checkAccess();
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       /* Although  flush also calls checkOpen, it catches
 | |
|        * any exceptions and reports them to the ErrorManager
 | |
|        * as flush failures.  However, we want to report
 | |
|        * a closed stream as a close failure, not as a
 | |
|        * flush failure here.  Therefore, we call checkOpen()
 | |
|        * before flush().
 | |
|        */
 | |
|       checkOpen();
 | |
|       flush();
 | |
| 
 | |
|       if (writer != null)
 | |
|       {
 | |
|         if (formatter != null)
 | |
|         {
 | |
|           /* Even if the StreamHandler has never published a record,
 | |
|            * it emits head and tail upon closing. An earlier version
 | |
|            * of the GNU Classpath implementation did not emitted
 | |
|            * anything. However, this had caused XML log files to be
 | |
|            * entirely empty instead of containing no log records.
 | |
|            */
 | |
|           if (streamState == STATE_FRESH)
 | |
|             writer.write(formatter.getHead(this));
 | |
|           if (streamState != STATE_CLOSED)
 | |
|             writer.write(formatter.getTail(this));
 | |
|         }
 | |
|         streamState = STATE_CLOSED;
 | |
|         writer.close();
 | |
|       }
 | |
|     }
 | |
|     catch (Exception ex)
 | |
|     {
 | |
|       reportError(null, ex, ErrorManager.CLOSE_FAILURE);
 | |
|     }
 | |
|   }
 | |
| }
 |