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 }