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 }