001 /***************************************************************************** 002 * Copyright (C) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Original code by Mauro Talevi * 009 *****************************************************************************/ 010 011 package org.picocontainer.gems.monitors; 012 013 import static org.picocontainer.monitors.ComponentMonitorHelper.ctorToString; 014 import static org.picocontainer.monitors.ComponentMonitorHelper.memberToString; 015 import static org.picocontainer.monitors.ComponentMonitorHelper.methodToString; 016 import static org.picocontainer.monitors.ComponentMonitorHelper.parmsToString; 017 018 import java.io.Serializable; 019 import java.lang.reflect.Constructor; 020 import java.lang.reflect.Member; 021 import java.lang.reflect.Method; 022 023 import org.apache.commons.logging.Log; 024 import org.apache.commons.logging.LogFactory; 025 import org.picocontainer.ComponentAdapter; 026 import org.picocontainer.ComponentMonitor; 027 import org.picocontainer.MutablePicoContainer; 028 import org.picocontainer.PicoContainer; 029 import org.picocontainer.Injector; 030 import org.picocontainer.Behavior; 031 import org.picocontainer.monitors.ComponentMonitorHelper; 032 import org.picocontainer.monitors.NullComponentMonitor; 033 034 035 /** 036 * A {@link ComponentMonitor} which writes to a Commons Logging {@link Log Log} instance. 037 * The Log instance can either be injected or, if not set, the {@link LogFactory LogFactory} 038 * will be used to retrieve it at every invocation of the monitor. 039 * <h4>Note on Serialization</h4> 040 * <p>Commons Logging does <em>not</em> guarantee Serialization. It is supported when using Log4j 041 * as a back end, but you should write a test case to determine if your particular logger implementation 042 * is supported if you plan on serializing this ComponentMonitor.</p> 043 * 044 * @author Paul Hammant 045 * @author Mauro Talevi 046 */ 047 @SuppressWarnings("serial") 048 public class CommonsLoggingComponentMonitor implements ComponentMonitor, Serializable { 049 050 051 /** 052 * Commons Logger. 053 */ 054 private Log log; 055 056 057 /** 058 * Delegate for component monitor chains. 059 */ 060 private final ComponentMonitor delegate; 061 062 /** 063 * Creates a CommonsLoggingComponentMonitor with no Log instance set. 064 * The {@link LogFactory LogFactory} will be used to retrieve the Log instance 065 * at every invocation of the monitor. 066 */ 067 public CommonsLoggingComponentMonitor() { 068 delegate = new NullComponentMonitor(); 069 } 070 071 /** 072 * Creates a CommonsLoggingComponentMonitor with a given Log instance class. 073 * The class name is used to retrieve the Log instance. 074 * 075 * @param logClass the class of the Log 076 */ 077 public CommonsLoggingComponentMonitor(final Class<?> logClass) { 078 this(logClass.getName()); 079 } 080 081 /** 082 * Creates a CommonsLoggingComponentMonitor with a given Log instance name. It uses the 083 * {@link LogFactory LogFactory} to create the Log instance. 084 * 085 * @param logName the name of the Log 086 */ 087 public CommonsLoggingComponentMonitor(final String logName) { 088 this(LogFactory.getLog(logName)); 089 } 090 091 /** 092 * Creates a CommonsLoggingComponentMonitor with a given Log instance 093 * @param log the Log to write to 094 */ 095 public CommonsLoggingComponentMonitor(final Log log) { 096 this(); 097 this.log = log; 098 } 099 100 /** 101 * Creates a CommonsLoggingComponentMonitor with a given Log instance class. 102 * The class name is used to retrieve the Log instance. 103 * 104 * @param logClass the class of the Log 105 * @param delegate the delegate 106 */ 107 public CommonsLoggingComponentMonitor(final Class<?> logClass, final ComponentMonitor delegate) { 108 this(logClass.getName(), delegate); 109 } 110 111 /** 112 * Creates a CommonsLoggingComponentMonitor with a given Log instance name. It uses the 113 * {@link LogFactory LogFactory} to create the Log instance. 114 * 115 * @param logName the name of the Log 116 * @param delegate the delegate 117 */ 118 public CommonsLoggingComponentMonitor(final String logName, final ComponentMonitor delegate) { 119 this(LogFactory.getLog(logName), delegate); 120 } 121 122 /** 123 * Creates a CommonsLoggingComponentMonitor with a given Log instance. 124 * @param log the Log with which to write events. 125 * @param delegate the delegate 126 */ 127 public CommonsLoggingComponentMonitor(final Log log, final ComponentMonitor delegate) { 128 this.log = log; 129 this.delegate = delegate; 130 } 131 132 133 /** {@inheritDoc} **/ 134 public <T> Constructor<T> instantiating(final PicoContainer container, final ComponentAdapter<T> componentAdapter, 135 final Constructor<T> constructor 136 ) { 137 Log log = getLog(constructor); 138 if (log.isDebugEnabled()) { 139 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INSTANTIATING, ctorToString(constructor))); 140 } 141 return delegate.instantiating(container, componentAdapter, constructor); 142 } 143 144 /** {@inheritDoc} **/ 145 public <T> void instantiated(final PicoContainer container, final ComponentAdapter<T> componentAdapter, 146 final Constructor<T> constructor, 147 final Object instantiated, 148 final Object[] parameters, 149 final long duration) { 150 Log log = getLog(constructor); 151 if (log.isDebugEnabled()) { 152 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INSTANTIATED, ctorToString(constructor), duration, instantiated.getClass().getName(), parmsToString(parameters))); 153 } 154 delegate.instantiated(container, componentAdapter, constructor, instantiated, parameters, duration); 155 } 156 157 /** {@inheritDoc} **/ 158 public <T> void instantiationFailed(final PicoContainer container, 159 final ComponentAdapter<T> componentAdapter, 160 final Constructor<T> constructor, 161 final Exception cause) { 162 Log log = getLog(constructor); 163 if (log.isWarnEnabled()) { 164 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.INSTANTIATION_FAILED, ctorToString(constructor), cause.getMessage()), cause); 165 } 166 delegate.instantiationFailed(container, componentAdapter, constructor, cause); 167 } 168 169 /** {@inheritDoc} **/ 170 public Object invoking(final PicoContainer container, 171 final ComponentAdapter<?> componentAdapter, 172 final Member member, 173 final Object instance, 174 final Object[] args) { 175 Log log = getLog(member); 176 if (log.isDebugEnabled()) { 177 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INVOKING, memberToString(member), instance)); 178 } 179 return delegate.invoking(container, componentAdapter, member, instance, args); 180 } 181 182 /** {@inheritDoc} **/ 183 public void invoked(final PicoContainer container, 184 final ComponentAdapter<?> componentAdapter, 185 final Member member, 186 final Object instance, 187 final long duration, 188 final Object[] args, 189 final Object retVal) { 190 Log log = getLog(member); 191 if (log.isDebugEnabled()) { 192 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INVOKED, methodToString(member), instance, duration)); 193 } 194 delegate.invoked(container, componentAdapter, member, instance, duration, args, retVal); 195 } 196 197 /** {@inheritDoc} **/ 198 public void invocationFailed(final Member member, final Object instance, final Exception cause) { 199 Log log = getLog(member); 200 if (log.isWarnEnabled()) { 201 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.INVOCATION_FAILED, memberToString(member), instance, cause.getMessage()), cause); 202 } 203 delegate.invocationFailed(member, instance, cause); 204 } 205 206 /** {@inheritDoc} **/ 207 public void lifecycleInvocationFailed(final MutablePicoContainer container, 208 final ComponentAdapter<?> componentAdapter, final Method method, 209 final Object instance, 210 final RuntimeException cause) { 211 Log log = getLog(method); 212 if (log.isWarnEnabled()) { 213 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.LIFECYCLE_INVOCATION_FAILED, methodToString(method), instance, cause.getMessage()), cause); 214 } 215 delegate.lifecycleInvocationFailed(container, componentAdapter, method, instance, cause); 216 } 217 218 /** {@inheritDoc} **/ 219 public Object noComponentFound(final MutablePicoContainer container, final Object componentKey) { 220 Log log = this.log != null ? this.log : LogFactory.getLog(ComponentMonitor.class); 221 if (log.isWarnEnabled()) { 222 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.NO_COMPONENT, componentKey)); 223 } 224 return delegate.noComponentFound(container, componentKey); 225 } 226 227 /** {@inheritDoc} **/ 228 public Injector newInjector(final Injector injector) { 229 return delegate.newInjector(injector); 230 } 231 232 /** {@inheritDoc} **/ 233 public Behavior newBehavior(Behavior behavior) { 234 return delegate.newBehavior(behavior); 235 } 236 237 /** 238 * Retrieves the logger appropriate for the calling member's class. 239 * @param member constructor/method/field who's callback is required. 240 * @return the Commons logging instance. 241 */ 242 protected Log getLog(final Member member) { 243 if ( log != null ){ 244 return log; 245 } 246 return LogFactory.getLog(member.getDeclaringClass()); 247 } 248 249 250 }