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 }