summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/util/logging/FileHandler.java
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/util/logging/FileHandler.java
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/util/logging/FileHandler.java')
-rw-r--r--libjava/classpath/java/util/logging/FileHandler.java665
1 files changed, 665 insertions, 0 deletions
diff --git a/libjava/classpath/java/util/logging/FileHandler.java b/libjava/classpath/java/util/logging/FileHandler.java
new file mode 100644
index 000000000..00d967f57
--- /dev/null
+++ b/libjava/classpath/java/util/logging/FileHandler.java
@@ -0,0 +1,665 @@
+/* FileHandler.java -- a class for publishing log messages to log files
+ Copyright (C) 2002, 2003, 2004, 2005 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 gnu.java.lang.CPStringBuilder;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * 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>user.home</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
+{
+ /**
+ * A literal that prefixes all file-handler related properties in the
+ * logging.properties file.
+ */
+ private static final String PROPERTY_PREFIX = "java.util.logging.FileHandler";
+ /**
+ * The name of the property to set for specifying a file naming (incl. path)
+ * pattern to use with rotating log files.
+ */
+ private static final String PATTERN_KEY = PROPERTY_PREFIX + ".pattern";
+ /**
+ * The default pattern to use when the <code>PATTERN_KEY</code> property was
+ * not specified in the logging.properties file.
+ */
+ private static final String DEFAULT_PATTERN = "%h/java%u.log";
+ /**
+ * The name of the property to set for specifying an approximate maximum
+ * amount, in bytes, to write to any one log output file. A value of zero
+ * (which is the default) implies a no limit.
+ */
+ private static final String LIMIT_KEY = PROPERTY_PREFIX + ".limit";
+ private static final int DEFAULT_LIMIT = 0;
+ /**
+ * The name of the property to set for specifying how many output files to
+ * cycle through. The default value is 1.
+ */
+ private static final String COUNT_KEY = PROPERTY_PREFIX + ".count";
+ private static final int DEFAULT_COUNT = 1;
+ /**
+ * The name of the property to set for specifying whether this handler should
+ * append, or not, its output to existing files. The default value is
+ * <code>false</code> meaning NOT to append.
+ */
+ private static final String APPEND_KEY = PROPERTY_PREFIX + ".append";
+ private static final boolean DEFAULT_APPEND = false;
+
+ /**
+ * 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;
+
+
+ /**
+ * The number of bytes that have currently been written to the stream.
+ * Package private for use in inner classes.
+ */
+ long written;
+
+
+ /**
+ * A linked list of files we are, or have written to. The entries
+ * are file path strings, kept in the order
+ */
+ private LinkedList logFiles;
+
+
+ /**
+ * 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(LogManager.getLogManager().getProperty(PATTERN_KEY),
+ LogManager.getIntProperty(LIMIT_KEY, DEFAULT_LIMIT),
+ LogManager.getIntProperty(COUNT_KEY, DEFAULT_COUNT),
+ LogManager.getBooleanProperty(APPEND_KEY, DEFAULT_APPEND));
+ }
+
+
+ /* FIXME: Javadoc missing. */
+ public FileHandler(String pattern)
+ throws IOException, SecurityException
+ {
+ this(pattern, DEFAULT_LIMIT, DEFAULT_COUNT, DEFAULT_APPEND);
+ }
+
+
+ /* FIXME: Javadoc missing. */
+ public FileHandler(String pattern, boolean append)
+ throws IOException, SecurityException
+ {
+ this(pattern, DEFAULT_LIMIT, DEFAULT_COUNT, append);
+ }
+
+
+ /* FIXME: Javadoc missing. */
+ public FileHandler(String pattern, int limit, int count)
+ throws IOException, SecurityException
+ {
+ this(pattern, limit, count,
+ LogManager.getBooleanProperty(APPEND_KEY, DEFAULT_APPEND));
+ }
+
+
+ /**
+ * 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(/* output stream, created below */ null,
+ PROPERTY_PREFIX,
+ /* default level */ Level.ALL,
+ /* formatter */ null,
+ /* default formatter */ XMLFormatter.class);
+
+ if ((limit <0) || (count < 1))
+ throw new IllegalArgumentException();
+
+ this.pattern = pattern != null ? pattern : DEFAULT_PATTERN;
+ this.limit = limit;
+ this.count = count;
+ this.append = append;
+ this.written = 0;
+ this.logFiles = new LinkedList ();
+
+ setOutputStream (createFileStream (this.pattern, limit, count, append,
+ /* generation */ 0));
+ }
+
+
+ /* FIXME: Javadoc missing. */
+ private 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(PATTERN_KEY);
+ if (pattern == null)
+ pattern = DEFAULT_PATTERN;
+
+ if (count > 1 && !has (pattern, 'g'))
+ pattern = pattern + ".%g";
+
+ do
+ {
+ path = replaceFileNameEscapes(pattern, generation, unique, count);
+
+ try
+ {
+ File file = new File(path);
+ if (!file.exists () || append)
+ {
+ FileOutputStream fout = new FileOutputStream (file, append);
+ // FIXME we need file locks for this to work properly, but they
+ // are not implemented yet in Classpath! Madness!
+// FileChannel channel = fout.getChannel ();
+// FileLock lock = channel.tryLock ();
+// if (lock != null) // We've locked the file.
+// {
+ if (logFiles.isEmpty ())
+ logFiles.addFirst (path);
+ return new ostr (fout);
+// }
+ }
+ }
+ catch (Exception ex)
+ {
+ reportError (null, ex, ErrorManager.OPEN_FAILURE);
+ }
+
+ unique = unique + 1;
+ if (!has (pattern, 'u'))
+ 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)
+ {
+ CPStringBuilder buf = new CPStringBuilder(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. */
+ public void publish(LogRecord record)
+ {
+ if (limit > 0 && written >= limit)
+ rotate ();
+ super.publish(record);
+ flush ();
+ }
+
+ /**
+ * Rotates the current log files, possibly removing one if we
+ * exceed the file count.
+ */
+ private synchronized void rotate ()
+ {
+ if (logFiles.size () > 0)
+ {
+ File f1 = null;
+ ListIterator lit = null;
+
+ // If we reach the file count, ditch the oldest file.
+ if (logFiles.size () == count)
+ {
+ f1 = new File ((String) logFiles.getLast ());
+ f1.delete ();
+ lit = logFiles.listIterator (logFiles.size () - 1);
+ }
+ // Otherwise, move the oldest to a new location.
+ else
+ {
+ String path = replaceFileNameEscapes (pattern, logFiles.size (),
+ /* unique */ 0, count);
+ f1 = new File (path);
+ logFiles.addLast (path);
+ lit = logFiles.listIterator (logFiles.size () - 1);
+ }
+
+ // Now rotate the files.
+ while (lit.hasPrevious ())
+ {
+ String s = (String) lit.previous ();
+ File f2 = new File (s);
+ f2.renameTo (f1);
+ f1 = f2;
+ }
+ }
+
+ setOutputStream (createFileStream (pattern, limit, count, append,
+ /* generation */ 0));
+
+ // Reset written count.
+ written = 0;
+ }
+
+ /**
+ * Tell if <code>pattern</code> contains the pattern sequence
+ * with character <code>escape</code>. That is, if <code>escape</code>
+ * is 'g', this method returns true if the given pattern contains
+ * "%g", and not just the substring "%g" (for example, in the case of
+ * "%%g").
+ *
+ * @param pattern The pattern to test.
+ * @param escape The escape character to search for.
+ * @return True iff the pattern contains the escape sequence with the
+ * given character.
+ */
+ private static boolean has (final String pattern, final char escape)
+ {
+ final int len = pattern.length ();
+ boolean sawPercent = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = pattern.charAt (i);
+ if (sawPercent)
+ {
+ if (c == escape)
+ return true;
+ if (c == '%') // Double percent
+ {
+ sawPercent = false;
+ continue;
+ }
+ }
+ sawPercent = (c == '%');
+ }
+ return false;
+ }
+
+ /**
+ * An output stream that tracks the number of bytes written to it.
+ */
+ private final class ostr extends FilterOutputStream
+ {
+ private ostr (OutputStream out)
+ {
+ super (out);
+ }
+
+ public void write (final int b) throws IOException
+ {
+ out.write (b);
+ FileHandler.this.written++; // FIXME: synchronize?
+ }
+
+ public void write (final byte[] b) throws IOException
+ {
+ write (b, 0, b.length);
+ }
+
+ public void write (final byte[] b, final int offset, final int length)
+ throws IOException
+ {
+ out.write (b, offset, length);
+ FileHandler.this.written += length; // FIXME: synchronize?
+ }
+ }
+}