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 *****************************************************************************/
008package org.picocontainer.lifecycle;
009
010import java.lang.reflect.InvocationTargetException;
011import java.lang.reflect.Method;
012
013import org.picocontainer.ComponentMonitor;
014import org.picocontainer.Disposable;
015import org.picocontainer.PicoLifecycleException;
016import org.picocontainer.Startable;
017
018/**
019 * Startable lifecycle strategy.  Starts and stops component if Startable,
020 * and disposes it if Disposable.
021 *
022 * A subclass of this class can define other intrfaces for Startable/Disposable as well as other method names
023 * for start/stop/dispose
024 *
025 * @author Mauro Talevi
026 * @author Jörg Schaible
027 * @see Startable
028 * @see Disposable
029 */
030@SuppressWarnings("serial")
031public class StartableLifecycleStrategy extends AbstractMonitoringLifecycleStrategy {
032
033 
034        private transient Method start, stop, dispose;
035
036    public StartableLifecycleStrategy(final ComponentMonitor monitor) {
037        super(monitor);
038    }
039
040    private void doMethodsIfNotDone() {
041        try {
042            if (start == null) {
043                start = getStartableInterface().getMethod(getStartMethodName());
044            }
045            if (stop == null) {
046                stop = getStartableInterface().getMethod(getStopMethodName());
047            }
048            if (dispose == null) {
049                dispose = getDisposableInterface().getMethod(getDisposeMethodName());
050            }
051        } catch (NoSuchMethodException e) {
052        }
053    }
054
055    /**
056     * Retrieve the lifecycle method name that represents the dispose method.
057     * @return the dispose method name. ('dispose')
058     */
059    protected String getDisposeMethodName() {
060        return "dispose";
061    }
062
063    /**
064     * Retrieve the lifecycle method name that represents the stop method. 
065     * @return the stop method name ('stop')
066     */
067    protected String getStopMethodName() {
068        return "stop";
069    }
070
071    /**
072     * Retrieve the lifecycle method name that represents the start method. 
073     * @return the stop method name ('start')
074     */
075    protected String getStartMethodName() {
076        return "start";
077    }
078
079
080    /** {@inheritDoc} **/
081    public void start(final Object component) {
082        doMethodsIfNotDone();
083        if (component != null && getStartableInterface().isAssignableFrom(component.getClass())) {
084            long str = System.currentTimeMillis();
085            currentMonitor().invoking(null, null, start, component, new Object[0]);
086            try {
087                startComponent(component);
088                currentMonitor().invoked(null, null, start, component, System.currentTimeMillis() - str, new Object[0], null);
089            } catch (RuntimeException cause) {
090                currentMonitor().lifecycleInvocationFailed(null, null, start, component, cause); // may re-throw
091            }
092        }
093    }
094
095    protected void startComponent(final Object component) {
096        doLifecycleMethod(component, start);
097    }
098
099    private void doLifecycleMethod(Object component, Method lifecycleMethod) {
100        try {
101            lifecycleMethod.invoke(component);
102        } catch (IllegalAccessException e) {
103            throw new PicoLifecycleException(lifecycleMethod, component, e);
104        } catch (InvocationTargetException e) {
105            if (e.getTargetException() instanceof RuntimeException) {
106                throw (RuntimeException) e.getTargetException();
107            }
108            throw new PicoLifecycleException(lifecycleMethod, component, e.getTargetException());
109        }
110    }
111
112    protected void stopComponent(final Object component) {
113        doLifecycleMethod(component, stop);
114    }
115    protected void disposeComponent(final Object component) {
116        doLifecycleMethod(component, dispose);
117    }
118
119    /** {@inheritDoc} **/
120    public void stop(final Object component) {
121        doMethodsIfNotDone();
122        if (component != null && getStartableInterface().isAssignableFrom(component.getClass())) {
123            long str = System.currentTimeMillis();
124            currentMonitor().invoking(null, null, stop, component, new Object[0]);
125            try {
126                stopComponent(component);
127                currentMonitor().invoked(null, null, stop, component, System.currentTimeMillis() - str, new Object[0], null);
128            } catch (RuntimeException cause) {
129                currentMonitor().lifecycleInvocationFailed(null, null, stop, component, cause); // may re-throw
130            }
131        }
132    }
133
134    /** {@inheritDoc} **/
135    public void dispose(final Object component) {
136        doMethodsIfNotDone();
137        if (component != null && getDisposableInterface().isAssignableFrom(component.getClass())) {
138            long str = System.currentTimeMillis();
139            currentMonitor().invoking(null, null, dispose, component, new Object[0]);
140            try {
141                disposeComponent(component);
142                currentMonitor().invoked(null, null, dispose, component, System.currentTimeMillis() - str, new Object[0], null);
143            } catch (RuntimeException cause) {
144                currentMonitor().lifecycleInvocationFailed(null, null, dispose, component, cause); // may re-throw
145            }
146        }
147    }
148
149    /** {@inheritDoc} **/
150    public boolean hasLifecycle(final Class<?> type) {
151        return getStartableInterface().isAssignableFrom(type) || getDisposableInterface().isAssignableFrom(type);
152    }
153
154    protected Class getDisposableInterface() {
155        return Disposable.class;
156    }
157
158    protected Class getStartableInterface() {
159        return Startable.class;
160    }
161}