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 }