/*
* Copyright 2011 Blazebit
*/
package com.blazebit.cdi.logging;
import com.blazebit.cdi.logging.annotation.Logging;
import com.blazebit.exception.ExceptionUtils;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
/**
* This interceptor logs invocations of methods, class name, method name,
* parameter values, return values, thrown exceptions, through the standard java
* logging API. It skips the logging when debug is not enabled for the
* intercepted class.
*
* <code>
* public class Bean implements Serializable {
*
* @Logging public String example(String value) throws Exception{ if(value !=
* null && value.isEmpty()){ throw new Exception("Empty String given");
* }
*
* return value; } } </code>
*
* Invocation: bean.example("test"); Log result: Bean.example(test)
* called Bean.example() returned test
*
* Invocation: bean.example(null); Log result: Bean.example(null)
* called Bean.example() returned null
*
* Invocation: bean.example(""); Log result: Bean.example("") called
* Bean.example() returned null Bean.example() throwed Exception with
* the message: Empty String given
*
* @author Christian Beikov
* @since 0.1.2
* @see Logging
*/
@Interceptor
@Logging
public class LoggingInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
@AroundInvoke
public Object errorLogging(InvocationContext ic) throws Exception {
// Retrieve the logger for the intercepted class
Logger log = Logger.getLogger(ic.getTarget().getClass().getName());
// Skip logging and directly proceed when debug is not enabled for
// the intercepted class
if (!log.isLoggable(Level.FINE)) {
return ic.proceed();
}
Object ret = null;
String className = ic.getMethod().getDeclaringClass().getSimpleName();
String methodName = ic.getMethod().getName();
Class<?> methodReturnType = ic.getMethod().getReturnType();
StringBuilder sb = new StringBuilder();
Throwable t = null;
Object[] o = ic.getParameters();
sb.append(className).append(methodName).append("(");
// This is a simple string join operation, like in apache StringUtils
// with the exception, that null is printed as the string "null"
for (int i = 0; i < o.length; i++) {
if (i != 0) {
sb.append(", ");
}
if (o[i] == null) {
sb.append("null");
} else {
sb.append(o[i].toString());
}
}
log.log(Level.FINE, sb.append(")").append(" called").toString());
try {
ret = ic.proceed();
} catch (Throwable t1) {
t = t1;
// Check if the throwable is an instance of
// InvocationTargetException
// and if so, unwrap the cause. OWB did not unwrap exceptions that
// have been thrown in decorators in some versions so we need to do
// this to be able to log the right exception
t = ExceptionUtils.unwrap(t, InvocationTargetException.class);
}
// Reuse the StringBuilder
sb.setLength(0);
sb.append(className).append(methodName).append("()");
if (t == null) {
if (void.class.equals(methodReturnType)) {
sb.append(" exited");
} else {
sb.append(" returned ");
// Append the return value to the log entry
if (ret == null) {
sb.append("null");
} else {
sb.append(ret.toString());
}
}
} else {
sb.append(" throwed ");
sb.append(t.getClass().getSimpleName()).append(
"() with the message: ");
// Append the exception message if there is one
if (t.getMessage() != null && !t.getMessage().isEmpty()) {
sb.append(t.getMessage());
}
}
log.log(Level.FINE, sb.toString());
if (t != null) {
// Cast to or wrap the
// throwable into a new exception and rethrow it
if (t instanceof Exception) {
throw (Exception) t;
}
throw new Exception(t);
}
return ret;
}
}