/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* 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 org.sleuthkit.autopsy.coreutils;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
import javax.swing.JOptionPane;
import org.openide.util.lookup.ServiceProvider;
import org.netbeans.core.NbErrorManager;
/**
* Replaces default NetBeans exception handler. Displays messages in a dialog.
*/
@ServiceProvider(service = Handler.class, supersedes = "org.netbeans.core.NbErrorManager")
public class AutopsyExceptionHandler extends Handler {
static final int INFO_VALUE = Level.INFO.intValue();
static final int WARNING_VALUE = Level.WARNING.intValue();
static final int SEVERE_VALUE = Level.SEVERE.intValue();
static final Handler nbErrorManager = new NbErrorManager(); // Default NetBeans handler
static final Version.Type buildType = Version.getBuildType();
private final Logger logger = Logger.getLogger(AutopsyExceptionHandler.class.getName());
public AutopsyExceptionHandler() {
super();
this.setLevel(Level.SEVERE);
/*
* if (buildType == Version.Type.DEVELOPMENT) //for dev builds, show
* dialogs for WARNING and above this.setLevel(Level.WARNING); else
* //for production builds, show dialogs for SEVERE and above (TODO in
* future consider not show any, explicit dialogs should be in place)
* this.setLevel(Level.SEVERE);
*/
this.setFilter(new ExceptionFilter());
this.setFormatter(new SimpleFormatter());
}
@Override
public void publish(LogRecord record) {
if (isLoggable(record)) {
final String title = getTitleForLevelValue(record.getLevel().intValue());
final String message = formatExplanation(record);
if (record.getMessage() != null) {
// Throwable was anticipated, caught and logged. Display log message and throwable message.
MessageNotifyUtil.Notify.error(title, message);
logger.log(Level.SEVERE, "Unexpected error: " + title + ", " + message); //NON-NLS
} else {
// Throwable (unanticipated) error. Use built-in exception handler to offer details, stacktrace.
nbErrorManager.publish(record);
}
}
}
/**
* Filter only accepts records with exceptions attached.
*/
private static class ExceptionFilter implements Filter {
@Override
public boolean isLoggable(LogRecord record) {
// True if there is an uncaught exception being thrown.
return record.getThrown() != null;
}
}
/**
*
* @param record A LogRecord with both a message and associated Throwable
* set.
*
* @return A String containing the log message and the cause of the
* Throwable (if there is one).
*/
private String formatExplanation(LogRecord record) {
final String logMessage = getFormatter().formatMessage(record);
String explanation = record.getThrown().getMessage();
String causeMessage = (explanation != null) ? "\nCaused by: " + explanation : ""; //NON-NLS
return logMessage + causeMessage;
}
// It's harder to do this cleanly than I thought, because Exceptions
// initialized with no message copy and prepend the cause's message
//
// private String recursiveExplanation(Throwable e) {
// String message = e.getMessage();
// String explanation = (message != null) ? "\nCaused by: " + message : "";
// Throwable cause = e.getCause();
// if (cause == null) {
// return explanation;
// } else {
// return explanation + recursiveExplanation(cause);
// }
// }
private static int getMessageTypeForLevelValue(int levelValue) {
if (levelValue >= SEVERE_VALUE) {
return JOptionPane.ERROR_MESSAGE;
} else if (levelValue >= WARNING_VALUE) {
return JOptionPane.WARNING_MESSAGE;
} else {
return JOptionPane.INFORMATION_MESSAGE;
}
}
private static String getTitleForLevelValue(int levelValue) {
if (levelValue >= SEVERE_VALUE) {
return "Error"; //NON-NLS
} else if (levelValue >= WARNING_VALUE) {
return "Warning"; //NON-NLS
} else {
return "Message"; //NON-NLS
}
}
@Override
public void flush() {
// no buffer to flush
}
@Override
public void close() throws SecurityException {
// no resources to close
}
}