package com.rcpcompany.utils.logging.internal;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.equinox.log.ExtendedLogService;
import org.eclipse.equinox.log.Logger;
import org.eclipse.jdt.annotation.Nullable;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.log.LogService;
import com.rcpcompany.utils.basic.ClassUtils;
import com.rcpcompany.utils.basic.TSRegistryUtils;
import com.rcpcompany.utils.logging.ILogUtilsForwardHandler;
import com.rcpcompany.utils.logging.LogUtils;
/**
* Internal implementation for {@link LogUtils}.
*
* @author Tonny Madsen, tonny.madsen@gmail.com
*/
public class LogUtilsImpl {
private ILogUtilsForwardHandler myLogHandler = null;
/**
* The basic OSGi log service if defined.
*/
private LogService myLogService = null;
/**
* The extended Equinox log service if defined.
*/
private ExtendedLogService myExtendedLogService = null;
/**
* The handler instance (singleton).
*/
private final static LogUtilsImpl INSTANCE;
static {
INSTANCE = new LogUtilsImpl();
INSTANCE.initLogForwarder();
}
/**
* Returns this hander singleton instance.
*
* @return the singleton
*/
public static LogUtilsImpl getInstance() {
return INSTANCE;
}
/**
* Constructs and returns a new {@link LogUtils} handler.
*/
private LogUtilsImpl() {
}
private void initLogForwarder() {
Class<ILogUtilsForwardHandler> handlerClass = null;
try {
handlerClass = (Class<ILogUtilsForwardHandler>) Class
.forName("com.rcpcompany.utils.logging.forwarder.ForwardHandler");
} catch (final ClassNotFoundException ex) {
return;
}
try {
myLogHandler = handlerClass.newInstance();
} catch (final InstantiationException ex) {
} catch (final IllegalAccessException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
/**
* The string used for the plug-in if it cannot be deduced.
*/
public static final String UNKNOWN_PLUGIN = "<unknown>";
/* ======================================================================== */
private Throwable lastException;
/**
* Whether the last log message used {@link System#err}.
*/
private boolean lastMessageUsedStdErr = false;
/**
* Logs the specified message.
*
* @param context
* the context related to the message
* @param logLevel
* the severity of the log message
* @param message
* the message to print
* @param exception
* any exception associated with the log message or <code>null</code>
*/
public void log(Object context, int logLevel, String message, Throwable exception) {
if (exception instanceof InvocationTargetException) {
exception = ((InvocationTargetException) exception).getTargetException();
}
/*
* Special case: if the exception is the same as last time!! So don't report it again...
*/
if (exception != null && exception == lastException)
return;
if (myLogHandler != null) {
myLogHandler.log(context, logLevel, message, exception);
return;
}
String bundleID = UNKNOWN_PLUGIN;
String messagePrefix = null;
if (context instanceof IConfigurationElement) {
final IConfigurationElement ce = (IConfigurationElement) context;
bundleID = ce.getContributor().getName();
messagePrefix = TSRegistryUtils.toString(ce);
} else if (context instanceof String) {
bundleID = (String) context;
} else if (context != null) {
final String b = findBundleID(context);
if (b != null) {
bundleID = b;
}
}
if (bundleID == null || bundleID.length() == 0) {
bundleID = UNKNOWN_PLUGIN;
}
if (message == null && exception != null) {
message = exception.getMessage();
if (message == null) {
message = ClassUtils.getLastClassName(exception);
}
}
if (messagePrefix != null) {
message = messagePrefix + ": " + message;
}
message = logMessage(message);
if (myExtendedLogService != null) {
Logger log = myExtendedLogService;
if (bundleID != null) {
Bundle bundle = null;
final BundleContext bc = Activator.getDefault().getContext();
if (bc != null) {
for (final Bundle b : bc.getBundles()) {
if (b.getSymbolicName().equals(bundleID)) {
bundle = b;
break;
}
}
}
if (bundle != null) {
log = myExtendedLogService.getLogger(bundle, "org.eclipse.equinox.logger"); // TODO which logger
// name to use
}
}
lastMessageUsedStdErr = false;
log.log(context, logLevel, message, exception);
} else if (myLogService != null) {
lastMessageUsedStdErr = false;
myLogService.log(logLevel, message, exception);
} else {
if (!lastMessageUsedStdErr) {
System.err.println("LOG [no current OSGi log service]");
lastMessageUsedStdErr = true;
}
System.err.println("LOG>>> " + message);
}
}
/**
* Returns the ID of the bundle that loaded the class of the specified object.
*
* @param obj
* the object in question
* @return the bundle ID or <code>null</code> if not known
*/
@Nullable
public String findBundleID(Object obj) {
final Bundle bundle = FrameworkUtil.getBundle(obj.getClass());
if (bundle == null)
return null;
return bundle.getSymbolicName();
}
/* ======================================================================== */
/**
* Calculates and returns a log message based on the specified string.
*
* @param message
* the message to print
* @return the calculated log message string
*/
public String logMessage(String message) {
final StringBuffer buffer = new StringBuffer();
buffer.append("[");
// TODO Change format!
// buffer.append(new Date(System.currentTimeMillis()));
//
// buffer.append(" - ");
buffer.append(Thread.currentThread().getName());
buffer.append(" ");
final RuntimeException ex = new RuntimeException();
ex.fillInStackTrace();
int level = 0;
final StackTraceElement[] stackTrace = ex.getStackTrace();
while (level < stackTrace.length) {
final StackTraceElement st = stackTrace[level++];
// Skip Utilities methods
final String className = st.getClassName();
if (className.startsWith(LogUtils.class.getName())) {
continue;
}
if (className.startsWith(LogUtilsImpl.class.getName())) {
continue;
}
buffer.append(ClassUtils.getLastClassName(className)).append('.').append(st.getMethodName()).append(" (")
.append(st.getFileName()).append(':').append(st.getLineNumber()).append(")");
break;
}
buffer.append("] ");
buffer.append(message);
if (LogUtils.DEBUG_STRACK_LEVELS > 0) {
int n = LogUtils.DEBUG_STRACK_LEVELS;
level--;
while (level < stackTrace.length && 0 < n) {
final StackTraceElement st = stackTrace[level++];
n--;
buffer.append("\n ").append(st);
}
}
return buffer.toString();
}
/* ======================================================================== */
/**
* OSGi DS Interface.
*
* @param server
* the new server to bind to
*/
public void bindLogService(LogService server) {
myLogService = server;
}
/**
* OSGi DS Interface.
*
* @param server
* the new server to bind to
*/
public void bindExtendedLogService(ExtendedLogService server) {
myExtendedLogService = server;
}
}