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