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