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 }