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