    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&ouml;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);
    086                try {
    087                    startComponent(component);
    088                    currentMonitor().invoked(null, null, start, component, System.currentTimeMillis() - str);
    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);
    125                try {
    126                    stopComponent(component);
    127                    currentMonitor().invoked(null, null, stop, component, System.currentTimeMillis() - str);
    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);
    140                try {
    141                    disposeComponent(component);
    142                    currentMonitor().invoked(null, null, dispose, component, System.currentTimeMillis() - str);
    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    }