mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			507 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			507 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* FileHandler.java -- a class for publishing log messages to log files
 | |
|    Copyright (C) 2002, 2003, 2004 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.File;
 | |
| import java.io.FileOutputStream;
 | |
| import java.io.IOException;
 | |
| 
 | |
| /**
 | |
|  * A <code>FileHandler</code> publishes log records to a set of log
 | |
|  * files.  A maximum file size can be specified; as soon as a log file
 | |
|  * reaches the size limit, it is closed and the next file in the set
 | |
|  * is taken.
 | |
|  *
 | |
|  * <p><strong>Configuration:</strong> Values of the subsequent
 | |
|  * <code>LogManager</code> properties are taken into consideration
 | |
|  * when a <code>FileHandler</code> is initialized.  If a property is
 | |
|  * not defined, or if it has an invalid value, a default is taken
 | |
|  * without an exception being thrown.
 | |
|  *
 | |
|  * <ul>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.level</code> - specifies
 | |
|  *     the initial severity level threshold. Default value:
 | |
|  *     <code>Level.ALL</code>.</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.filter</code> - specifies
 | |
|  *     the name of a Filter class. Default value: No Filter.</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.formatter</code> - specifies
 | |
|  *     the name of a Formatter class. Default value:
 | |
|  *     <code>java.util.logging.XMLFormatter</code>.</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.encoding</code> - specifies
 | |
|  *     the name of the character encoding. Default value:
 | |
|  *     the default platform encoding.</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.limit</code> - specifies the number
 | |
|  *     of bytes a log file is approximately allowed to reach before it
 | |
|  *     is closed and the handler switches to the next file in the
 | |
|  *     rotating set.  A value of zero means that files can grow
 | |
|  *     without limit.  Default value: 0 (unlimited growth).</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.count</code> - specifies the number
 | |
|  *     of log files through which this handler cycles.  Default value:
 | |
|  *     1.</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.pattern</code> - specifies a
 | |
|  *     pattern for the location and name of the produced log files.
 | |
|  *     See the section on <a href="#filePatterns">file name
 | |
|  *     patterns</a> for details.  Default value:
 | |
|  *     <code>"%h/java%u.log"</code>.</li>
 | |
|  *
 | |
|  * <li><code>java.util.FileHandler.append</code> - specifies
 | |
|  *     whether the handler will append log records to existing
 | |
|  *     files, or whether the handler will clear log files
 | |
|  *     upon switching to them. Default value: <code>false</code>,
 | |
|  *     indicating that files will be cleared.</li>
 | |
|  *
 | |
|  * </ul>
 | |
|  *
 | |
|  * <p><a name="filePatterns"><strong>File Name Patterns:</strong></a>
 | |
|  * The name and location and log files are specified with pattern
 | |
|  * strings. The handler will replace the following character sequences
 | |
|  * when opening log files:
 | |
|  *
 | |
|  * <p><ul>
 | |
|  * <li><code>/</code> - replaced by the platform-specific path name
 | |
|  *     separator.  This value is taken from the system property
 | |
|  *     <code>file.separator</code>.</li>
 | |
|  *
 | |
|  * <li><code>%t</code> - replaced by the platform-specific location of
 | |
|  *     the directory intended for temporary files.  This value is
 | |
|  *     taken from the system property <code>java.io.tmpdir</code>.</li>
 | |
|  *
 | |
|  * <li><code>%h</code> - replaced by the location of the home
 | |
|  *     directory of the current user.  This value is taken from the
 | |
|  *     system property <code>file.separator</code>.</li>
 | |
|  *
 | |
|  * <li><code>%g</code> - replaced by a generation number for
 | |
|  *     distinguisthing the individual items in the rotating set 
 | |
|  *     of log files.  The generation number cycles through the
 | |
|  *     sequence 0, 1, ..., <code>count</code> - 1.</li>
 | |
|  *
 | |
|  * <li><code>%u</code> - replaced by a unique number for
 | |
|  *     distinguisthing the output files of several concurrently
 | |
|  *     running processes.  The <code>FileHandler</code> starts
 | |
|  *     with 0 when it tries to open a log file.  If the file
 | |
|  *     cannot be opened because it is currently in use,
 | |
|  *     the unique number is incremented by one and opening
 | |
|  *     is tried again.  These steps are repeated until the
 | |
|  *     opening operation succeeds.
 | |
|  *
 | |
|  *     <p>FIXME: Is the following correct? Please review.  The unique
 | |
|  *     number is determined for each log file individually when it is
 | |
|  *     opened upon switching to the next file.  Therefore, it is not
 | |
|  *     correct to assume that all log files in a rotating set bear the
 | |
|  *     same unique number.
 | |
|  *
 | |
|  *     <p>FIXME: The Javadoc for the Sun reference implementation
 | |
|  *     says: "Note that the use of unique ids to avoid conflicts is
 | |
|  *     only guaranteed to work reliably when using a local disk file
 | |
|  *     system." Why? This needs to be mentioned as well, in case
 | |
|  *     the reviewers decide the statement is true.  Otherwise,
 | |
|  *     file a bug report with Sun.</li>
 | |
|  *
 | |
|  * <li><code>%%</code> - replaced by a single percent sign.</li>
 | |
|  * </ul>
 | |
|  *
 | |
|  * <p>If the pattern string does not contain <code>%g</code> and
 | |
|  * <code>count</code> is greater than one, the handler will append
 | |
|  * the string <code>.%g</code> to the specified pattern.
 | |
|  *
 | |
|  * <p>If the handler attempts to open a log file, this log file
 | |
|  * is being used at the time of the attempt, and the pattern string
 | |
|  * does not contain <code>%u</code>, the handler will append
 | |
|  * the string <code>.%u</code> to the specified pattern. This
 | |
|  * step is performed after any generation number has been
 | |
|  * appended.
 | |
|  *
 | |
|  * <p><em>Examples for the GNU platform:</em> 
 | |
|  *
 | |
|  * <p><ul>
 | |
|  *
 | |
|  * <li><code>%h/java%u.log</code> will lead to a single log file
 | |
|  *     <code>/home/janet/java0.log</code>, assuming <code>count</code>
 | |
|  *     equals 1, the user's home directory is
 | |
|  *     <code>/home/janet</code>, and the attempt to open the file
 | |
|  *     succeeds.</li>
 | |
|  *
 | |
|  * <li><code>%h/java%u.log</code> will lead to three log files
 | |
|  *     <code>/home/janet/java0.log.0</code>,
 | |
|  *     <code>/home/janet/java0.log.1</code>, and
 | |
|  *     <code>/home/janet/java0.log.2</code>,
 | |
|  *     assuming <code>count</code> equals 3, the user's home
 | |
|  *     directory is <code>/home/janet</code>, and all attempts
 | |
|  *     to open files succeed.</li>
 | |
|  *
 | |
|  * <li><code>%h/java%u.log</code> will lead to three log files
 | |
|  *     <code>/home/janet/java0.log.0</code>,
 | |
|  *     <code>/home/janet/java1.log.1</code>, and
 | |
|  *     <code>/home/janet/java0.log.2</code>,
 | |
|  *     assuming <code>count</code> equals 3, the user's home
 | |
|  *     directory is <code>/home/janet</code>, and the attempt
 | |
|  *     to open <code>/home/janet/java0.log.1</code> fails.</li>
 | |
|  *
 | |
|  * </ul>
 | |
|  *
 | |
|  * @author Sascha Brawer (brawer@acm.org)
 | |
|  */
 | |
| public class FileHandler
 | |
|   extends StreamHandler
 | |
| {
 | |
|   /**
 | |
|    * The number of bytes a log file is approximately allowed to reach
 | |
|    * before it is closed and the handler switches to the next file in
 | |
|    * the rotating set.  A value of zero means that files can grow
 | |
|    * without limit.
 | |
|    */
 | |
|   private final int limit;
 | |
| 
 | |
| 
 | |
|  /**
 | |
|   * The number of log files through which this handler cycles.
 | |
|   */
 | |
|   private final int count;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * The pattern for the location and name of the produced log files.
 | |
|    * See the section on <a href="#filePatterns">file name patterns</a>
 | |
|    * for details.
 | |
|    */
 | |
|   private final String pattern;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Indicates whether the handler will append log records to existing
 | |
|    * files (<code>true</code>), or whether the handler will clear log files
 | |
|    * upon switching to them (<code>false</code>).
 | |
|    */
 | |
|   private final boolean append;
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Constructs a <code>FileHandler</code>, taking all property values
 | |
|    * from the current {@link LogManager LogManager} configuration.
 | |
|    *
 | |
|    * @throws java.io.IOException FIXME: The Sun Javadoc says: "if
 | |
|    *         there are IO problems opening the files."  This conflicts
 | |
|    *         with the general principle that configuration errors do
 | |
|    *         not prohibit construction. Needs review.
 | |
|    *
 | |
|    * @throws SecurityException if a security manager exists and
 | |
|    *         the caller is not granted the permission to control
 | |
|    *         the logging infrastructure.
 | |
|    */
 | |
|   public FileHandler()
 | |
|     throws IOException, SecurityException
 | |
|   {
 | |
|     this(/* pattern: use configiguration */ null,
 | |
| 
 | |
| 	 LogManager.getIntProperty("java.util.logging.FileHandler.limit",
 | |
| 				   /* default */ 0),
 | |
| 
 | |
| 	 LogManager.getIntProperty("java.util.logging.FileHandler.count",
 | |
| 				   /* default */ 1),
 | |
| 
 | |
| 	 LogManager.getBooleanProperty("java.util.logging.FileHandler.append",
 | |
| 				       /* default */ false));
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /* FIXME: Javadoc missing. */
 | |
|   public FileHandler(String pattern)
 | |
|     throws IOException, SecurityException
 | |
|   {
 | |
|     this(pattern,
 | |
| 	 /* limit */ 0,
 | |
| 	 /* count */ 1,
 | |
| 	 /* append */ false);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /* FIXME: Javadoc missing. */
 | |
|   public FileHandler(String pattern, boolean append)
 | |
|     throws IOException, SecurityException
 | |
|   {
 | |
|     this(pattern,
 | |
| 	 /* limit */ 0,
 | |
| 	 /* count */ 1,
 | |
| 	 append);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /* FIXME: Javadoc missing. */
 | |
|   public FileHandler(String pattern, int limit, int count)
 | |
|     throws IOException, SecurityException
 | |
|   {
 | |
|     this(pattern, limit, count, 
 | |
| 	 LogManager.getBooleanProperty(
 | |
| 	   "java.util.logging.FileHandler.append",
 | |
| 	   /* default */ false));
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Constructs a <code>FileHandler</code> given the pattern for the
 | |
|    * location and name of the produced log files, the size limit, the
 | |
|    * number of log files thorough which the handler will rotate, and
 | |
|    * the <code>append</code> property.  All other property values are
 | |
|    * taken from the current {@link LogManager LogManager}
 | |
|    * configuration.
 | |
|    *
 | |
|    * @param pattern The pattern for the location and name of the
 | |
|    *        produced log files.  See the section on <a
 | |
|    *        href="#filePatterns">file name patterns</a> for details.
 | |
|    *        If <code>pattern</code> is <code>null</code>, the value is
 | |
|    *        taken from the {@link LogManager LogManager} configuration
 | |
|    *        property
 | |
|    *        <code>java.util.logging.FileHandler.pattern</code>.
 | |
|    *        However, this is a pecularity of the GNU implementation,
 | |
|    *        and Sun's API specification does not mention what behavior
 | |
|    *        is to be expected for <code>null</code>. Therefore,
 | |
|    *        applications should not rely on this feature.
 | |
|    *
 | |
|    * @param limit specifies the number of bytes a log file is
 | |
|    *        approximately allowed to reach before it is closed and the
 | |
|    *        handler switches to the next file in the rotating set.  A
 | |
|    *        value of zero means that files can grow without limit.
 | |
|    *
 | |
|    * @param count specifies the number of log files through which this
 | |
|    *        handler cycles.
 | |
|    *
 | |
|    * @param append specifies whether the handler will append log
 | |
|    *        records to existing files (<code>true</code>), or whether the
 | |
|    *        handler will clear log files upon switching to them
 | |
|    *        (<code>false</code>).
 | |
|    *
 | |
|    * @throws java.io.IOException FIXME: The Sun Javadoc says: "if
 | |
|    *         there are IO problems opening the files."  This conflicts
 | |
|    *         with the general principle that configuration errors do
 | |
|    *         not prohibit construction. Needs review.
 | |
|    *
 | |
|    * @throws SecurityException if a security manager exists and
 | |
|    *         the caller is not granted the permission to control
 | |
|    *         the logging infrastructure.
 | |
|    *         <p>FIXME: This seems in contrast to all other handler
 | |
|    *         constructors -- verify this by running tests against
 | |
|    *         the Sun reference implementation.
 | |
|    */
 | |
|   public FileHandler(String pattern,
 | |
| 		     int limit,
 | |
| 		     int count,
 | |
| 		     boolean append)
 | |
|     throws IOException, SecurityException
 | |
|   {
 | |
|     super(createFileStream(pattern, limit, count, append,
 | |
| 			   /* generation */ 0),
 | |
| 	  "java.util.logging.FileHandler",
 | |
| 	  /* default level */ Level.ALL,
 | |
| 	  /* formatter */ null,
 | |
| 	  /* default formatter */ XMLFormatter.class);
 | |
| 
 | |
|     if ((limit <0) || (count < 1))
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     this.pattern = pattern;
 | |
|     this.limit = limit;
 | |
|     this.count = count;
 | |
|     this.append = append;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /* FIXME: Javadoc missing. */
 | |
|   private static java.io.OutputStream createFileStream(String pattern,
 | |
| 						       int limit,
 | |
| 						       int count,
 | |
| 						       boolean append,
 | |
| 						       int generation)
 | |
|   {
 | |
|     String  path;
 | |
|     int     unique = 0;
 | |
| 
 | |
|     /* Throws a SecurityException if the caller does not have
 | |
|      * LoggingPermission("control").
 | |
|      */
 | |
|     LogManager.getLogManager().checkAccess();
 | |
| 
 | |
|     /* Default value from the java.util.logging.FileHandler.pattern
 | |
|      * LogManager configuration property.
 | |
|      */
 | |
|     if (pattern == null)
 | |
|       pattern = LogManager.getLogManager().getProperty(
 | |
|                               "java.util.logging.FileHandler.pattern");
 | |
|     if (pattern == null)
 | |
|       pattern = "%h/java%u.log";
 | |
| 
 | |
|     do
 | |
|     {
 | |
|       path = replaceFileNameEscapes(pattern, generation, unique, count);
 | |
| 
 | |
|       try
 | |
|       {
 | |
| 	File file = new File(path);
 | |
| 	if (file.createNewFile())
 | |
| 	  return new FileOutputStream(path, append);
 | |
|       }
 | |
|       catch (Exception ex)
 | |
|       {
 | |
| 	ex.printStackTrace();	
 | |
|       }
 | |
| 
 | |
|       unique = unique + 1;
 | |
|       if (pattern.indexOf("%u") < 0)
 | |
|         pattern = pattern + ".%u";
 | |
|     }
 | |
|     while (true);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Replaces the substrings <code>"/"</code> by the value of the
 | |
|    * system property <code>"file.separator"</code>, <code>"%t"</code>
 | |
|    * by the value of the system property
 | |
|    * <code>"java.io.tmpdir"</code>, <code>"%h"</code> by the value of
 | |
|    * the system property <code>"user.home"</code>, <code>"%g"</code>
 | |
|    * by the value of <code>generation</code>, <code>"%u"</code> by the
 | |
|    * value of <code>uniqueNumber</code>, and <code>"%%"</code> by a
 | |
|    * single percent character.  If <code>pattern<code> does
 | |
|    * <em>not</em> contain the sequence <code>"%g"</code>,
 | |
|    * the value of <code>generation</code> will be appended to
 | |
|    * the result.
 | |
|    *
 | |
|    * @throws NullPointerException if one of the system properties
 | |
|    *         <code>"file.separator"</code>,
 | |
|    *         <code>"java.io.tmpdir"</code>, or
 | |
|    *         <code>"user.home"</code> has no value and the
 | |
|    *         corresponding escape sequence appears in
 | |
|    *         <code>pattern</code>.
 | |
|    */
 | |
|   private static String replaceFileNameEscapes(String pattern,
 | |
| 					       int generation,
 | |
| 					       int uniqueNumber,
 | |
| 					       int count)
 | |
|   {
 | |
|     StringBuffer buf = new StringBuffer(pattern);
 | |
|     String       replaceWith;
 | |
|     boolean      foundGeneration = false;
 | |
| 
 | |
|     int pos = 0;
 | |
|     do
 | |
|     {
 | |
|       // Uncomment the next line for finding bugs.
 | |
|       // System.out.println(buf.substring(0,pos) + '|' + buf.substring(pos));
 | |
|       
 | |
|       if (buf.charAt(pos) == '/')
 | |
|       {
 | |
| 	/* The same value is also provided by java.io.File.separator. */
 | |
| 	replaceWith = System.getProperty("file.separator");
 | |
| 	buf.replace(pos, pos + 1, replaceWith);
 | |
| 	pos = pos + replaceWith.length() - 1;
 | |
| 	continue;
 | |
|       }
 | |
| 
 | |
|       if (buf.charAt(pos) == '%')
 | |
|       {
 | |
|         switch (buf.charAt(pos + 1))
 | |
| 	{
 | |
| 	case 't':
 | |
| 	  replaceWith = System.getProperty("java.io.tmpdir");
 | |
| 	  break;
 | |
| 
 | |
| 	case 'h':
 | |
| 	  replaceWith = System.getProperty("user.home");
 | |
| 	  break;
 | |
| 
 | |
| 	case 'g':
 | |
| 	  replaceWith = Integer.toString(generation);
 | |
| 	  foundGeneration = true;
 | |
| 	  break;
 | |
| 
 | |
| 	case 'u':
 | |
| 	  replaceWith = Integer.toString(uniqueNumber);
 | |
| 	  break;
 | |
| 
 | |
| 	case '%':
 | |
| 	  replaceWith = "%";
 | |
| 	  break;
 | |
| 
 | |
| 	default:
 | |
| 	  replaceWith = "??";
 | |
| 	  break; // FIXME: Throw exception?
 | |
| 	}
 | |
| 
 | |
| 	buf.replace(pos, pos + 2, replaceWith);
 | |
| 	pos = pos + replaceWith.length() - 1;
 | |
| 	continue;
 | |
|       }
 | |
|     }
 | |
|     while (++pos < buf.length() - 1);
 | |
| 
 | |
|     if (!foundGeneration && (count > 1))
 | |
|     {
 | |
|       buf.append('.');
 | |
|       buf.append(generation);
 | |
|     }
 | |
| 
 | |
|     return buf.toString();
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /* FIXME: Javadoc missing, implementation incomplete. */
 | |
|   public void publish(LogRecord record)
 | |
|   {
 | |
|     super.publish(record);
 | |
| 
 | |
|     /* FIXME: Decide when to switch over. How do we get to
 | |
|      * the number of bytes published so far? Two possibilities:
 | |
|      * 1. File.length, 2. have metering wrapper around
 | |
|      * output stream counting the number of written bytes.
 | |
|      */
 | |
|   
 | |
|     /* FIXME: Switch over if needed! This implementation always
 | |
|      * writes into a single file, i.e. behaves as if limit
 | |
|      * always was zero. So, the implementation is somewhat
 | |
|      * functional but incomplete.
 | |
|      */
 | |
|   }
 | |
| }
 |