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