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 Mauro Talevi *
009 *****************************************************************************/
010
011 package org.picocontainer.gems.monitors;
012
013 import static org.picocontainer.monitors.ComponentMonitorHelper.ctorToString;
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.Serializable;
019 import java.lang.reflect.Constructor;
020 import java.lang.reflect.Member;
021 import java.lang.reflect.Method;
022
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025 import org.picocontainer.ComponentAdapter;
026 import org.picocontainer.ComponentMonitor;
027 import org.picocontainer.MutablePicoContainer;
028 import org.picocontainer.PicoContainer;
029 import org.picocontainer.Injector;
030 import org.picocontainer.Behavior;
031 import org.picocontainer.monitors.ComponentMonitorHelper;
032 import org.picocontainer.monitors.NullComponentMonitor;
033
034
035 /**
036 * A {@link ComponentMonitor} which writes to a Commons Logging {@link Log Log} instance.
037 * The Log instance can either be injected or, if not set, the {@link LogFactory LogFactory}
038 * will be used to retrieve it at every invocation of the monitor.
039 * <h4>Note on Serialization</h4>
040 * <p>Commons Logging does <em>not</em> guarantee Serialization. It is supported when using Log4j
041 * as a back end, but you should write a test case to determine if your particular logger implementation
042 * is supported if you plan on serializing this ComponentMonitor.</p>
043 *
044 * @author Paul Hammant
045 * @author Mauro Talevi
046 */
047 @SuppressWarnings("serial")
048 public class CommonsLoggingComponentMonitor implements ComponentMonitor, Serializable {
049
050
051 /**
052 * Commons Logger.
053 */
054 private Log log;
055
056
057 /**
058 * Delegate for component monitor chains.
059 */
060 private final ComponentMonitor delegate;
061
062 /**
063 * Creates a CommonsLoggingComponentMonitor with no Log instance set.
064 * The {@link LogFactory LogFactory} will be used to retrieve the Log instance
065 * at every invocation of the monitor.
066 */
067 public CommonsLoggingComponentMonitor() {
068 delegate = new NullComponentMonitor();
069 }
070
071 /**
072 * Creates a CommonsLoggingComponentMonitor with a given Log instance class.
073 * The class name is used to retrieve the Log instance.
074 *
075 * @param logClass the class of the Log
076 */
077 public CommonsLoggingComponentMonitor(final Class<?> logClass) {
078 this(logClass.getName());
079 }
080
081 /**
082 * Creates a CommonsLoggingComponentMonitor with a given Log instance name. It uses the
083 * {@link LogFactory LogFactory} to create the Log instance.
084 *
085 * @param logName the name of the Log
086 */
087 public CommonsLoggingComponentMonitor(final String logName) {
088 this(LogFactory.getLog(logName));
089 }
090
091 /**
092 * Creates a CommonsLoggingComponentMonitor with a given Log instance
093 * @param log the Log to write to
094 */
095 public CommonsLoggingComponentMonitor(final Log log) {
096 this();
097 this.log = log;
098 }
099
100 /**
101 * Creates a CommonsLoggingComponentMonitor with a given Log instance class.
102 * The class name is used to retrieve the Log instance.
103 *
104 * @param logClass the class of the Log
105 * @param delegate the delegate
106 */
107 public CommonsLoggingComponentMonitor(final Class<?> logClass, final ComponentMonitor delegate) {
108 this(logClass.getName(), delegate);
109 }
110
111 /**
112 * Creates a CommonsLoggingComponentMonitor with a given Log instance name. It uses the
113 * {@link LogFactory LogFactory} to create the Log instance.
114 *
115 * @param logName the name of the Log
116 * @param delegate the delegate
117 */
118 public CommonsLoggingComponentMonitor(final String logName, final ComponentMonitor delegate) {
119 this(LogFactory.getLog(logName), delegate);
120 }
121
122 /**
123 * Creates a CommonsLoggingComponentMonitor with a given Log instance.
124 * @param log the Log with which to write events.
125 * @param delegate the delegate
126 */
127 public CommonsLoggingComponentMonitor(final Log log, final ComponentMonitor delegate) {
128 this.log = log;
129 this.delegate = delegate;
130 }
131
132
133 /** {@inheritDoc} **/
134 public <T> Constructor<T> instantiating(final PicoContainer container, final ComponentAdapter<T> componentAdapter,
135 final Constructor<T> constructor
136 ) {
137 Log log = getLog(constructor);
138 if (log.isDebugEnabled()) {
139 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INSTANTIATING, ctorToString(constructor)));
140 }
141 return delegate.instantiating(container, componentAdapter, constructor);
142 }
143
144 /** {@inheritDoc} **/
145 public <T> void instantiated(final PicoContainer container, final ComponentAdapter<T> componentAdapter,
146 final Constructor<T> constructor,
147 final Object instantiated,
148 final Object[] parameters,
149 final long duration) {
150 Log log = getLog(constructor);
151 if (log.isDebugEnabled()) {
152 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INSTANTIATED, ctorToString(constructor), duration, instantiated.getClass().getName(), parmsToString(parameters)));
153 }
154 delegate.instantiated(container, componentAdapter, constructor, instantiated, parameters, duration);
155 }
156
157 /** {@inheritDoc} **/
158 public <T> void instantiationFailed(final PicoContainer container,
159 final ComponentAdapter<T> componentAdapter,
160 final Constructor<T> constructor,
161 final Exception cause) {
162 Log log = getLog(constructor);
163 if (log.isWarnEnabled()) {
164 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.INSTANTIATION_FAILED, ctorToString(constructor), cause.getMessage()), cause);
165 }
166 delegate.instantiationFailed(container, componentAdapter, constructor, cause);
167 }
168
169 /** {@inheritDoc} **/
170 public Object invoking(final PicoContainer container,
171 final ComponentAdapter<?> componentAdapter,
172 final Member member,
173 final Object instance,
174 final Object[] args) {
175 Log log = getLog(member);
176 if (log.isDebugEnabled()) {
177 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INVOKING, memberToString(member), instance));
178 }
179 return delegate.invoking(container, componentAdapter, member, instance, args);
180 }
181
182 /** {@inheritDoc} **/
183 public void invoked(final PicoContainer container,
184 final ComponentAdapter<?> componentAdapter,
185 final Member member,
186 final Object instance,
187 final long duration,
188 final Object[] args,
189 final Object retVal) {
190 Log log = getLog(member);
191 if (log.isDebugEnabled()) {
192 log.debug(ComponentMonitorHelper.format(ComponentMonitorHelper.INVOKED, methodToString(member), instance, duration));
193 }
194 delegate.invoked(container, componentAdapter, member, instance, duration, args, retVal);
195 }
196
197 /** {@inheritDoc} **/
198 public void invocationFailed(final Member member, final Object instance, final Exception cause) {
199 Log log = getLog(member);
200 if (log.isWarnEnabled()) {
201 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.INVOCATION_FAILED, memberToString(member), instance, cause.getMessage()), cause);
202 }
203 delegate.invocationFailed(member, instance, cause);
204 }
205
206 /** {@inheritDoc} **/
207 public void lifecycleInvocationFailed(final MutablePicoContainer container,
208 final ComponentAdapter<?> componentAdapter, final Method method,
209 final Object instance,
210 final RuntimeException cause) {
211 Log log = getLog(method);
212 if (log.isWarnEnabled()) {
213 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.LIFECYCLE_INVOCATION_FAILED, methodToString(method), instance, cause.getMessage()), cause);
214 }
215 delegate.lifecycleInvocationFailed(container, componentAdapter, method, instance, cause);
216 }
217
218 /** {@inheritDoc} **/
219 public Object noComponentFound(final MutablePicoContainer container, final Object componentKey) {
220 Log log = this.log != null ? this.log : LogFactory.getLog(ComponentMonitor.class);
221 if (log.isWarnEnabled()) {
222 log.warn(ComponentMonitorHelper.format(ComponentMonitorHelper.NO_COMPONENT, componentKey));
223 }
224 return delegate.noComponentFound(container, componentKey);
225 }
226
227 /** {@inheritDoc} **/
228 public Injector newInjector(final Injector injector) {
229 return delegate.newInjector(injector);
230 }
231
232 /** {@inheritDoc} **/
233 public Behavior newBehavior(Behavior behavior) {
234 return delegate.newBehavior(behavior);
235 }
236
237 /**
238 * Retrieves the logger appropriate for the calling member's class.
239 * @param member constructor/method/field who's callback is required.
240 * @return the Commons logging instance.
241 */
242 protected Log getLog(final Member member) {
243 if ( log != null ){
244 return log;
245 }
246 return LogFactory.getLog(member.getDeclaringClass());
247 }
248
249
250 }