-
Enhancement
-
Resolution: Unresolved
-
P4
-
None
-
6u26
-
x86
-
windows_vista
A DESCRIPTION OF THE REQUEST :
On shutdown of the JVM, the LogManager$Cleaner will call LogManager.reset. LogManager.reset will first clear all the properties assigned in the LogManager then walks all the loggers and calls close on each attached handler. Because the LogManager properties are cleared first, Handler.close is not able to perform any valid LogManager.getProperty calls.
JUSTIFICATION :
It is inconsistent that Handler.close is able to get properties from a direct call but unable to get properties during an indirect call from LogManager.reset. There is no way to perform lazy lookups during close so values have to be cached on startup which hurts the load times of an application. For some handlers that are adapters for other APIs there is no way to explictly know what parameters are required to be cached at startup since there is no way to iterate over LogManager keys.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Handler.close should always be able to getProperties from the LogManager during a reset.
ACTUAL -
LogManager.getProperty will return null.
---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class Cleared extends Handler {
private static final Logger logger = Logger.getLogger("Cleared");
public static void main(String[] args) throws IOException {
Properties props = new Properties();
props.put(Cleared.class.getName(), logger.getClass().getName());
ByteArrayOutputStream out = new ByteArrayOutputStream();
props.store(out, "");
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
LogManager.getLogManager().readConfiguration(in);
logger.addHandler(new Cleared());
}
public Cleared() {
try {
check();
} catch(RuntimeException re) {
this.reportError("", re, ErrorManager.OPEN_FAILURE);
}
}
@Override
public void publish(LogRecord record) {
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
try {
check();
} catch(RuntimeException re) {
this.reportError("", re, ErrorManager.CLOSE_FAILURE);
}
}
private void check() {
String p = LogManager.getLogManager().getProperty(getClass().getName());
if (!logger.getClass().getName().equals(p)) {
throw new IllegalStateException();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Create a LogManager subclass and override reset to first close and remove all handlers then perform the super action.
On shutdown of the JVM, the LogManager$Cleaner will call LogManager.reset. LogManager.reset will first clear all the properties assigned in the LogManager then walks all the loggers and calls close on each attached handler. Because the LogManager properties are cleared first, Handler.close is not able to perform any valid LogManager.getProperty calls.
JUSTIFICATION :
It is inconsistent that Handler.close is able to get properties from a direct call but unable to get properties during an indirect call from LogManager.reset. There is no way to perform lazy lookups during close so values have to be cached on startup which hurts the load times of an application. For some handlers that are adapters for other APIs there is no way to explictly know what parameters are required to be cached at startup since there is no way to iterate over LogManager keys.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Handler.close should always be able to getProperties from the LogManager during a reset.
ACTUAL -
LogManager.getProperty will return null.
---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class Cleared extends Handler {
private static final Logger logger = Logger.getLogger("Cleared");
public static void main(String[] args) throws IOException {
Properties props = new Properties();
props.put(Cleared.class.getName(), logger.getClass().getName());
ByteArrayOutputStream out = new ByteArrayOutputStream();
props.store(out, "");
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
LogManager.getLogManager().readConfiguration(in);
logger.addHandler(new Cleared());
}
public Cleared() {
try {
check();
} catch(RuntimeException re) {
this.reportError("", re, ErrorManager.OPEN_FAILURE);
}
}
@Override
public void publish(LogRecord record) {
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
try {
check();
} catch(RuntimeException re) {
this.reportError("", re, ErrorManager.CLOSE_FAILURE);
}
}
private void check() {
String p = LogManager.getLogManager().getProperty(getClass().getName());
if (!logger.getClass().getName().equals(p)) {
throw new IllegalStateException();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Create a LogManager subclass and override reset to first close and remove all handlers then perform the super action.