001 /* 002 * (c) 2003-2005, 2009, 2010 ThoughtWorks Ltd 003 * All rights reserved. 004 * 005 * The software in this package is published under the terms of the BSD 006 * style license a copy of which has been included with this distribution in 007 * the LICENSE.txt file. 008 * 009 * Created on 27-Jul-2004 010 */ 011 package com.thoughtworks.proxy.toys.echo; 012 013 import java.io.PrintWriter; 014 import java.lang.reflect.Method; 015 016 import com.thoughtworks.proxy.ProxyFactory; 017 import com.thoughtworks.proxy.toys.decorate.Decorating; 018 import com.thoughtworks.proxy.toys.decorate.Decorator; 019 020 /** 021 * A {@link com.thoughtworks.proxy.toys.decorate.Decorator} implementation that echoes any invocation to a {@link PrintWriter}. 022 * <p> 023 * The implementation will try to create new proxies for every return value, that can be proxied by the 024 * {@link ProxyFactory} in use. 025 * </p> 026 * 027 * @author Dan North 028 * @author Jörg Schaible 029 * @since 0.1 030 */ 031 public class EchoDecorator<T> extends Decorator<T> { 032 private static final long serialVersionUID = 1L; 033 private final PrintWriter out; 034 private final ProxyFactory factory; 035 036 /** 037 * Construct an EchoingDecorator. 038 * 039 * @param out the {@link PrintWriter} receiving the logs 040 * @param factory the {@link ProxyFactory} to use 041 * @since 0.2 042 */ 043 public EchoDecorator(final PrintWriter out, final ProxyFactory factory) { 044 this.out = out; 045 this.factory = factory; 046 } 047 048 @Override 049 public Object[] beforeMethodStarts(final T proxy, final Method method, final Object[] args) { 050 printMethodCall(method, args); 051 return super.beforeMethodStarts(proxy, method, args); 052 } 053 054 @Override 055 @SuppressWarnings("unchecked") 056 public Object decorateResult(final T proxy, final Method method, final Object[] args, Object result) { 057 Class returnType = method.getReturnType(); 058 printMethodResult(result); 059 if (returnType != Object.class && factory.canProxy(returnType)) { 060 result = Decorating.proxy(result, returnType).visiting(this).build(factory); 061 } else if (result != null && returnType == Object.class && factory.canProxy(result.getClass())) { 062 returnType = result.getClass(); 063 result = Decorating.proxy(result, returnType).visiting(this).build(factory); 064 } 065 return result; 066 } 067 068 @Override 069 public Throwable decorateTargetException( 070 final T proxy, final Method method, final Object[] args, final Throwable cause) { 071 printTargetException(cause); 072 return super.decorateTargetException(proxy, method, args, cause); 073 } 074 075 @Override 076 public Exception decorateInvocationException( 077 final T proxy, final Method method, final Object[] args, final Exception cause) { 078 printInvocationException(cause); 079 return super.decorateInvocationException(proxy, method, args, cause); 080 } 081 082 private void printMethodCall(Method method, Object[] args) { 083 final StringBuilder buf = new StringBuilder("["); 084 buf.append(Thread.currentThread().getName()); 085 buf.append("] "); 086 buf.append(method.getDeclaringClass().getName()); 087 buf.append(".").append(method.getName()); 088 089 if (args == null) { 090 args = new Object[0]; 091 } 092 buf.append("("); 093 for (int i = 0; i < args.length; i++) { 094 buf.append(i == 0 ? "<" : ", <").append(args[i]).append(">"); 095 } 096 buf.append(") "); 097 out.print(buf); 098 out.flush(); 099 } 100 101 private void printMethodResult(final Object result) { 102 final StringBuilder buf = new StringBuilder("--> <"); 103 buf.append(result == null ? "NULL" : result.toString()); 104 buf.append(">"); 105 out.println(buf); 106 out.flush(); 107 } 108 109 private void printTargetException(final Throwable throwable) { 110 final StringBuilder buf = new StringBuilder("throws "); 111 buf.append(throwable.getClass().getName()); 112 buf.append(": "); 113 buf.append(throwable.getMessage()); 114 out.println(buf); 115 out.flush(); 116 } 117 118 private void printInvocationException(final Throwable throwable) { 119 out.print("INTERNAL ERROR, "); 120 printTargetException(throwable); 121 } 122 }