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 void invoking(final PicoContainer container,
177 final ComponentAdapter<?> componentAdapter,
178 final Member member,
179 final Object instance) {
180 Logger logger = getLogger(member);
181 if (logger.isDebugEnabled()) {
182 logger.debug(format(ComponentMonitorHelper.INVOKING, memberToString(member), instance));
183 }
184 delegate.invoking(container, componentAdapter, member, instance);
185 }
186
187 /** {@inheritDoc} **/
188 public void invoked(final PicoContainer container,
189 final ComponentAdapter<?> componentAdapter,
190 final Method method,
191 final Object instance,
192 final long duration) {
193 Logger logger = getLogger(method);
194 if (logger.isDebugEnabled()) {
195 logger.debug(format(ComponentMonitorHelper.INVOKED, methodToString(method), instance, duration));
196 }
197 delegate.invoked(container, componentAdapter, method, instance, duration);
198 }
199
200 /** {@inheritDoc} **/
201 public void invocationFailed(final Member member, final Object instance, final Exception cause) {
202 Logger logger = getLogger(member);
203 if (logger.isEnabledFor(Priority.WARN)) {
204 logger.warn(format(ComponentMonitorHelper.INVOCATION_FAILED, memberToString(member), instance, cause.getMessage()), cause);
205 }
206 delegate.invocationFailed(member, instance, cause);
207 }
208
209 /** {@inheritDoc} **/
210 public void lifecycleInvocationFailed(final MutablePicoContainer container,
211 final ComponentAdapter<?> componentAdapter, final Method method,
212 final Object instance,
213 final RuntimeException cause) {
214 Logger logger = getLogger(method);
215 if (logger.isEnabledFor(Priority.WARN)) {
216 logger.warn(format(ComponentMonitorHelper.LIFECYCLE_INVOCATION_FAILED, methodToString(method), instance, cause.getMessage()), cause);
217 }
218 delegate.lifecycleInvocationFailed(container, componentAdapter, method, instance, cause);
219 }
220
221 /** {@inheritDoc} **/
222 public Object noComponentFound(final MutablePicoContainer container, final Object componentKey) {
223 Logger logger = this.logger != null ? this.logger : LogManager.getLogger(ComponentMonitor.class);
224 if (logger.isEnabledFor(Priority.WARN)) {
225 logger.warn(format(ComponentMonitorHelper.NO_COMPONENT, componentKey));
226 }
227 return delegate.noComponentFound(container, componentKey);
228
229 }
230
231 /** {@inheritDoc} */
232 public Injector newInjector(final Injector injector) {
233 return delegate.newInjector(injector);
234 }
235
236 /** {@inheritDoc} **/
237 public Behavior newBehavior(Behavior behavior) {
238 return delegate.newBehavior(behavior);
239 }
240
241 protected Logger getLogger(final Member member) {
242 if ( logger != null ){
243 return logger;
244 }
245 return LogManager.getLogger(member.getDeclaringClass());
246 }
247
248
249 /**
250 * Serializes the monitor.
251 * @param oos object output stream.
252 * @throws IOException
253 */
254 private void writeObject(final ObjectOutputStream oos) throws IOException {
255 oos.defaultWriteObject();
256 if (logger != null) {
257 oos.writeBoolean(true);
258 oos.writeUTF(logger.getName());
259 } else {
260 oos.writeBoolean(false);
261 }
262 }
263
264 /**
265 * Manually creates a new logger instance if it was defined earlier.
266 * @param ois
267 * @throws IOException
268 * @throws ClassNotFoundException
269 */
270 private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
271 ois.defaultReadObject();
272 boolean hasDefaultLogger = ois.readBoolean();
273 if (hasDefaultLogger) {
274 String defaultLoggerCategory = ois.readUTF();
275 assert defaultLoggerCategory != null : "Serialization indicated default logger, "
276 +"but no logger category found in input stream.";
277 logger = LogManager.getLogger(defaultLoggerCategory);
278 }
279 }
280
281 }