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., 59 Temple Place, Suite 330, Boston, MA
 | 
						|
02111-1307 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);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |