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