001// Copyright 2006, 2007, 2008, 2011 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.ioc.internal.services; 016 017import org.apache.tapestry5.ioc.services.ExceptionTracker; 018import org.apache.tapestry5.plastic.MethodInvocation; 019import org.slf4j.Logger; 020 021import java.util.Iterator; 022 023import static java.lang.String.format; 024 025/** 026 * Used by {@link org.apache.tapestry5.ioc.internal.services.LoggingDecoratorImpl} to delegate out logging behavior to a 027 * separate object. 028 */ 029public final class MethodLogger 030{ 031 private static final int BUFFER_SIZE = 200; 032 033 private static final String ENTER = "ENTER"; 034 035 private static final String EXIT = " EXIT"; 036 037 private static final String FAIL = " FAIL"; 038 039 private final Logger logger; 040 041 private final ExceptionTracker exceptionTracker; 042 043 public MethodLogger(Logger logger, ExceptionTracker exceptionTracker) 044 { 045 this.logger = logger; 046 this.exceptionTracker = exceptionTracker; 047 } 048 049 public boolean isDebugEnabled() 050 { 051 return logger.isDebugEnabled(); 052 } 053 054 /** 055 * Invoked when a method is first entered 056 * 057 * @param invocation identifies method invoked as well as parameters passed to method 058 */ 059 public void entry(MethodInvocation invocation) 060 { 061 StringBuilder buffer = new StringBuilder(BUFFER_SIZE); 062 063 buffer.append(format("[%s] %s(", ENTER, invocation.getMethod().getName())); 064 065 for (int i = 0; i < invocation.getMethod().getParameterTypes().length; i++) 066 { 067 if (i > 0) buffer.append(", "); 068 069 convert(buffer, invocation.getParameter(i)); 070 } 071 072 buffer.append(')'); 073 074 logger.debug(buffer.toString()); 075 } 076 077 private void convert(StringBuilder buffer, Object object) 078 { 079 if (object == null) 080 { 081 buffer.append("null"); 082 return; 083 } 084 085 // Minimal, alas: Doesn't handle embedded quotes and other 086 // characters. Really want to convert the string back to what it 087 // would look like as source code. 088 089 if (object instanceof String) 090 { 091 buffer.append("\""); 092 buffer.append(object.toString()); 093 buffer.append("\""); 094 return; 095 } 096 097 if (object instanceof Object[]) 098 { 099 Object[] values = (Object[]) object; 100 buffer.append('{'); 101 102 for (int i = 0; i < values.length; i++) 103 { 104 if (i > 0) buffer.append(", "); 105 106 convert(buffer, values[i]); 107 } 108 109 buffer.append('}'); 110 return; 111 } 112 113 if (object instanceof Iterable) 114 { 115 Iterable itr = (Iterable) object; 116 boolean first = true; 117 118 buffer.append('['); 119 Iterator i = itr.iterator(); 120 while (i.hasNext()) 121 { 122 if (!first) buffer.append(", "); 123 124 convert(buffer, i.next()); 125 first = false; 126 } 127 buffer.append(']'); 128 return; 129 } 130 131 // Might need to add a few more, for things like character values ... 132 133 buffer.append(object.toString()); 134 } 135 136 /** 137 * Invoked when a method exits (possibly returning a value). 138 * 139 * @param invocation identifies method invocation and result value 140 */ 141 public void exit(MethodInvocation invocation) 142 { 143 StringBuilder buffer = new StringBuilder(BUFFER_SIZE); 144 145 buffer.append(format("[%s] %s", EXIT, invocation.getMethod().getName())); 146 147 if (invocation.getMethod().getReturnType() != void.class) 148 { 149 buffer.append(" ["); 150 convert(buffer, invocation.getReturnValue()); 151 buffer.append(']'); 152 } 153 154 logger.debug(buffer.toString()); 155 } 156 157 /** 158 * Invoked when method invocation instead throws an exception. 159 * 160 * @param invocation identifies method invocation which failed 161 * @param t exception throws by method invocation 162 */ 163 public void fail(MethodInvocation invocation, Throwable t) 164 { 165 logger.debug( 166 format("[%s] %s -- %s", FAIL, 167 invocation.getMethod().getName(), 168 t.getClass().getName()), 169 exceptionTracker.exceptionLogged(t) ? null : t); 170 } 171}