/*
* Copyright 2009-2016 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB 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 3 of the License, or
* (at your option) any later version.
*
* ZooDB 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 ZooDB. If not, see <http://www.gnu.org/licenses/>.
*
* See the README and COPYING files for further information.
*/
package org.zoodb.internal.util;
import java.lang.reflect.Constructor;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.zoodb.api.ZooException;
import org.zoodb.api.impl.ZooPC;
public class DBLogger {
private static final boolean isJDO;
//TODO ENUM
// enum EX_TYPE {
// FATAL,
// ILLEGAL_ARGUMENT,
// ILLEGAL_STATE,
// //OBJECT_NOT_FOUND, //?
// USER; //repeatable
// }
public static final Logger LOGGER =
Logger.getLogger(DBLogger.class.getName());
public static final Handler LOGGER_CONSOLE_HANDLER = new ConsoleHandler();
private static int verbosityLevel = 0;
private static boolean verboseToLog = false;
public static final Class<? extends RuntimeException> USER_EXCEPTION;
public static final Class<? extends RuntimeException> FATAL_EXCEPTION;
//these always result in the session being closed!
public static final Class<? extends RuntimeException> FATAL_DATA_STORE_EXCEPTION;
public static final Class<? extends RuntimeException> FATAL_INTERNAL_EXCEPTION;
public static final Class<? extends RuntimeException> OBJ_NOT_FOUND_EXCEPTION;
public static final Class<? extends RuntimeException> OPTIMISTIC_VERIFICATION_EXCEPTION;
static {
if (ReflTools.existsClass("javax.jdo.JDOHelper")) {
//try JDO
USER_EXCEPTION = ReflTools.classForName("javax.jdo.JDOUserException");
FATAL_EXCEPTION = ReflTools.classForName("javax.jdo.JDOFatalException");
FATAL_DATA_STORE_EXCEPTION = ReflTools.classForName("javax.jdo.JDOFatalDataStoreException");
FATAL_INTERNAL_EXCEPTION = ReflTools.classForName("javax.jdo.JDOFatalInternalException");
OBJ_NOT_FOUND_EXCEPTION = ReflTools.classForName("javax.jdo.JDOObjectNotFoundException");
OPTIMISTIC_VERIFICATION_EXCEPTION = ReflTools.classForName("javax.jdo.JDOOptimisticVerificationException");
isJDO = true;
} else {
//Native ZooDB
USER_EXCEPTION = ZooException.class;
FATAL_EXCEPTION = ZooException.class;
FATAL_DATA_STORE_EXCEPTION = ZooException.class;
FATAL_INTERNAL_EXCEPTION = ZooException.class;
OBJ_NOT_FOUND_EXCEPTION = ZooException.class;
OPTIMISTIC_VERIFICATION_EXCEPTION = ZooException.class;
isJDO = false;
}
LOGGER_CONSOLE_HANDLER.setFormatter(new OneLineFormatter());
}
/**
* Set the verbosity level for debug output. Level 0 means no output, higher levels result
* in increasingly detailed output. Default is 0.
* @param level
*/
public static void setVerbosityLevel(int level) {
verbosityLevel = level;
}
/**
* Set the level of the logger.
* @param level
* @see Logger#setLevel(Level)
*/
public static void setLoggerLevel(Level level, boolean redirectOutputToConsole) {
LOGGER.setLevel(level);
if (redirectOutputToConsole) {
if (!Arrays.asList(LOGGER.getHandlers()).contains(LOGGER_CONSOLE_HANDLER)) {
LOGGER.addHandler(LOGGER_CONSOLE_HANDLER);
}
LOGGER_CONSOLE_HANDLER.setLevel(level);
} else {
LOGGER.removeHandler(LOGGER_CONSOLE_HANDLER);
}
}
public static class OneLineFormatter extends Formatter {
private static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";//XXX";
@Override
public String format(final LogRecord record) {
return String.format(
"%1$s %2$-7s %3$s.%4$s(...) -> %5$s\n",
new SimpleDateFormat(PATTERN).format(
new Date(record.getMillis())),
record.getLevel().getName(),
record.getSourceClassName().substring(
record.getSourceClassName().lastIndexOf('.')+1),
record.getSourceMethodName(),
formatMessage(record));
}
}
private static RuntimeException newEx(Class<? extends RuntimeException> exCls, String msg,
Throwable cause) {
return newEx(exCls, msg, cause, null);
}
private static RuntimeException newEx(Class<? extends RuntimeException> exCls, String msg,
Throwable cause, Object failed) {
//severe(msg);
Constructor<? extends RuntimeException> con;
con = ReflTools.getConstructor(exCls, String.class, Throwable.class, Object.class);
return ReflTools.newInstance(con, msg, cause, failed);
}
/**
* Prints a debug message if the level is below or equal the
* <code>verbosity</code> setting. The output can be
* redirected to the logging mechanism by setting the following
* property: <tt>verboseOutput = log</tt>.
* @param level
* @param message Message to print.
*/
public static final void debugPrint(int level, String ... message) {
if (level <= verbosityLevel) {
long tId = Thread.currentThread().getId();
FormattedStringBuilder buf =
new FormattedStringBuilder().append("Debug (" + tId + "): ").append(message);
if (verboseToLog) {
LOGGER.info(buf.toString());
} else {
System.out.print(buf.toString());
}
}
}
/**
* Prints a debug message if the level is below or equal the
* <code>verbosity</code> setting. The output can be
* redirected to the logging mechanism by setting the following
* property: <tt>verboseOutput = log</tt>.
* @param level
* @param message Message to print.
*/
public static final void debugPrintln(int level, String ... message) {
debugPrint(level, message);
if (level <= verbosityLevel && !verboseToLog) {
System.out.println();
}
}
public static void severe(String string) {
if (LOGGER.isLoggable(Level.SEVERE)) {
System.err.println("SEVERE: " + string);
}
}
public static void warning(String string) {
if (LOGGER.isLoggable(Level.WARNING)) {
System.err.println("WARNING: " + string);
}
}
public static void info(String string) {
if (LOGGER.isLoggable(Level.INFO)) {
System.out.println("INFO: " + string);
}
}
public static boolean isLoggable(Level level) {
return LOGGER.isLoggable(level);
}
public static RuntimeException newUser(String msg) {
return newEx(USER_EXCEPTION, msg, null);
}
public static RuntimeException newUser(String msg, Throwable t) {
return newEx(USER_EXCEPTION, msg, t);
}
public static RuntimeException newUser(String msg, ZooPC obj) {
if (isJDO) {
//throw new JDOUserException(msg, obj);
return newEx(USER_EXCEPTION, msg, null, obj);
}
return newEx(USER_EXCEPTION, msg + " obj=" + Util.getOidAsString(obj), null);
}
public static RuntimeException newFatal(String msg) {
return newFatal(msg, null);
}
public static RuntimeException newFatal(String msg, Throwable t) {
return newEx(FATAL_EXCEPTION, msg, t);
}
public static RuntimeException newObjectNotFoundException(String msg) {
return newObjectNotFoundException(msg, null, null);
}
public static RuntimeException newObjectNotFoundException(String msg, Throwable t,
Object failed) {
return newEx(OBJ_NOT_FOUND_EXCEPTION, msg, t, failed);
}
public static RuntimeException newFatalInternal(String msg) {
return newFatalInternal(msg, null);
}
public static RuntimeException newFatalInternal(String msg, Throwable t) {
return newEx(FATAL_INTERNAL_EXCEPTION, msg, t);
}
/**
* THese always result in the session being closed!
* @param msg
* @param t
* @return Fatal data store exception.
*/
public static RuntimeException newFatalDataStore(String msg, Throwable t) {
return newEx(FATAL_DATA_STORE_EXCEPTION, msg, t);
}
public static boolean isUser(RuntimeException e) {
return USER_EXCEPTION.isAssignableFrom(e.getClass());
}
public static boolean isObjectNotFoundException(RuntimeException e) {
return OBJ_NOT_FOUND_EXCEPTION.isAssignableFrom(e.getClass());
}
public static boolean isFatalDataStoreException(RuntimeException e) {
return FATAL_DATA_STORE_EXCEPTION.isAssignableFrom(e.getClass());
}
public static boolean isOptimisticVerificationException(RuntimeException e) {
return OPTIMISTIC_VERIFICATION_EXCEPTION.isAssignableFrom(e.getClass());
}
}