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 }