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