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
011package org.picocontainer.gems.monitors;
012
013import static org.picocontainer.monitors.ComponentMonitorHelper.ctorToString;
014import static org.picocontainer.monitors.ComponentMonitorHelper.memberToString;
015import static org.picocontainer.monitors.ComponentMonitorHelper.methodToString;
016import static org.picocontainer.monitors.ComponentMonitorHelper.parmsToString;
017
018import java.io.Serializable;
019import java.lang.reflect.Constructor;
020import java.lang.reflect.Member;
021import java.lang.reflect.Method;
022
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.picocontainer.ComponentAdapter;
026import org.picocontainer.ComponentMonitor;
027import org.picocontainer.MutablePicoContainer;
028import org.picocontainer.PicoContainer;
029import org.picocontainer.Injector;
030import org.picocontainer.Behavior;
031import org.picocontainer.monitors.ComponentMonitorHelper;
032import 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")
048public 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 synchronized Log getLog(final Member member) {
243        if ( log != null ){
244            return log;
245        } 
246        return LogFactory.getLog(member.getDeclaringClass());
247    }
248
249    
250}