/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.sun.jini.logging;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Defines a {@link java.util.logging.LogManager} that insures that the {@link
* Levels#FAILED Levels.FAILED} and {@link Levels#HANDLED Levels.HANDLED}
* fields, instances of {@link Level}, have been initialized, and that can
* periodically check for changes to the logging configuration file and force
* it to be reread. Use this class as the value of the
* <code>java.util.logging.manager</code> system property to permit specifying
* the symbolic names for the <code>FAILED</code> and <code>HANDLED</code>
* logging levels in standard logging configuration files, or to allow changes
* to the logging configuration file to be noticed. <p>
*
* The <code>com.sun.jini.logging.interval</code> logging property (obtained
* using {@link java.util.logging.LogManager#getProperty
* LogManager.getProperty}) specifies the time interval in milliseconds
* between probes to see if the logging configuration file has changed;
* periodic checking only takes place if the value is greater than zero. (If a
* new logging configuration file is read, this property can be redefined.)
* The logging configuration file is specified by the
* <code>java.util.logging.config.file</code> system property (which is
* sampled at every probe), if defined, otherwise it is the
* <code>logging.properties</code> file in the <code>lib</code> subdirectory
* of the directory specified by the <code>java.home</code> system property.
* The file is read if the name of the file differs from that used in the
* previous probe or if the file has a different modification time. <p>
*
* This implementation uses the {@link java.util.logging.Logger} named
* <code>com.sun.jini.logging.LogManager</code> to log information at the
* following logging levels: <p>
*
* <table border="1" cellpadding="5" summary="Describes logging performed
* by the LogManager class at different logging levels">
* <caption halign="center" valign="top"><b><code>
* com.sun.jini.logging.LogManager</code></b></caption>
* <tr><th scope="col">Level<th scope="col">Description
* <tr><td>{@link Level#WARNING WARNING}<td>if an exception occurs while
* rereading the logging configuration file
* <tr><td>{@link Level#CONFIG CONFIG}<td>each time the logging configuration
* file is successfully reread
* <tr><td>{@link Level#CONFIG CONFIG}<td>termination of probes because
* interval is less than or equal to zero
* </table>
*
* @author Sun Microsystems, Inc.
* @since 2.0
*/
public class LogManager extends java.util.logging.LogManager {
private Probe probe = null;
/** Creates an instance of this class. */
public LogManager() {
/* Refer to the levels to make sure that they are defined */
Levels.FAILED.toString();
Levels.HANDLED.toString();
}
/**
* Reinitialize the logging properties and reread the logging
* configuration, and initiate probes if the probe interval is greater
* than zero.
*/
public void readConfiguration(InputStream ins) throws IOException {
super.readConfiguration(ins);
synchronized (this) {
if (probe == null) {
long interval = getInterval();
if (interval > 0) {
probe = new Probe(interval);
probe.start();
}
}
}
}
/** Return the probe interval. */
private long getInterval() {
String val = getProperty("com.sun.jini.logging.interval");
if (val != null) {
try {
return Long.decode(val).longValue();
} catch (NumberFormatException e) {
}
}
return 0;
}
/** Return the logging configuration file name. */
private static File getFile() {
String fname = System.getProperty("java.util.logging.config.file");
if (fname != null) {
return new File(fname);
} else {
return new File(System.getProperty("java.home"),
"lib" + File.separator + "logging.properties");
}
}
/** Thread to probe for config file changes and force reread */
private class Probe extends Thread {
/** Time in milliseconds between probes */
private long interval;
/** The last file read */
private File prevFile;
/** The lastModified time of prevFile */
private long prevModified;
Probe(long interval) {
super("LogManager config file probe");
setDaemon(true);
this.interval = interval;
prevFile = getFile();
prevModified = prevFile.lastModified();
}
public void run() {
Logger logger =
Logger.getLogger("com.sun.jini.logging.LogManager");
try {
while (interval > 0) {
Thread.sleep(interval);
File file = getFile();
long lastModified = file.lastModified();
if (lastModified > 0 &&
(!file.equals(prevFile) ||
lastModified != prevModified))
{
try {
readConfiguration();
interval = getInterval();
logger.log(Level.CONFIG,
"logging config file reread complete," +
" new interval is {0}",
new Long(interval));
} catch (Throwable t) {
try {
logger.log(Level.WARNING,
"exception reading logging config file",t);
} catch (Throwable t2) {}
}
prevFile = file;
prevModified = lastModified;
}
}
} catch (InterruptedException e) {
} finally {
synchronized (LogManager.this) {
probe = null;
}
logger.config("logging config file probe terminating");
}
}
}
}