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