/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.util.reflect;
import java.io.PrintStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import xxl.core.collections.containers.Container;
import xxl.core.cursors.Cursor;
import xxl.core.cursors.MetaDataCursor;
/**
* This class provides a general Logger that can be used
* with every interface. It uses the reflection mechanism that
* was introduced with jdk 1.3. The logger forwards the calls
* to a different instance of the same interface (principle of
* a decorator).
* <p>
* For conveniance, some classes of xxl are directly supported.
*/
public class Logger implements InvocationHandler {
/** Object to log */
private Object delegate;
/** Printstream to write on */
private PrintStream out;
/**
* Produces dynamically a Logger for the specified interface and object and
* returns it.
*
* @param delegate Object to which the calls are delegated.
* @param interfaceName name of the interface
* @param out PrintStream which is used for ouput.
*
* @return returns the Logger created
*/
public static Object newInstance(Object delegate, String interfaceName, PrintStream out) {
try {
Class c = Class.forName(interfaceName);
return Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] { c },
new Logger(delegate, out)
);
}
catch (ClassNotFoundException e) {
return null;
}
}
/**
* Returns a logger for a MetaDataCursor.
*
* @param mdc MetaDataCursor to be logged.
* @param out PrintStream which is used for ouput.
* @return returns a logger for a MetaDataCursor.
*/
public static MetaDataCursor getMetaDataCursorLogger(MetaDataCursor mdc, PrintStream out) {
return (MetaDataCursor) newInstance(mdc,"xxl.core.cursors.MetaDataCursor",out);
}
/**
* Returns a logger for a Cursor.
*
* @param c Cursor to be logged.
* @param out PrintStream which is used for ouput.
* @return returns a logger for a Cursor.
*/
public static Cursor getCursorLogger(Cursor c, PrintStream out) {
return (Cursor) newInstance(c,"xxl.core.cursors.Cursor",out);
}
/**
* Returns a logger for an Iterator.
*
* @param it Iterator to be logged.
* @param out PrintStream which is used for ouput.
* @return returns a logger for a Iterator.
*/
public static Iterator getIteratorLogger(Iterator it, PrintStream out) {
return (Iterator) newInstance(it,"java.util.Iterator",out);
}
/**
* Returns a logger for a Container.
*
* @param container Container to be logged.
* @param out PrintStream which is used for ouput.
* @return returns a logger for a Container.
*/
public static Container getContainerLogger(Container container, PrintStream out) {
return (Container) newInstance(container,"xxl.core.collections.containers.Container",out);
}
/**
* Creates a logger (private!).
*
* @param delegate Object to which the calls are delegated.
* @param out PrintStream which is used for ouput.
*/
private Logger(Object delegate, PrintStream out) {
this.delegate = delegate;
this.out = out;
}
/**
* This method is invoked automatically by the proxy. It is
* unusual to call this method directly.
*
* @param proxy the proxy instance that the method was invoked on
* @param meth the Method instance corresponding to the interface method
* invoked on the proxy instance. The declaring class of the Method
* object will be the interface that the method was declared in, which
* may be a superinterface of the proxy interface that the proxy class
* inherits the method through.
* @param args an array of objects containing the values of the arguments passed
* in the method invocation on the proxy instance, or null if interface
* method takes no arguments. Arguments of primitive types are wrapped in
* instances of the appropriate primitive wrapper class, such as
* java.lang.Integer or java.lang.Boolean.
* @return the value to return from the method invocation on the proxy instance.
* If the declared return type of the interface method is a primitive type,
* then the value returned by this method must be an instance of the
* corresponding primitive wrapper class; otherwise, it must be a type
* assignable to the declared return type. If the value returned by this
* method is null and the interface method's return type is primitive, then
* a NullPointerException will be thrown by the method invocation on the
* proxy instance. If the value returned by this method is otherwise not
* compatible with the interface method's declared return type as described
* above, a ClassCastException will be thrown by the method invocation on
* the proxy instance.
* @throws Throwable
*/
public Object invoke(Object proxy, Method meth, Object[] args) throws Throwable {
if (args==null)
out.println("Logger\tbefore\t"+meth.getName()+"\t"+delegate.getClass().getName()+"\tParam:\t0");
else {
out.print("Logger\tbefore\t"+meth.getName()+"\t"+delegate.getClass().getName()+"\tParam:\t0\t"+args.length);
for (int i=0 ; i<args.length ; i++)
out.print("\t"+args[i]);
out.println();
}
// Get stack trace
try {
throw new RuntimeException();
}
catch (Exception e) {
out.print("Logger\ttrace\t");
StackTraceElement st[] = e.getStackTrace();
for (int i=2; i<st.length; i++) {
if (i!=1)
out.print(" \t");
out.print(st[i].getClassName()+"."+st[i].getMethodName()+":"+st[i].getLineNumber());
}
out.println();
}
try {
Object o = meth.invoke(delegate, args);
out.println("Logger\tafter\t"+meth.getName()+"\t"+delegate.getClass().getName()+"\tOutput\t"+o);
return o;
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}