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 Paul Hammaant * 009 *****************************************************************************/ 010 package org.picocontainer.gems.monitors; 011 012 import static org.picocontainer.monitors.ComponentMonitorHelper.ctorToString; 013 import static org.picocontainer.monitors.ComponentMonitorHelper.format; 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.IOException; 019 import java.io.ObjectInputStream; 020 import java.io.ObjectOutputStream; 021 import java.io.Serializable; 022 import java.lang.reflect.Constructor; 023 import java.lang.reflect.Member; 024 import java.lang.reflect.Method; 025 026 import org.picocontainer.ComponentAdapter; 027 import org.picocontainer.ComponentMonitor; 028 import org.picocontainer.MutablePicoContainer; 029 import org.picocontainer.PicoContainer; 030 import org.picocontainer.Injector; 031 import org.picocontainer.Behavior; 032 import org.picocontainer.monitors.ComponentMonitorHelper; 033 import org.picocontainer.monitors.NullComponentMonitor; 034 import org.slf4j.Logger; 035 import org.slf4j.LoggerFactory; 036 037 /** 038 * A {@link org.picocontainer.ComponentMonitor} which writes to a Slf4j 039 * {@link org.slf4j.Logger} instance. The Logger instance can either be injected 040 * or, if not set, the {@link org.slf4j.LoggerFactory} will be used to retrieve 041 * it at every invocation of the monitor. 042 * 043 * @author Paul Hammant 044 * @author Mauro Talevi 045 * @author Michael Rimov 046 */ 047 @SuppressWarnings("serial") 048 public class Slf4jComponentMonitor implements ComponentMonitor, Serializable { 049 050 051 /** 052 * Slf4j Logger. 053 */ 054 private transient Logger logger; 055 056 /** 057 * Delegate Monitor. 058 */ 059 private final ComponentMonitor delegate; 060 061 /** 062 * Creates a Slf4jComponentMonitor with no Logger instance set. The 063 * {@link org.slf4j.LoggerFactory} will be used to retrieve the Logger 064 * instance at every invocation of the monitor. 065 */ 066 public Slf4jComponentMonitor() { 067 delegate = new NullComponentMonitor(); 068 069 } 070 071 /** 072 * Creates a Slf4jComponentMonitor with a given Logger instance class. The 073 * class name is used to retrieve the Logger instance. 074 * 075 * @param loggerClass 076 * the class of the Logger 077 */ 078 public Slf4jComponentMonitor(final Class<?> loggerClass) { 079 this(loggerClass.getName()); 080 } 081 082 /** 083 * Creates a Slf4jComponentMonitor with a given Logger instance name. It 084 * uses the {@link org.slf4j.LoggerFactory} to create the Logger instance. 085 * 086 * @param loggerName 087 * the name of the Log 088 */ 089 public Slf4jComponentMonitor(final String loggerName) { 090 this(LoggerFactory.getLogger(loggerName)); 091 } 092 093 /** 094 * Creates a Slf4jComponentMonitor with a given Logger instance 095 * 096 * @param logger 097 * the Logger to write to 098 */ 099 public Slf4jComponentMonitor(final Logger logger) { 100 this(); 101 this.logger = logger; 102 } 103 104 /** 105 * Creates a Slf4jComponentMonitor with a given Logger instance class. The 106 * class name is used to retrieve the Logger instance. 107 * 108 * @param loggerClass 109 * the class of the Logger 110 * @param delegate 111 * the delegate 112 */ 113 public Slf4jComponentMonitor(final Class<?> loggerClass, 114 final ComponentMonitor delegate) { 115 this(loggerClass.getName(), delegate); 116 } 117 118 /** 119 * Creates a Slf4jComponentMonitor with a given Logger instance name. It 120 * uses the {@link org.slf4j.LoggerFactory} to create the Logger instance. 121 * 122 * @param loggerName 123 * the name of the Log 124 * @param delegate 125 * the delegate 126 */ 127 public Slf4jComponentMonitor(final String loggerName, 128 final ComponentMonitor delegate) { 129 this(LoggerFactory.getLogger(loggerName), delegate); 130 } 131 132 /** 133 * Creates a Slf4jComponentMonitor with a given Slf4j Logger instance 134 * 135 * @param logger 136 * the Logger to write to 137 * @param delegate 138 * the delegate 139 */ 140 public Slf4jComponentMonitor(final Logger logger, 141 final ComponentMonitor delegate) { 142 this(delegate); 143 this.logger = logger; 144 } 145 146 /** 147 * Similar to default constructor behavior, but this version wraps a 148 * delegate ComponentMonitor. 149 * 150 * @param delegate 151 * The next component monitor in the chain. 152 */ 153 public Slf4jComponentMonitor(final ComponentMonitor delegate) { 154 this.delegate = delegate; 155 } 156 157 /** {@inheritDoc} * */ 158 public <T> Constructor<T> instantiating(final PicoContainer container, 159 final ComponentAdapter<T> componentAdapter, 160 final Constructor<T> constructor) { 161 Logger logger = getLogger(constructor); 162 if (logger.isDebugEnabled()) { 163 logger.debug(format(ComponentMonitorHelper.INSTANTIATING, 164 ctorToString(constructor))); 165 } 166 return delegate.instantiating(container, componentAdapter, constructor); 167 } 168 169 /** {@inheritDoc} * */ 170 public <T> void instantiated(final PicoContainer container, 171 final ComponentAdapter<T> componentAdapter, 172 final Constructor<T> constructor, final Object instantiated, 173 final Object[] parameters, final long duration) { 174 Logger logger = getLogger(constructor); 175 if (logger.isDebugEnabled()) { 176 logger.debug(format(ComponentMonitorHelper.INSTANTIATED, 177 ctorToString(constructor), duration, instantiated 178 .getClass().getName(), parmsToString(parameters))); 179 } 180 delegate.instantiated(container, componentAdapter, constructor, 181 instantiated, parameters, duration); 182 } 183 184 /** {@inheritDoc} * */ 185 public <T> void instantiationFailed(final PicoContainer container, 186 final ComponentAdapter<T> componentAdapter, 187 final Constructor<T> constructor, final Exception cause) { 188 Logger logger = getLogger(constructor); 189 if (logger.isWarnEnabled()) { 190 logger.warn(format(ComponentMonitorHelper.INSTANTIATION_FAILED, 191 ctorToString(constructor), cause.getMessage()), cause); 192 } 193 delegate.instantiationFailed(container, componentAdapter, constructor, 194 cause); 195 } 196 197 /** {@inheritDoc} * */ 198 public Object invoking(final PicoContainer container, 199 final ComponentAdapter<?> componentAdapter, final Member member, 200 final Object instance, Object[] args) { 201 Logger logger = getLogger(member); 202 if (logger.isDebugEnabled()) { 203 logger.debug(format(ComponentMonitorHelper.INVOKING, 204 memberToString(member), instance)); 205 } 206 return delegate.invoking(container, componentAdapter, member, instance, args); 207 } 208 209 /** {@inheritDoc} * */ 210 public void invoked(final PicoContainer container, 211 final ComponentAdapter<?> componentAdapter, final Member member, 212 final Object instance, final long duration, Object[] args, Object retVal) { 213 Logger logger = getLogger(member); 214 if (logger.isDebugEnabled()) { 215 logger.debug(format(ComponentMonitorHelper.INVOKED, 216 methodToString(member), instance, duration)); 217 } 218 delegate.invoked(container, componentAdapter, member, instance, 219 duration, args, retVal); 220 } 221 222 /** {@inheritDoc} * */ 223 public void invocationFailed(final Member member, final Object instance, 224 final Exception cause) { 225 Logger logger = getLogger(member); 226 if (logger.isWarnEnabled()) { 227 logger.warn(format(ComponentMonitorHelper.INVOCATION_FAILED, 228 memberToString(member), instance, cause.getMessage()), 229 cause); 230 } 231 delegate.invocationFailed(member, instance, cause); 232 } 233 234 /** {@inheritDoc} * */ 235 public void lifecycleInvocationFailed(final MutablePicoContainer container, 236 final ComponentAdapter<?> componentAdapter, final Method method, 237 final Object instance, final RuntimeException cause) { 238 Logger logger = getLogger(method); 239 if (logger.isWarnEnabled()) { 240 logger.warn(format( 241 ComponentMonitorHelper.LIFECYCLE_INVOCATION_FAILED, 242 methodToString(method), instance, cause.getMessage()), 243 cause); 244 } 245 delegate.lifecycleInvocationFailed(container, componentAdapter, method, 246 instance, cause); 247 } 248 249 /** {@inheritDoc} * */ 250 public Object noComponentFound(final MutablePicoContainer container, 251 final Object componentKey) { 252 Logger logger = this.logger != null ? this.logger : LoggerFactory 253 .getLogger(ComponentMonitor.class); 254 if (logger.isWarnEnabled()) { 255 logger.warn(format(ComponentMonitorHelper.NO_COMPONENT, 256 componentKey)); 257 } 258 return delegate.noComponentFound(container, componentKey); 259 260 } 261 262 /** {@inheritDoc} */ 263 public Injector newInjector( 264 final Injector injector) { 265 return delegate.newInjector(injector); 266 } 267 268 /** {@inheritDoc} **/ 269 public Behavior newBehavior(Behavior behavior) { 270 return delegate.newBehavior(behavior); 271 } 272 273 274 /** 275 * Retrieves the logger factory based class being instantiated. 276 * 277 * @param member 278 * Source method/constructor, etc being instantiated. 279 * @return an appropriate logger instance for this callback. 280 */ 281 protected Logger getLogger(final Member member) { 282 if (logger != null) { 283 return logger; 284 } 285 return LoggerFactory.getLogger(member.getDeclaringClass()); 286 } 287 288 /** 289 * Serializes the monitor. 290 * 291 * @param oos 292 * object output stream. 293 * @throws IOException 294 */ 295 private void writeObject(final ObjectOutputStream oos) throws IOException { 296 oos.defaultWriteObject(); 297 if (logger != null) { 298 oos.writeBoolean(true); 299 oos.writeUTF(logger.getName()); 300 } else { 301 oos.writeBoolean(false); 302 } 303 } 304 305 /** 306 * Manually creates a new logger instance if it was defined earlier. 307 * 308 * @param ois 309 * @throws IOException 310 * @throws ClassNotFoundException 311 */ 312 private void readObject(final ObjectInputStream ois) throws IOException, 313 ClassNotFoundException { 314 ois.defaultReadObject(); 315 boolean hasDefaultLogger = ois.readBoolean(); 316 if (hasDefaultLogger) { 317 String defaultLoggerCategory = ois.readUTF(); 318 assert defaultLoggerCategory != null : "Serialization indicated default logger, " 319 + "but no logger category found in input stream."; 320 logger = LoggerFactory.getLogger(defaultLoggerCategory); 321 } 322 } 323 }