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 Centerline Computers, Inc. *
009 *****************************************************************************/
010
011 package org.picocontainer.gems.containers;
012
013 import java.io.ObjectInputStream;
014 import java.io.ObjectOutputStream;
015 import java.io.Serializable;
016 import java.util.Collection;
017 import java.util.List;
018
019 import org.apache.log4j.Logger;
020 import org.picocontainer.ComponentAdapter;
021 import org.picocontainer.MutablePicoContainer;
022 import org.picocontainer.Parameter;
023 import org.picocontainer.PicoContainer;
024 import org.picocontainer.PicoVerificationException;
025 import org.picocontainer.PicoVisitor;
026
027 /**
028 * Decorates a MutablePicoContainer to provide extensive tracing capabilities
029 * for all function calls into the Picocontainers.
030 * <p>
031 * By default, this class uses <tt>org.picocontainer.PicoContainer</tt> as its
032 * logging category, however, this may be changed by providing the logger in its
033 * alternate constructor.
034 * </p>
035 * <p>
036 * Start and Stop events are logged under <tt>info</tt> priority, as are all
037 * conditions where querying for an object returns a null object (e.g.,
038 * getComponentAdapter(Object) returns null). All other functions use
039 * <tt>debug</tt> priority.
040 * </p>
041 * <p>
042 * If used in nanocontainer, you can add wrap your PicoContainer with the
043 * Log4jTracingContainerDecorator: (Groovy Example)
044 * </p>
045 *
046 * <pre>
047 * pico = builder.container(parent: parent) {
048 * //component(.....)
049 * //And others.
050 * }
051 *
052 * //Wrap the underlying NanoContainer with a Decorated Pico.
053 * pico = new org.picocontainer.gems.containers.Log4jTracingContainerDecorator (pico.getPico())
054 * </pre>
055 *
056 * @author Michael Rimov
057 * @since Version 1.3
058 */
059 public class Log4jTracingContainerDecorator implements MutablePicoContainer, Serializable {
060
061 /**
062 * Wrapped container.
063 */
064 private final MutablePicoContainer delegate;
065
066 /**
067 * Logger instance used for writing events.
068 */
069 private transient Logger logger;
070
071 /**
072 * Default typical wrapper that wraps another MutablePicoContainer.
073 *
074 * @param delegate
075 * Container to be decorated.
076 * @throws NullPointerException
077 * if delegate is null.
078 */
079 public Log4jTracingContainerDecorator(final MutablePicoContainer delegate) {
080 this(delegate, Logger.getLogger(PicoContainer.class));
081 }
082
083 /**
084 * Alternate constructor that allows specification of the Logger to use.
085 *
086 * @param delegate
087 * Container to be decorated.
088 * @param logger
089 * specific Log4j Logger to use.
090 * @throws NullPointerException
091 * if delegate or logger is null.
092 */
093 public Log4jTracingContainerDecorator(final MutablePicoContainer delegate, final Logger logger) {
094 if (delegate == null) {
095 throw new NullPointerException("delegate");
096 }
097
098 if (logger == null) {
099 throw new NullPointerException("logger");
100 }
101
102 this.delegate = delegate;
103 this.logger = logger;
104 }
105
106 /**
107 * Standard message handling for cases when a null object is returned for a
108 * given key.
109 *
110 * @param componentKey
111 * @param target
112 */
113 protected void onKeyDoesntExistInContainer(final Object componentKey, final Logger target) {
114 logger.info("Could not find component " + ((componentKey != null) ? componentKey.toString() : " null ")
115 + " in container or parent container.");
116 }
117
118 /**
119 * {@inheritDoc}
120 *
121 * @param visitor
122 * @see org.picocontainer.PicoContainer#accept(org.picocontainer.PicoVisitor)
123 */
124 public void accept(final PicoVisitor visitor) {
125 if (logger.isDebugEnabled()) {
126 logger.debug("Visiting Container " + delegate + " with visitor " + visitor);
127 }
128 delegate.accept(visitor);
129 }
130
131 /**
132 * {@inheritDoc}
133 *
134 * @param child
135 * @return
136 * @see org.picocontainer.MutablePicoContainer#addChildContainer(org.picocontainer.PicoContainer)
137 */
138 public boolean addChildContainer(final PicoContainer child) {
139 if (logger.isDebugEnabled()) {
140 logger.debug("Adding child container: " + child + " to container " + delegate);
141 }
142 return delegate.addChildContainer(child);
143 }
144
145 /**
146 * {@inheritDoc}
147 *
148 * @see org.picocontainer.Disposable#dispose()
149 */
150 public void dispose() {
151 if (logger.isDebugEnabled()) {
152 logger.debug("Disposing container " + delegate);
153 }
154 delegate.dispose();
155 }
156
157 /**
158 * {@inheritDoc}
159 *
160 * @param componentKey
161 * @return
162 * @see org.picocontainer.PicoContainer#getComponentAdapter(java.lang.Object)
163 */
164 public ComponentAdapter getComponentAdapter(final Object componentKey) {
165 if (logger.isDebugEnabled()) {
166 logger.debug("Locating component adapter with key " + componentKey);
167 }
168
169 ComponentAdapter adapter = delegate.getComponentAdapter(componentKey);
170 if (adapter == null) {
171 onKeyDoesntExistInContainer(componentKey, logger);
172 }
173 return adapter;
174 }
175
176 /**
177 * {@inheritDoc}
178 *
179 * @param componentType
180 * @return ComponentAdapter or null.
181 * @see org.picocontainer.PicoContainer#getComponentAdapterOfType(java.lang.Class)
182 */
183 public ComponentAdapter getComponentAdapterOfType(final Class componentType) {
184 if (logger.isDebugEnabled()) {
185 logger.debug("Locating component adapter with type " + componentType);
186 }
187
188 ComponentAdapter ca = delegate.getComponentAdapterOfType(componentType);
189
190 if (ca == null) {
191 onKeyDoesntExistInContainer(ca, logger);
192 }
193 return ca;
194 }
195
196 /**
197 * {@inheritDoc}
198 *
199 * @return Collection or null.
200 * @see org.picocontainer.PicoContainer#getComponentAdapters()
201 */
202 public Collection getComponentAdapters() {
203 if (logger.isDebugEnabled()) {
204 logger.debug("Grabbing all component adapters for container: " + delegate);
205 }
206 return delegate.getComponentAdapters();
207 }
208
209 /**
210 * {@inheritDoc}
211 *
212 * @param componentType
213 * @return List of ComponentAdapters
214 * @see org.picocontainer.PicoContainer#getComponentAdaptersOfType(java.lang.Class)
215 */
216 public List getComponentAdaptersOfType(final Class componentType) {
217 if (logger.isDebugEnabled()) {
218 logger.debug("Grabbing all component adapters for container: " + delegate + " of type: "
219 + componentType.getName());
220 }
221 return delegate.getComponentAdaptersOfType(componentType);
222 }
223
224 /**
225 * {@inheritDoc}
226 *
227 * @param componentKey
228 * @return
229 * @see org.picocontainer.PicoContainer#getComponentInstance(java.lang.Object)
230 */
231 public Object getComponentInstance(final Object componentKey) {
232
233 if (logger.isDebugEnabled()) {
234 logger.debug("Attempting to load component instance with key: " + componentKey + " for container "
235 + delegate);
236
237 }
238
239 Object result = delegate.getComponentInstance(componentKey);
240 if (result == null) {
241 onKeyDoesntExistInContainer(componentKey, logger);
242 }
243
244 return result;
245 }
246
247 /**
248 * {@inheritDoc}
249 *
250 * @param componentType
251 * @return
252 * @see org.picocontainer.PicoContainer#getComponentInstanceOfType(java.lang.Class)
253 */
254 public Object getComponentInstanceOfType(final Class componentType) {
255 if (logger.isDebugEnabled()) {
256 logger.debug("Attempting to load component instance with type: " + componentType + " for container "
257 + delegate);
258
259 }
260
261 Object result = delegate.getComponentInstanceOfType(componentType);
262 if (result == null) {
263 if (logger.isInfoEnabled()) {
264 logger.info("No component of type " + componentType.getName() + " was found in container: " + delegate);
265 }
266 }
267
268 return result;
269 }
270
271 /**
272 * {@inheritDoc}
273 *
274 * @return
275 * @see org.picocontainer.PicoContainer#getComponentInstances()
276 */
277 public List getComponentInstances() {
278 if (logger.isDebugEnabled()) {
279 logger.debug("Retrieving all component instances for container " + delegate);
280 }
281 return delegate.getComponentInstances();
282 }
283
284 /**
285 * {@inheritDoc}
286 *
287 * @param componentType
288 * @return
289 * @see org.picocontainer.PicoContainer#getComponentInstancesOfType(java.lang.Class)
290 */
291 public List getComponentInstancesOfType(final Class componentType) {
292 if (logger.isDebugEnabled()) {
293 logger.debug("Loading all component instances of type " + componentType + " for container " + delegate);
294 }
295 List result = delegate.getComponentInstancesOfType(componentType);
296 if (result == null || result.size() == 0) {
297 if (logger.isInfoEnabled()) {
298 logger.info("Could not find any components " + " in container or parent container.");
299 }
300 }
301
302 return result;
303 }
304
305 /**
306 * {@inheritDoc}
307 *
308 * @return
309 * @see org.picocontainer.PicoContainer#getParent()
310 */
311 public PicoContainer getParent() {
312 if (logger.isDebugEnabled()) {
313 logger.debug("Retrieving the parent for container " + delegate);
314 }
315
316 return delegate.getParent();
317 }
318
319 /**
320 * {@inheritDoc}
321 *
322 * @return
323 * @see org.picocontainer.MutablePicoContainer#makeChildContainer()
324 */
325 public MutablePicoContainer makeChildContainer() {
326 if (logger.isDebugEnabled()) {
327 logger.debug("Making child container for container " + delegate);
328 }
329
330 // Wrap the new delegate
331 return new Log4jTracingContainerDecorator(delegate.makeChildContainer());
332 }
333
334 /**
335 * {@inheritDoc}
336 *
337 * @param componentAdapter
338 * @return
339 * @see org.picocontainer.MutablePicoContainer#registerComponent(org.picocontainer.ComponentAdapter)
340 */
341 public ComponentAdapter registerComponent(final ComponentAdapter componentAdapter) {
342 if (logger.isDebugEnabled()) {
343 logger.debug("Registering component adapter " + componentAdapter);
344 }
345
346 return delegate.registerComponent(componentAdapter);
347 }
348
349 /**
350 * {@inheritDoc}
351 *
352 * @param componentImplementation
353 * @return
354 * @see org.picocontainer.MutablePicoContainer#registerComponentImplementation(java.lang.Class)
355 */
356 public ComponentAdapter registerComponentImplementation(final Class componentImplementation) {
357 if (logger.isDebugEnabled()) {
358 logger.debug("Registering component implementation " + componentImplementation.getName());
359 }
360
361 return delegate.registerComponentImplementation(componentImplementation);
362 }
363
364 /**
365 * {@inheritDoc}
366 *
367 * @param componentKey
368 * @param componentImplementation
369 * @param parameters
370 * @return
371 * @see org.picocontainer.MutablePicoContainer#registerComponentImplementation(java.lang.Object,
372 * java.lang.Class, org.picocontainer.Parameter[])
373 */
374 public ComponentAdapter registerComponentImplementation(final Object componentKey,
375 final Class componentImplementation, final Parameter[] parameters) {
376
377 if (logger.isDebugEnabled()) {
378 logger.debug("Registering component implementation with key " + componentKey + " and implementation "
379 + componentImplementation.getName() + " using parameters " + parameters);
380 }
381
382 return delegate.registerComponentImplementation(componentKey, componentImplementation, parameters);
383 }
384
385 /**
386 * {@inheritDoc}
387 *
388 * @param componentKey
389 * @param componentImplementation
390 * @return
391 * @see org.picocontainer.MutablePicoContainer#registerComponentImplementation(java.lang.Object,
392 * java.lang.Class)
393 */
394 public ComponentAdapter registerComponentImplementation(final Object componentKey,
395 final Class componentImplementation) {
396 if (logger.isDebugEnabled()) {
397 logger.debug("Registering component implementation with key " + componentKey + " and implementation "
398 + componentImplementation.getName());
399 }
400
401 return delegate.registerComponentImplementation(componentKey, componentImplementation);
402 }
403
404 /**
405 * {@inheritDoc}
406 *
407 * @param componentKey
408 * @param componentInstance
409 * @return
410 * @see org.picocontainer.MutablePicoContainer#registerComponentInstance(java.lang.Object,
411 * java.lang.Object)
412 */
413 public ComponentAdapter registerComponentInstance(final Object componentKey, final Object componentInstance) {
414 if (logger.isDebugEnabled()) {
415 logger.debug("Registering component instance with key " + componentKey + " and instance "
416 + componentInstance + "(class: "
417 + ((componentInstance != null) ? componentInstance.getClass().getName() : " null "));
418 }
419
420 return delegate.registerComponentInstance(componentKey, componentInstance);
421 }
422
423 /**
424 * {@inheritDoc}
425 *
426 * @param componentInstance
427 * @return
428 * @see org.picocontainer.MutablePicoContainer#registerComponentInstance(java.lang.Object)
429 */
430 public ComponentAdapter registerComponentInstance(final Object componentInstance) {
431 if (logger.isDebugEnabled()) {
432 logger.debug("Registering component instance " + componentInstance + "(class: "
433 + ((componentInstance != null) ? componentInstance.getClass().getName() : " null "));
434 }
435
436 return delegate.registerComponentInstance(componentInstance);
437 }
438
439 /**
440 * {@inheritDoc}
441 *
442 * @param child
443 * @return
444 * @see org.picocontainer.MutablePicoContainer#removeChildContainer(org.picocontainer.PicoContainer)
445 */
446 public boolean removeChildContainer(final PicoContainer child) {
447 if (logger.isDebugEnabled()) {
448 logger.debug("Removing child container: " + child + " from parent: " + delegate);
449 }
450 return delegate.removeChildContainer(child);
451 }
452
453 /**
454 * {@inheritDoc}
455 *
456 * @see org.picocontainer.Startable#start()
457 */
458 public void start() {
459 if (logger.isInfoEnabled()) {
460 logger.info("Starting Container " + delegate);
461 }
462
463 delegate.start();
464 }
465
466 /**
467 * {@inheritDoc}
468 *
469 * @see org.picocontainer.Startable#stop()
470 */
471 public void stop() {
472 if (logger.isInfoEnabled()) {
473 logger.info("Stopping Container " + delegate);
474 }
475 delegate.stop();
476 }
477
478 /**
479 * {@inheritDoc}
480 *
481 * @param componentKey
482 * @return
483 * @see org.picocontainer.MutablePicoContainer#unregisterComponent(java.lang.Object)
484 */
485 public ComponentAdapter unregisterComponent(final Object componentKey) {
486 if (logger.isDebugEnabled()) {
487 logger.debug("Unregistering component " + componentKey + " from container " + delegate);
488 }
489
490 return delegate.unregisterComponent(componentKey);
491 }
492
493 /**
494 * {@inheritDoc}
495 *
496 * @param componentInstance
497 * @return
498 * @see org.picocontainer.MutablePicoContainer#unregisterComponentByInstance(java.lang.Object)
499 */
500 public ComponentAdapter unregisterComponentByInstance(final Object componentInstance) {
501 if (logger.isDebugEnabled()) {
502 logger.debug("Unregistering component by instance (" + componentInstance + ") from container " + delegate);
503 }
504
505 return delegate.unregisterComponentByInstance(componentInstance);
506 }
507
508 /**
509 * {@inheritDoc}
510 *
511 * @throws PicoVerificationException
512 * @deprecated
513 * @see org.picocontainer.PicoContainer#verify()
514 */
515 public void verify() throws PicoVerificationException {
516 logger.info("Verifying container");
517 logger.warn("Using deprecated function PicoContainer.verify(). "
518 + "Please use VerifyingVisitor instead.");
519 delegate.verify();
520 }
521
522 /**
523 * Retrieves the logger instance used by this decorator.
524 *
525 * @return Logger instance.
526 */
527 public Logger getLoggerUsed() {
528 return this.logger;
529 }
530
531 private void readObject(final ObjectInputStream s) throws java.io.IOException, java.lang.ClassNotFoundException {
532
533 s.defaultReadObject();
534 String loggerName = s.readUTF();
535 logger = Logger.getLogger(loggerName);
536 }
537
538 private void writeObject(final ObjectOutputStream s) throws java.io.IOException {
539 s.defaultWriteObject();
540 s.writeUTF(logger.getName());
541 }
542
543 }