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.gems.lifecycle;
009
010 import org.picocontainer.ComponentMonitor;
011 import org.picocontainer.defaults.AbstractMonitoringLifecycleStrategy;
012
013 import java.lang.reflect.InvocationTargetException;
014 import java.lang.reflect.Method;
015 import java.util.HashMap;
016 import java.util.Map;
017
018
019 /**
020 * Reflection lifecycle strategy. Starts, stops, disposes of component if appropriate methods are
021 * present. The component may implement only one of the three methods.
022 *
023 * @author Paul Hammant
024 * @author Mauro Talevi
025 * @author Jörg Schaible
026 * @see org.picocontainer.Startable
027 * @see org.picocontainer.Disposable
028 * @see org.picocontainer.defaults.DefaultLifecycleStrategy
029 * @since 1.2
030 */
031 public class ReflectionLifecycleStrategy extends AbstractMonitoringLifecycleStrategy {
032
033 private final static int START = 0;
034 private final static int STOP = 1;
035 private final static int DISPOSE = 2;
036 private String[] methodNames;
037 private final transient Map methodMap = new HashMap();
038
039 /**
040 * Construct a ReflectionLifecycleStrategy.
041 *
042 * @param monitor the monitor to use
043 * @throws NullPointerException if the monitor is <code>null</code>
044 */
045 public ReflectionLifecycleStrategy(ComponentMonitor monitor) {
046 this(monitor, "start", "stop", "dispose");
047 }
048
049 /**
050 * Construct a ReflectionLifecycleStrategy with individual method names. Note, that a lifecycle
051 * method does not have any arguments.
052 *
053 * @param monitor the monitor to use
054 * @param startMethodName the name of the start method
055 * @param stopMethodName the name of the stop method
056 * @param disposeMethodName the name of the dispose method
057 * @throws NullPointerException if the monitor is <code>null</code>
058 */
059 public ReflectionLifecycleStrategy(
060 ComponentMonitor monitor, String startMethodName, String stopMethodName,
061 String disposeMethodName) {
062 super(monitor);
063 methodNames = new String[]{startMethodName, stopMethodName, disposeMethodName};
064 }
065
066 public void start(Object component) {
067 Method[] methods = init(component.getClass());
068 invokeMethod(component, methods[START]);
069 }
070
071 public void stop(Object component) {
072 Method[] methods = init(component.getClass());
073 invokeMethod(component, methods[STOP]);
074 }
075
076 public void dispose(Object component) {
077 Method[] methods = init(component.getClass());
078 invokeMethod(component, methods[DISPOSE]);
079 }
080
081 private void invokeMethod(Object component, Method method) {
082 if (component != null && method != null) {
083 try {
084 long str = System.currentTimeMillis();
085 currentMonitor().invoking(method, component);
086 method.invoke(component, new Object[0]);
087 currentMonitor().invoked(method, component, System.currentTimeMillis() - str);
088 } catch (IllegalAccessException e) {
089 RuntimeException re = new ReflectionLifecycleException(method.getName(), e);
090 currentMonitor().lifecycleInvocationFailed(method, component, re);
091 throw re;
092 } catch (InvocationTargetException e) {
093 RuntimeException re = new ReflectionLifecycleException(method.getName(), e);
094 currentMonitor().lifecycleInvocationFailed(method, component, re);
095 throw re;
096 }
097 }
098 }
099
100 /**
101 * {@inheritDoc} The component has a lifecylce if at least one of the three methods is present.
102 */
103 public boolean hasLifecycle(Class type) {
104 Method[] methods = init(type);
105 for (int i = 0; i < methods.length; i++) {
106 if (methods[i] != null) {
107 return true;
108 }
109 }
110 return false;
111 }
112
113 private Method[] init(Class type) {
114 Method[] methods;
115 synchronized (methodMap) {
116 methods = (Method[])methodMap.get(type);
117 if (methods == null) {
118 methods = new Method[methodNames.length];
119 for (int i = 0; i < methods.length; i++) {
120 try {
121 methods[i] = type.getMethod(methodNames[i], new Class[0]);
122 } catch (NoSuchMethodException e) {
123 continue;
124 }
125 }
126 methodMap.put(type, methods);
127 }
128 }
129 return methods;
130 }
131 }