Return-Path:
+ * This handler reads the following properties from the log manager to
+ * initialize itself:
+ * System.err
.
+ *
+ *
+ * Level.INFO
if this property is not found or has an
+ * invalid value;
+ * null
if
+ * this property is not found or has an invalid value;
+ * java.util.logging.SimpleFormatter
if this property is not
+ * found or has an invalid value;
+ * null
if
+ * this property is not found or has an invalid value.
+ *
+ * This class is not thread-safe. + *
+ * + */ +public class ConsoleHandler extends StreamHandler { + + /* + * ------------------------------------------------------------------- + * Constructors + * ------------------------------------------------------------------- + */ + + /** + * Constructs aConsoleHandler
object.
+ */
+ public ConsoleHandler() {
+ super(System.err);
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Closes this handler. The System.err
is flushed but not
+ * closed.
+ */
+ public void close() {
+ super.close(false);
+ }
+
+ /**
+ * Logs a record if necessary. A flush operation will be done.
+ *
+ * @param record
+ * the log record to be logged
+ */
+ public void publish(LogRecord record) {
+ super.publish(record);
+ super.flush();
+
+ }
+
+}
+
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/ErrorManager.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/ErrorManager.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/ErrorManager.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/ErrorManager.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,147 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+/**
+ * Handler
objects can report errors to the
+ * ErrorManager
instance attached to them when they encounter any
+ * exceptions or errors.
+ *
+ * Callers of a logger are unlikely to be interested in the exceptions occured
+ * during logging. Use an ErrorManager
object to report these
+ * exceptions.
+ *
ErrorManager
.
+ */
+ public ErrorManager() {
+ lock = new Object();
+ firstCall = true;
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Reports an error.
+ *
+ * This method can be called by a Handler
object when it
+ * encounters an exception or error. The first call to this method will do
+ * the exact error-reporting as desired. Subsequent calls are ignored.
+ *
+ * @param msg
+ * the error message which may be null
+ * @param ex
+ * the exception which may be null
+ * @param errorCode
+ * the error code indicating the type of the failure
+ */
+ public void error(String msg, Exception ex, int errorCode) {
+ if (firstCall) {
+ // Synchronize concurrent "first" calls
+ synchronized (lock) {
+ if (firstCall) {
+ outputError(msg, ex, errorCode);
+ }
+ }
+ }
+ }
+
+ //if it is the first time to call error, output it
+ private void outputError(String msg, Exception ex, int errorCode) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(this.getClass().getName());
+ sb.append(": the error code is "); //$NON-NLS-1$
+ sb.append(errorCode);
+ sb.append("."); //$NON-NLS-1$
+ sb.append(LogManager.getSystemLineSeparator());
+ if (null != msg) {
+ sb.append("The error message is: "); //$NON-NLS-1$
+ sb.append(msg);
+ sb.append(LogManager.getSystemLineSeparator());
+ }
+ if (null != ex) {
+ sb.append(ex.toString());
+ }
+ System.err.println(sb);
+ firstCall = false;
+ }
+
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/FileHandler.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/FileHandler.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/FileHandler.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/FileHandler.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,605 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Hashtable;
+
+/**
+ * A Handler
writes description of logging event into a specified
+ * file or a rotating set of files.
+ *
+ * If a set of files are used, when a given amount of data has been written to + * one file, this file is closed, and another file is opened. The name of these + * files are generated by given name pattern, see below for details. + *
+ *+ * By default the IO buffering mechanism is enabled, but when each log record is + * complete, it is flushed out. + *
+ *
+ * XMLFormatter
is default formatter for FileHandler
.
+ *
+ * MemoryHandler
will read following LogManager
+ * properties for initialization, if given propeties are not defined or has
+ * invalid values, default value will be used.
+ *
Handler
, defaults to Level.ALL
.Filter
+ * class name, defaults to no Filter
.Formatter
class, defaults to
+ * java.util.logging.XMLFormatter
.FileHandler
should append onto existing files, defaults to
+ * false.+ * Name pattern is a string that may includes some special sub-strings, which + * will be replaced to generate output files: + *
+ * The "%u" unique field is used to avoid conflicts and set to 0 at first. If
+ * one FileHandler
tries to open the filename which is currently
+ * in use by another process, it will repeatly increment the unique number field
+ * and try again. If the "%u" component has not been included in the file name
+ * pattern and some contention on a file does occur then a unique numerical
+ * value will be added to the end of the filename in question immediately to the
+ * right of a dot. The unique ids to avoid conflicts is only guaranteed to work
+ * reliably when using a local disk file system.
+ *
FileHandler
using LogManager
+ * properties or their default value
+ *
+ * @throws IOException
+ * if any IO exception happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to control this handler,
+ * required permissions include LogPermission("control")
+ * and other permission like FilePermission("write")
,
+ * etc.
+ *
+ */
+ public FileHandler() throws IOException {
+ init(null, null, null, null);
+ }
+
+ //init properties
+ private void init(String p, Boolean a, Integer l, Integer c)
+ throws IOException {
+ //check access
+ manager = LogManager.getLogManager();
+ manager.checkAccess();
+ initProperties(p, a, l, c);
+ initOutputFiles();
+ }
+
+ private void initOutputFiles() throws FileNotFoundException, IOException {
+ int uniqueID = -1;
+ FileOutputStream fileStream = null;
+ FileChannel channel = null;
+ while (true) {
+ //try to find a unique file which is not locked by other process
+ fileName = parseFileName(generation, ++uniqueID);
+ synchronized (allLocks) {
+ //if current process has held lock for this fileName
+ //continue to find next file
+ if (null != allLocks.get(fileName)) {
+ continue;
+ }
+ try {
+ fileStream = new FileOutputStream(fileName, true);
+ channel = fileStream.getChannel();
+ } catch(FileNotFoundException e){
+ //invalid path name, throw exception
+ throw e;
+ }
+ //if lock is unsupported and IOException throwed, just let the
+ //IOException throws out and exit
+ //otherwise it will go into an undead cycle
+ lock = channel.tryLock();
+ if (null == lock) {
+ continue;
+ }
+ files[0] = new File(fileName);
+ allLocks.put(fileName, lock);
+ break;
+ }
+ }
+ for (generation = 1; generation < count; generation++) {
+ //cache all file names for rotation use
+ files[generation] = new File(parseFileName(generation, uniqueID));
+ }
+ output = new MeasureOutputStream(new BufferedOutputStream(fileStream),
+ files[0].length());
+ if (append && output.getLength() < limit) {
+ setOutputStream(output);
+ } else {
+ setOutputStream(output);
+ findNextGeneration();
+ }
+ }
+
+ private void initProperties(String p, Boolean a, Integer l, Integer c) {
+ super.initProperties("ALL", null, "java.util.logging.XMLFormatter", //$NON-NLS-1$//$NON-NLS-2$
+ null);
+ String className = this.getClass().getName();
+ pattern = (null == p) ? getStringProperty(className + ".pattern", //$NON-NLS-1$
+ DEFAULT_PATTERN) : p;
+ if (null == pattern || "".equals(pattern)) { //$NON-NLS-1$
+ throw new NullPointerException("Pattern cannot be empty"); //$NON-NLS-1$
+ }
+ append = (null == a) ? getBooleanProperty(className + ".append", //$NON-NLS-1$
+ DEFAULT_APPEND) : a.booleanValue();
+ count = (null == c) ? getIntProperty(className + ".count", //$NON-NLS-1$
+ DEFAULT_COUNT) : c.intValue();
+ limit = (null == l) ? getIntProperty(className + ".limit", //$NON-NLS-1$
+ DEFAULT_LIMIT) : l.intValue();
+ count = count < 1 ? DEFAULT_COUNT : count;
+ limit = limit < 0 ? DEFAULT_LIMIT : limit;
+ files = new File[count];
+ }
+
+ private void findNextGeneration() {
+ super.close();
+ for (int i = count - 1; i > 0; i--) {
+ if (files[i].exists()) {
+ files[i].delete();
+ }
+ files[i - 1].renameTo(files[i]);
+ }
+ try {
+ output = new MeasureOutputStream(new BufferedOutputStream(
+ new FileOutputStream(files[0])));
+ } catch (FileNotFoundException e1) {
+ this.getErrorManager().error("Error happened when open log file.", //$NON-NLS-1$
+ e1, ErrorManager.OPEN_FAILURE);
+ }
+ setOutputStream(output);
+
+ }
+
+ //apply settings, parse pattern and open files
+ private String parseFileName(int gen, int uniqueID) {
+ int cur = 0;
+ int next = 0;
+ boolean hasUniqueID = false;
+ boolean hasGeneration = false;
+ //TODO privilege code?
+ String tempPath = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
+ String homePath = System.getProperty("user.home"); //$NON-NLS-1$
+ StringBuffer sb = new StringBuffer();
+ pattern = pattern.replace('/', File.separatorChar);
+ char[] value = pattern.toCharArray();
+ while ((next = pattern.indexOf('%', cur)) >= 0) {
+ if (++next < pattern.length()) {
+ switch (value[next]) {
+ case 'g':
+ sb.append(value, cur, next - cur - 1).append(gen);
+ hasGeneration = true;
+ break;
+ case 'u':
+ sb.append(value, cur, next - cur - 1).append(uniqueID);
+ hasUniqueID = true;
+ break;
+ case 't':
+ sb.append(value, cur, next - cur - 1).append(tempPath);
+ break;
+ case 'h':
+ sb.append(value, cur, next - cur - 1).append(homePath);
+ break;
+ case '%':
+ sb.append(value, cur, next - cur - 1).append('%');
+ break;
+ default:
+ sb.append(value, cur, next - cur);
+ }
+ cur = ++next;
+ } else {
+
+ }
+ }
+ sb.append(value, cur, value.length - cur);
+ if (!hasGeneration && count > 1) {
+ sb.append(".").append(gen); //$NON-NLS-1$
+ }
+ if (!hasUniqueID && uniqueID > 0) {
+ sb.append(".").append(uniqueID); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+
+ //get boolean LogManager property, if invalid value got, using default value
+ private boolean getBooleanProperty(String key, boolean defaultValue) {
+ String property = manager.getProperty(key);
+ if (null == property) {
+ return defaultValue;
+ }
+ boolean result = defaultValue;
+ if ("true".equalsIgnoreCase(property)) { //$NON-NLS-1$
+ result = true;
+ } else if ("false".equalsIgnoreCase(property)) { //$NON-NLS-1$
+ result = false;
+ }
+ return result;
+ }
+
+ //get String LogManager property, if invalid value got, using default value
+ private String getStringProperty(String key, String defaultValue) {
+ String property = manager.getProperty(key);
+ return property == null ? defaultValue : property;
+ }
+
+ //get int LogManager property, if invalid value got, using default value
+ private int getIntProperty(String key, int defaultValue) {
+ String property = manager.getProperty(key);
+ int result = defaultValue;
+ if (null != property) {
+ try {
+ result = Integer.parseInt(property);
+ } catch (Exception e) {//ignore
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Construct a FileHandler
, the given name pattern is used as
+ * output filename, the file limit is set to zero(no limit), and the file
+ * count is set to one, other configuration using LogManager
+ * properties or their default value
+ *
+ * This handler write to only one file and no amount limit.
+ *
+ * @param pattern
+ * the name pattern of output file
+ * @throws IOException
+ * if any IO exception happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to control this handler,
+ * required permissions include LogPermission("control")
+ * and other permission like FilePermission("write")
,
+ * etc.
+ *
+ */
+ public FileHandler(String pattern) throws IOException {
+ if(null == pattern || "".equals(pattern)){ //$NON-NLS-1$
+ throw new NullPointerException("Pattern cannot be empty"); //$NON-NLS-1$
+ }
+ init(pattern, null, new Integer(DEFAULT_LIMIT), new Integer(
+ DEFAULT_COUNT));
+ }
+
+ /**
+ * Construct a FileHandler
, the given name pattern is used
+ * as output filename, the file limit is set to zero(i.e. no limit applies),
+ * the file count is initialized to one, and the value of
+ * append
becomes the new instance's append mode. Other
+ * configuration is done using LogManager
properties.
+ *
+ * This handler write to only one file and no amount limit.
+ *
+ * @param pattern
+ * the name pattern of output file
+ * @param append
+ * the append mode
+ * @throws IOException
+ * if any IO exception happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller does
+ * not have the required permissions to control this handler,
+ * required permissions include
+ * LogPermission("control")
and other permission
+ * like FilePermission("write")
, etc.
+ *
+ */
+ public FileHandler(String pattern, boolean append) throws IOException {
+ if(null == pattern || "".equals(pattern)){ //$NON-NLS-1$
+ throw new NullPointerException("Pattern cannot be empty"); //$NON-NLS-1$
+ }
+ init(pattern, Boolean.valueOf(append), new Integer(DEFAULT_LIMIT),
+ new Integer(DEFAULT_COUNT));
+ }
+
+ /**
+ * Construct a FileHandler
, the given name pattern is used as
+ * output filename, the file limit is set to given limit argument, and
+ * the file count is set to given count argument, other configuration using
+ * LogManager
properties or their default value
+ *
+ * This handler is configured to write to a rotating set of count files,
+ * when the limit of bytes has been written to one output file, another file
+ * will be opened instead.
+ *
+ * @param pattern
+ * the name pattern of output file
+ * @param limit
+ * the data amount limit in bytes of one ouput file, cannot less
+ * than one
+ * @param count
+ * the maximum number of files can be used, cannot less than one
+ * @throws IOException
+ * if any IO exception happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to control this handler,
+ * required permissions include LogPermission("control")
+ * and other permission like FilePermission("write")
,
+ * etc.
+ * @throws IllegalArgumentException
+ * if count<1, or limit<0
+ */
+ public FileHandler(String pattern, int limit, int count) throws IOException {
+ if(null == pattern || "".equals(pattern)){ //$NON-NLS-1$
+ throw new NullPointerException("Pattern cannot be empty"); //$NON-NLS-1$
+ }
+ if (limit < 1 || count < 0) {
+ throw new IllegalArgumentException(
+ "The limit and count property must larger than 0 and 1, respctively"); //$NON-NLS-1$
+ }
+ init(pattern, null, new Integer(limit), new Integer(count));
+ }
+
+ /**
+ * Construct a FileHandler
, the given name pattern is used as
+ * output filename, the file limit is set to given limit argument, the file
+ * count is set to given count argument, and the append mode is set to given
+ * append argument, other configuration using LogManager
+ * properties or their default value
+ *
+ * This handler is configured to write to a rotating set of count files,
+ * when the limit of bytes has been written to one output file, another file
+ * will be opened instead.
+ *
+ * @param pattern
+ * the name pattern of output file
+ * @param limit
+ * the data amount limit in bytes of one ouput file, cannot less
+ * than one
+ * @param count
+ * the maximum number of files can be used, cannot less than one
+ * @param append
+ * the append mode
+ * @throws IOException
+ * if any IO exception happened
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to control this handler,
+ * required permissions include LogPermission("control")
+ * and other permission like FilePermission("write")
,
+ * etc.
+ * @throws IllegalArgumentException
+ * if count<1, or limit<0
+ *
+ */
+ public FileHandler(String pattern, int limit, int count, boolean append)
+ throws IOException {
+ if(null == pattern || "".equals(pattern)){ //$NON-NLS-1$
+ throw new NullPointerException("Pattern cannot be empty"); //$NON-NLS-1$
+ }
+ if (limit < 1 || count < 0) {
+ throw new IllegalArgumentException(
+ "The limit and count property must larger than 0 and 1, respectively"); //$NON-NLS-1$
+ }
+ init(pattern, Boolean.valueOf(append), new Integer(limit), new Integer(
+ count));
+ }
+
+ /*
+ * ---------------------------------------------
+ * Methods overrides StreamHandler
+ * ---------------------------------------------
+ */
+ /**
+ * Flush and close all opened files.
+ *
+ * @throws SecurityException
+ * if security manager exists and it determines that caller
+ * does not have the required permissions to control this handler,
+ * required permissions include LogPermission("control")
+ * and other permission like FilePermission("write")
,
+ * etc.
+ */
+ public void close() {
+ //release locks
+ super.close();
+ // //FIXME: delete this
+ // System.out.println("close:"+fileName);
+ allLocks.remove(fileName);
+ try {
+ lock.release();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+
+ /**
+ * Publish a LogRecord
+ *
+ * @param record the log record to be published
+ */
+ public void publish(LogRecord record) {
+ super.publish(record);
+ flush();
+ if (limit > 0 && output.getLength() >= limit) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ findNextGeneration();
+ return null;
+ }
+ });
+ }
+ }
+
+ /*
+ * This output stream use decorator pattern to add measure feature to OutputStream
+ * which can detect the total size(in bytes) of output, the initial size can be set
+ */
+ class MeasureOutputStream extends OutputStream {
+
+ OutputStream wrapped;
+
+ long length;
+
+ public MeasureOutputStream(OutputStream stream, long currentLength) {
+ wrapped = stream;
+ length = currentLength;
+ }
+
+ public MeasureOutputStream(OutputStream stream) {
+ this(stream, 0);
+ }
+
+ public void write(int oneByte) throws IOException {
+ wrapped.write(oneByte);
+ length++;
+ }
+
+ public void write(byte[] bytes) throws IOException {
+ wrapped.write(bytes);
+ length += bytes.length;
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ wrapped.write(b, off, len);
+ length += len;
+ }
+
+ public void close() throws IOException {
+ wrapped.close();
+ }
+
+ public void flush() throws IOException {
+ wrapped.flush();
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public void setLength(long newLength) {
+ length = newLength;
+ }
+
+ }
+
+}
+
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Filter.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Filter.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Filter.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Filter.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,43 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+/**
+ * Filter
objects are used to filter loggings that are not
+ * desired. Handler
or Logger
objects can be
+ * attached with a filter to get finer grain control over what should be logged.
+ *
+ */
+public interface Filter {
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Checks whether the supplied log record needs to be logged.
+ *
+ * @param record
+ * the log record to be checked
+ * @return true
if the supplied log record needs to be
+ * logged, otherwise false
+ */
+ boolean isLoggable(LogRecord record);
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Formatter.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Formatter.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Formatter.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Formatter.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,129 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * Formatter
objects are used to format LogRecord
+ * objects into a string representation. Head and tail strings are sometime used
+ * to wrap a set of records. The getHead
and getTail
+ * methods are presented for this purpose.
+ *
+ */
+public abstract class Formatter {
+
+ /*
+ * -------------------------------------------------------------------
+ * Constructors
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Constructs a Formatter
object.
+ */
+ protected Formatter() {
+ super();
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Formats a LogRecord
object into a string representation.
+ * The resulted string is usually localized and includes the message field
+ * of the supplied LogRecord
object.
+ *
+ * @param r
+ * the log record to be formatted into a string
+ * @return the string resulted from the formatting
+ */
+ public abstract String format(LogRecord r);
+
+ /**
+ * Formats a LogRecord
object into a localized string
+ * representation. This method can be regarded as a convenience for
+ * subclasses of Formatter
to use.
+ *
+ * The message string is firstly localized using the
+ * ResourceBundle
object associated with the supplied
+ * LogRecord
.
+ *
Handler
object accepts a logging request and exports the
+ * desired messages to a target, for example, a file, the console, etc. It can
+ * be disabled by setting its logging level to Level.OFF
.
+ *
+ */
+public abstract class Handler {
+
+ /*
+ * -------------------------------------------------------------------
+ * Constants
+ * -------------------------------------------------------------------
+ */
+ private static final Level DEFAULT_LEVEL = Level.ALL;
+
+ /*
+ * -------------------------------------------------------------------
+ * Instance variables
+ * -------------------------------------------------------------------
+ */
+
+ // the error manager to report errors during logging
+ private ErrorManager errorMan;
+
+ // the character encoding used by this handler
+ private String encoding;
+
+ // the logging level
+ private Level level;
+
+ // the formatter used to export messages
+ private Formatter formatter;
+
+ // the filter used to filter undesired messages
+ private Filter filter;
+
+ // class name, used for property reading
+ private String prefix;
+
+ /*
+ * -------------------------------------------------------------------
+ * Constructors
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Constructs a Handler
object with a default error manager,
+ * the default encoding, and the default logging level
+ * Level.ALL
. It has no filter and no formatter.
+ */
+ protected Handler() {
+ this.errorMan = new ErrorManager();
+ this.level = DEFAULT_LEVEL;
+ this.encoding = null;
+ this.filter = null;
+ this.formatter = null;
+ this.prefix = this.getClass().getName();
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ // get a instance from given class name, using Class.forName()
+ private Object getDefaultInstance(String className) {
+ Object result = null;
+ if (null == className) {
+ return result;
+ }
+ try {
+ result = Class.forName(className).newInstance();
+ } catch (Exception e) {
+ //ignore
+ }
+ return result;
+ }
+
+ // get a instance from given class name, using context classloader
+ private Object getCustomizeInstance(final String className)
+ throws Exception {
+ Class c = (Class) AccessController
+ .doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ ClassLoader loader = Thread.currentThread()
+ .getContextClassLoader();
+ if (null == loader)
+ loader = ClassLoader.getSystemClassLoader();
+ return loader.loadClass(className);
+ }
+ });
+ return c.newInstance();
+ }
+
+ // print error message in some format
+ void printInvalidPropMessage(String key, String value, Exception e) {
+ String msg = new StringBuffer().append("Invalid property value for ") //$NON-NLS-1$
+ .append(prefix).append(".").append(key).append(":").append( //$NON-NLS-1$//$NON-NLS-2$
+ value).toString();
+ errorMan.error(msg, e, ErrorManager.GENERIC_FAILURE);
+ }
+
+ /*
+ * init the common properties, including filter, level, formatter, and
+ * encoding
+ */
+ void initProperties(String defaultLevel, String defaultFilter,
+ String defaultFormatter, String defaultEncoding) {
+ LogManager manager = LogManager.getLogManager();
+
+ //set filter
+ final String filterName = manager.getProperty(prefix + ".filter"); //$NON-NLS-1$
+ if (null != filterName) {
+ try {
+ filter = (Filter) getCustomizeInstance(filterName);
+ } catch (Exception e1) {
+ printInvalidPropMessage("filter", filterName, e1); //$NON-NLS-1$
+ filter = (Filter) getDefaultInstance(defaultFilter);
+ }
+ } else {
+ filter = (Filter) getDefaultInstance(defaultFilter);
+ }
+
+ //set level
+ String levelName = manager.getProperty(prefix + ".level"); //$NON-NLS-1$
+ if (null != levelName) {
+ try {
+ level = Level.parse(levelName);
+ } catch (Exception e) {
+ printInvalidPropMessage("level", levelName, e); //$NON-NLS-1$
+ level = Level.parse(defaultLevel);
+ }
+ } else {
+ level = Level.parse(defaultLevel);
+ }
+
+ //set formatter
+ final String formatterName = manager.getProperty(prefix + ".formatter"); //$NON-NLS-1$
+ if (null != formatterName) {
+ try {
+ formatter = (Formatter) getCustomizeInstance(formatterName);
+ } catch (Exception e) {
+ printInvalidPropMessage("formatter", formatterName, e); //$NON-NLS-1$
+ formatter = (Formatter) getDefaultInstance(defaultFormatter);
+ }
+ } else {
+ formatter = (Formatter) getDefaultInstance(defaultFormatter);
+ }
+
+ //set encoding
+ final String encodingName = manager.getProperty(prefix + ".encoding"); //$NON-NLS-1$
+ try {
+ internalSetEncoding(encodingName);
+ } catch (UnsupportedEncodingException e) {
+ printInvalidPropMessage("encoding", encodingName, e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Closes this handler. A flush operation will usually be performed and all
+ * the associated resources will be freed. Client applications should not
+ * use a handler after closing it.
+ *
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public abstract void close();
+
+ /**
+ * Flushes any buffered output.
+ */
+ public abstract void flush();
+
+ /**
+ * Accepts an actual logging request.
+ *
+ * @param record
+ * the log record to be logged
+ */
+ public abstract void publish(LogRecord record);
+
+ /**
+ * Gets the character encoding used by this handler.
+ *
+ * @return the character encoding used by this handler
+ */
+ public String getEncoding() {
+ return this.encoding;
+ }
+
+ /**
+ * Gets the error manager used by this handler to report errors during
+ * logging.
+ *
+ * @return the error manager used by this handler
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public ErrorManager getErrorManager() {
+ LogManager.getLogManager().checkAccess();
+ return this.errorMan;
+ }
+
+ /**
+ * Gets the filter used by this handler.
+ *
+ * @return the filter used by this handler
+ */
+ public Filter getFilter() {
+ return this.filter;
+ }
+
+ /**
+ * Gets the fomatter used by this handler to format the logging messages.
+ *
+ * @return the fomatter used by this handler
+ */
+ public Formatter getFormatter() {
+ return this.formatter;
+ }
+
+ /**
+ * Gets the logging level of this handler.
+ *
+ * @return the logging level of this handler
+ */
+ public Level getLevel() {
+ return this.level;
+ }
+
+ /**
+ * Determines whether the supplied log record need to be logged. The logging
+ * levels will be checked as well as the filter.
+ *
+ * @param record
+ * the log record to be checked
+ * @return true
if the supplied log record need to be logged,
+ * otherwise false
+ */
+ public boolean isLoggable(LogRecord record) {
+ if (null == record) {
+ reportError(
+ "Null pointer of LogRecord", new NullPointerException("null"), ErrorManager.GENERIC_FAILURE); //$NON-NLS-1$ //$NON-NLS-2$
+ return false;
+ }
+ if (this.level.intValue() == Level.OFF.intValue()) {
+ return false;
+ } else if (record.getLevel().intValue() >= this.level.intValue()) {
+ return null == this.filter ? true : this.filter.isLoggable(record);
+ }
+ return false;
+ }
+
+ /**
+ * Report an error to the error manager associated with this handler.
+ *
+ * @param msg
+ * the error message
+ * @param ex
+ * the associated exception
+ * @param code
+ * the error code
+ */
+ protected void reportError(String msg, Exception ex, int code) {
+ this.errorMan.error(msg, ex, code);
+ }
+
+ /**
+ * Sets the character encoding used by this handler. A null
+ * value indicates the using of the default encoding. This internal method
+ * does not check security.
+ *
+ * @param newEncoding
+ * the character encoding to set
+ * @throws UnsupportedEncodingException
+ * If the specified encoding is not supported by the runtime.
+ */
+ void internalSetEncoding(String newEncoding)
+ throws UnsupportedEncodingException {
+ // accepts "null" because it indicates using default encoding
+ if (null == newEncoding) {
+ this.encoding = null;
+ } else {
+ if (Charset.isSupported(newEncoding)) {
+ this.encoding = newEncoding;
+ } else {
+ throw new UnsupportedEncodingException("The encoding \"" //$NON-NLS-1$
+ + newEncoding + "\" is not supported."); //$NON-NLS-1$
+ }
+
+ }
+ }
+
+ /**
+ * Sets the character encoding used by this handler. A null
+ * value indicates the using of the default encoding.
+ *
+ * @param encoding
+ * the character encoding to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ * @throws UnsupportedEncodingException
+ * If the specified encoding is not supported by the runtime.
+ */
+ public void setEncoding(String encoding) throws SecurityException,
+ UnsupportedEncodingException {
+ LogManager.getLogManager().checkAccess();
+ internalSetEncoding(encoding);
+ }
+
+ /**
+ * Sets the error manager for this handler.
+ *
+ * @param em
+ * the error manager to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public void setErrorManager(ErrorManager em) {
+ LogManager.getLogManager().checkAccess();
+ if (null == em) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ this.errorMan = em;
+ }
+
+ /**
+ * Sets the filter to be used by this handler.
+ *
+ * @param newFilter
+ * the filter to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public void setFilter(Filter newFilter) {
+ LogManager.getLogManager().checkAccess();
+ this.filter = newFilter;
+ }
+
+ /**
+ * Sets the formatter to be used by this handler. This internal method does
+ * not check security.
+ *
+ * @param newFormatter
+ * the fomatter to set
+ */
+ void internalSetFormatter(Formatter newFormatter) {
+ if (null == newFormatter) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ this.formatter = newFormatter;
+ }
+
+ /**
+ * Sets the formatter to be used by this handler.
+ *
+ * @param newFormatter
+ * the fomatter to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public void setFormatter(Formatter newFormatter) {
+ LogManager.getLogManager().checkAccess();
+ internalSetFormatter(newFormatter);
+ }
+
+ /**
+ * Sets the logging level of this handler.
+ *
+ * @param newLevel
+ * the logging level to set
+ * @throws SecurityException
+ * If a security manager determines that the caller does not
+ * have the required permission.
+ */
+ public void setLevel(Level newLevel) {
+ if (null == newLevel) {
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ }
+ LogManager.getLogManager().checkAccess();
+ this.level = newLevel;
+ }
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Level.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Level.java?rev=386087&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Level.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/logging/src/main/java/java/util/logging/Level.java Wed Mar 15 06:55:38 2006
@@ -0,0 +1,359 @@
+/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package java.util.logging;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * Level
objects are used to indicate the level of logging. There
+ * are a set of predefined logging levels, each associated with an integer
+ * value. Enabling a certain logging level also enables all logging levels with
+ * larger values.
+ * + * The predefined levels in ascending order are FINEST, FINER, FINE, CONFIG, + * INFO, WARNING, SEVERE. There are two additional predefined levels, which are + * ALL and OFF. ALL indicates logging all messages, and OFF indicates logging no + * messages. + *
+ * + */ +public class Level implements Serializable { + + + //for serialization compability + private static final long serialVersionUID = -8176160795706313070L; + + /* + * ------------------------------------------------------------------- + * Constants + * ------------------------------------------------------------------- + */ + + /* + * ------------------------------------------------------------------- + * Class variables + * ------------------------------------------------------------------- + */ + private static Map levels = new HashMap(); + + // The following string constants define the name of all predefined levels. + private static final String SEVERESTR = "SEVERE"; //$NON-NLS-1$ + + private static final String WARNINGSTR = "WARNING"; //$NON-NLS-1$ + + private static final String INFOSTR = "INFO"; //$NON-NLS-1$ + + private static final String CONFIGSTR = "CONFIG"; //$NON-NLS-1$ + + private static final String FINESTR = "FINE"; //$NON-NLS-1$ + + private static final String FINERSTR = "FINER"; //$NON-NLS-1$ + + private static final String FINESTSTR = "FINEST"; //$NON-NLS-1$ + + private static final String OFFSTR = "OFF"; //$NON-NLS-1$ + + private static final String ALLSTR = "ALL"; //$NON-NLS-1$ + + /** + * The SEVERE level indicates a severe failure. + */ + public static final Level SEVERE = new Level(SEVERESTR, 1000); + + /** + * The WARNING level indicates a warning. + */ + public static final Level WARNING = new Level(WARNINGSTR, 900); + + /** + * The INFO level indicates an informative message. + */ + public static final Level INFO = new Level(INFOSTR, 800); + + /** + * The CONFIG level indicates a static configuration message. + */ + public static final Level CONFIG = new Level(CONFIGSTR, 700); + + /** + * The FINE level provides tracing messages. + */ + public static final Level FINE = new Level(FINESTR, 500); + + /** + * The FINER level provides more detailed tracing messages. + */ + public static final Level FINER = new Level(FINERSTR, 400); + + /** + * The FINEST level provides highly detailed tracing messages. + */ + public static final Level FINEST = new Level(FINESTSTR, 300); + + /** + * The OFF level provides no logging messages. + */ + public static final Level OFF = new Level(OFFSTR, Integer.MAX_VALUE); + + /** + * The ALL level provides all logging messages. + */ + public static final Level ALL = new Level(ALLSTR, Integer.MIN_VALUE); + + + /* + * ------------------------------------------------------------------- + * Global initialization + * ------------------------------------------------------------------- + */ + + static { + levels.remove(null); + } + + /* + * ------------------------------------------------------------------- + * Instance variables + * ------------------------------------------------------------------- + */ + + /** + * The name of this Level. + * + * @serial + */ + private final String name; + + /** + * The integer value indicating the level. + * + * @serial + */ + private final int value; + + /** + * The name of the resource bundle used to localize the level name. + * + * @serial + */ + private final String resourceBundleName; + + /* + * The resource bundle associated with this level, used to localize the + * level name. + */ + private transient ResourceBundle rb; + + /* + * ------------------------------------------------------------------- + * Constructors + * ------------------------------------------------------------------- + */ + + /** + * Constructs an instance ofLevel
taking the supplied name
+ * and level value.
+ *
+ * @param name
+ * name of the level
+ * @param level
+ * an integer value indicating the level
+ */
+ protected Level(String name, int level) {
+ this(name, level, null);
+ }
+
+ /**
+ * Constructs an instance of Level
taking the supplied name
+ * and level value.
+ *
+ * @param name
+ * name of the level
+ * @param level
+ * an integer value indicating the level
+ * @param resourceBundleName
+ * the name of the resource bundle to use
+ */
+ protected Level(String name, int level, String resourceBundleName) {
+ this.name = name;
+ this.value = level;
+ this.resourceBundleName = resourceBundleName;
+ //put value into known values list in Constructor
+ if(null==levels.get(name)){
+ levels.put(name,this);
+ }
+ if(null==levels.get(String.valueOf(level))){
+ levels.put(String.valueOf(this.intValue()), this);
+ }
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Gets the name of this Level
.
+ *
+ * @return the name of this Level
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Gets the name of the resource bundle associated with this
+ * Level
.
+ *
+ * @return the name of the resource bundle associated with this
+ * Level
+ */
+ public String getResourceBundleName() {
+ return this.resourceBundleName;
+ }
+
+ /**
+ * Gets the integer value indicating this Level
.
+ *
+ * @return the integer value indicating this Level
+ */
+ public final int intValue() {
+ return this.value;
+ }
+
+ /**
+ * Parses a level name into a Level
object.
+ *
+ * @param name
+ * the name of the desired level, which cannot be null
+ * @return a Level
object with the specified name
+ * @throws NullPointerException
+ * If name
is null.
+ * @throws IllegalArgumentException
+ * When name
cannot be parsed.
+ */
+ public static final Level parse(String name) {
+ if (null == name)
+ throw new NullPointerException("null"); //$NON-NLS-1$
+ // Check if the name is a predefined one
+ Level result = (Level) levels.get(name);
+ if (null != result) {
+ return result;
+ }
+ // Try to parse the name as an integer
+ try {
+ int v = Integer.parseInt(name);
+ result = new Level(name, v);
+ return result;
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Cannot parse this name: " //$NON-NLS-1$
+ + name);
+ }
+ }
+
+ /**
+ * Gets the localized name of this level. The default locale is used. If no
+ * resource bundle is associated with this Level
, the
+ * original level name is returned.
+ *
+ * @return the localized name of this level
+ */
+ public String getLocalizedName() {
+ String result = name;
+ if (null != resourceBundleName && null == rb) {
+ try {
+ rb = ResourceBundle.getBundle(resourceBundleName);
+ } catch (Exception e) {
+ rb = null;
+ }
+ }
+ if (null != rb) {
+ try {
+ result = rb.getString(name);
+ } catch (Exception e) {
+ result = name;
+ }
+ }
+ return result;
+ }
+
+ /*
+ * Maintains the Object uniqueness property across serialization.
+ */
+ private Object readResolve() {
+ String levelName = this.getName();
+ Level result = (Level) levels.get(levelName);
+
+ if (null != result) {
+ boolean sameResourceBundle = (this.resourceBundleName == null ? result
+ .getResourceBundleName() == null
+ : this.resourceBundleName.equals(result
+ .getResourceBundleName()));
+ if (result.intValue() == this.value && sameResourceBundle) {
+ return result;
+ }
+ }
+ return this;
+ }
+
+ /*
+ * -------------------------------------------------------------------
+ * Methods overriding parent class Object
+ * -------------------------------------------------------------------
+ */
+
+ /**
+ * Compares two Level
objects for equality. They are
+ * considered to be equal if they have the same value.
+ *
+ * @param o
+ * the other object to be compared with
+ * @return true
if this object equals to the supplied object,
+ * otherwise false
+ */
+ public boolean equals(Object o) {
+ if (!(o instanceof Level)) {
+ return false;
+ }
+ return ((Level) o).intValue() == this.value;
+ }
+
+ /**
+ * Returns the hash code of this Level
object.
+ *
+ * @return the hash code of this Level
object
+ */
+ public int hashCode() {
+ return this.value;
+ }
+
+ /**
+ * Returns the string representation of this Level
object.
+ * Usually this will include its name.
+ *
+ * @return the string representation of this Level
object
+ */
+ public final String toString() {
+ return this.name;
+ }
+
+}
+