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 org.picocontainer.ComponentMonitor;
011 import org.picocontainer.lifecycle.AbstractMonitoringLifecycleStrategy;
012 import org.picocontainer.lifecycle.ReflectionLifecycleException;
013
014 import java.lang.reflect.InvocationTargetException;
015 import java.lang.reflect.Method;
016 import java.util.HashMap;
017 import java.util.Map;
018
019
020 /**
021 * Reflection lifecycle strategy. Starts, stops, disposes of component if appropriate methods are
022 * present. The component may implement only one of the three methods.
023 *
024 * @author Paul Hammant
025 * @author Mauro Talevi
026 * @author Jörg Schaible
027 * @see org.picocontainer.Startable
028 * @see org.picocontainer.Disposable
029 * @see org.picocontainer.lifecycle.StartableLifecycleStrategy
030 */
031 public final 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 final String[] methodNames;
037 private final transient Map<Class, Method[]> methodMap = new HashMap<Class, Method[]>();
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(null, null, method, component);
086 method.invoke(component);
087 currentMonitor().invoked(null, null, method, component, System.currentTimeMillis() - str);
088 } catch (IllegalAccessException e) {
089 monitorAndThrowReflectionLifecycleException(method, e, component);
090 } catch (InvocationTargetException e) {
091 monitorAndThrowReflectionLifecycleException(method, e, component);
092 }
093 }
094 }
095
096 protected void monitorAndThrowReflectionLifecycleException(Method method,
097 Exception e,
098 Object component) {
099 RuntimeException re = new ReflectionLifecycleException(method.getName(), e);
100 currentMonitor().lifecycleInvocationFailed(null, null, method, component, re);
101 throw re;
102 }
103
104 /**
105 * {@inheritDoc} The component has a lifecylce if at least one of the three methods is present.
106 */
107 public boolean hasLifecycle(Class type) {
108 Method[] methods = init(type);
109 for (Method method : methods) {
110 if (method != null) {
111 return true;
112 }
113 }
114 return false;
115 }
116
117 private Method[] init(Class type) {
118 Method[] methods;
119 synchronized (methodMap) {
120 methods = methodMap.get(type);
121 if (methods == null) {
122 methods = new Method[methodNames.length];
123 for (int i = 0; i < methods.length; i++) {
124 try {
125 methods[i] = type.getMethod(methodNames[i]);
126 } catch (NoSuchMethodException e) {
127 continue;
128 }
129 }
130 methodMap.put(type, methods);
131 }
132 }
133 return methods;
134 }
135 }