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 java.lang.reflect.InvocationTargetException;
011    import java.lang.reflect.Method;
012    
013    import org.picocontainer.ComponentMonitor;
014    import org.picocontainer.Disposable;
015    import org.picocontainer.PicoLifecycleException;
016    import 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")
031    public 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    }