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                                                          *
009 *****************************************************************************/
010package org.picocontainer.monitors;
011
012import java.lang.reflect.Constructor;
013import java.lang.reflect.Member;
014import java.lang.reflect.Method;
015import java.util.ArrayList;
016import java.util.Collection;
017import java.util.List;
018
019import org.picocontainer.ComponentAdapter;
020import org.picocontainer.ComponentMonitor;
021import org.picocontainer.MutablePicoContainer;
022import org.picocontainer.PicoContainer;
023import org.picocontainer.PicoException;
024import org.picocontainer.PicoLifecycleException;
025import org.picocontainer.Injector;
026import org.picocontainer.Behavior;
027
028/**
029 * A {@link ComponentMonitor} which collects lifecycle failures
030 * and rethrows them on demand after the failures.
031 * 
032 * @author Paul Hammant
033 * @author Mauro Talevi
034 */
035@SuppressWarnings("serial")
036public final class LifecycleComponentMonitor implements ComponentMonitor {
037
038        /**
039         * Delegate for chained component monitors.
040         */
041    private final ComponentMonitor delegate;
042    
043    private final List<RuntimeException> lifecycleFailures = new ArrayList<RuntimeException>();
044
045    public LifecycleComponentMonitor(ComponentMonitor delegate) {
046        this.delegate = delegate;
047    }
048
049    public LifecycleComponentMonitor() {
050        this(new NullComponentMonitor());
051    }
052
053    public <T> Constructor<T> instantiating(PicoContainer container, ComponentAdapter<T> componentAdapter,
054                                     Constructor<T> constructor) {
055        return delegate.instantiating(container, componentAdapter, constructor);
056    }
057
058    public <T> void instantiated(PicoContainer container, ComponentAdapter<T> componentAdapter,
059                             Constructor<T> constructor,
060                             Object instantiated,
061                             Object[] parameters,
062                             long duration) {
063        delegate.instantiated(container, componentAdapter, constructor, instantiated, parameters, duration);
064    }
065
066    public <T> void instantiationFailed(PicoContainer container,
067                                    ComponentAdapter<T> componentAdapter,
068                                    Constructor<T> constructor,
069                                    Exception cause) {
070        delegate.instantiationFailed(container, componentAdapter, constructor, cause);
071    }
072
073    public Object invoking(PicoContainer container,
074                           ComponentAdapter<?> componentAdapter,
075                           Member member,
076                           Object instance, Object[] args) {
077        return delegate.invoking(container, componentAdapter, member, instance, args);
078    }
079
080    public void invoked(PicoContainer container,
081                        ComponentAdapter<?> componentAdapter,
082                        Member member,
083                        Object instance,
084                        long duration, Object[] args, Object retVal) {
085        delegate.invoked(container, componentAdapter, member, instance, duration, args, retVal);
086    }
087
088    public void invocationFailed(Member member, Object instance, Exception cause) {
089        delegate.invocationFailed(member, instance, cause);
090    }
091
092    public void lifecycleInvocationFailed(MutablePicoContainer container,
093                                          ComponentAdapter<?> componentAdapter, Method method,
094                                          Object instance,
095                                          RuntimeException cause) {
096        lifecycleFailures.add(cause);
097        try {
098            delegate.lifecycleInvocationFailed(container, componentAdapter, method, instance, cause);
099        } catch (PicoLifecycleException e) {
100            // do nothing, exception already logged for later rethrow.
101        }
102    }
103
104    public Object noComponentFound(MutablePicoContainer container, Object componentKey) {
105        return delegate.noComponentFound(container, componentKey);
106    }
107
108    public Injector newInjector(Injector injector) {
109        return delegate.newInjector(injector);
110    }
111
112    /** {@inheritDoc} **/
113    public Behavior newBehavior(Behavior behavior) {
114        return delegate.newBehavior(behavior);
115    }
116
117
118    public void rethrowLifecycleFailuresException() {
119        throw new LifecycleFailuresException(lifecycleFailures);
120    }
121
122    /**
123     * Subclass of {@link PicoException} that is thrown when the collected
124     * lifecycle failures need to be be collectively rethrown.
125     * 
126     * @author Paul Hammant
127     * @author Mauro Talevi
128     */
129    public final class LifecycleFailuresException extends PicoException {
130
131                
132                private final List<RuntimeException> lifecycleFailures;
133
134        public LifecycleFailuresException(List<RuntimeException> lifecycleFailures) {
135            this.lifecycleFailures = lifecycleFailures;
136        }
137
138        public String getMessage() {
139            StringBuffer message = new StringBuffer();
140            for (Object lifecycleFailure : lifecycleFailures) {
141                Exception failure = (Exception)lifecycleFailure;
142                message.append(failure.getMessage()).append(";  ");
143            }
144            return message.toString();
145        }
146
147        public Collection<RuntimeException> getFailures() {
148            return lifecycleFailures;
149        }
150    }
151}