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    }