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