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