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.PicoLifecycleException;
012
013 import javax.annotation.PostConstruct;
014 import javax.annotation.PreDestroy;
015 import java.lang.annotation.Annotation;
016 import java.lang.reflect.InvocationTargetException;
017 import java.lang.reflect.Method;
018 import java.util.HashSet;
019 import java.util.Set;
020
021 /**
022 * Java EE 5 has some annotations PreDestroy and PostConstruct that map to start() and dispose() in our world
023 *
024 * @author Paul Hammant
025 */
026 @SuppressWarnings("serial")
027 public final class JavaEE5LifecycleStrategy extends AbstractMonitoringLifecycleStrategy {
028
029 /**
030 * Construct a JavaEE5LifecycleStrategy.
031 *
032 * @param monitor the monitor to use
033 * @throws NullPointerException if the monitor is <code>null</code>
034 */
035 public JavaEE5LifecycleStrategy(final ComponentMonitor monitor) {
036 super(monitor);
037 }
038
039 /** {@inheritDoc} **/
040 public void start(final Object component) {
041 doLifecycleMethod(component, PostConstruct.class, true);
042 }
043
044 /** {@inheritDoc} **/
045 public void stop(final Object component) {
046 }
047
048 /** {@inheritDoc} **/
049 public void dispose(final Object component) {
050 doLifecycleMethod(component, PreDestroy.class, false);
051 }
052
053 private void doLifecycleMethod(final Object component, Class<? extends Annotation> annotation, boolean superFirst) {
054 doLifecycleMethod(component, annotation, component.getClass(), superFirst, new HashSet<String>());
055 }
056
057 private void doLifecycleMethod(Object component, Class<? extends Annotation> annotation, Class<? extends Object> clazz, boolean superFirst, Set<String> doneAlready) {
058 Class<?> parent = clazz.getSuperclass();
059 if (superFirst && parent != Object.class) {
060 doLifecycleMethod(component, annotation, parent, superFirst, doneAlready);
061 }
062 Method[] methods = clazz.getDeclaredMethods();
063 for (Method method : methods) {
064 String signature = signature(method);
065 if (method.isAnnotationPresent(annotation) && !doneAlready.contains(signature)) {
066 try {
067 long str = System.currentTimeMillis();
068 currentMonitor().invoking(null, null, method, component, new Object[0]);
069 method.invoke(component);
070 doneAlready.add(signature);
071 currentMonitor().invoked(null, null, method, component, System.currentTimeMillis() - str, new Object[0], null);
072 } catch (IllegalAccessException e) {
073 throw new PicoLifecycleException(method, component, e);
074 } catch (InvocationTargetException e) {
075 throw new PicoLifecycleException(method, component, e);
076 }
077 }
078 }
079 if (!superFirst && parent != Object.class) {
080 doLifecycleMethod(component, annotation, parent, superFirst, doneAlready);
081 }
082 }
083
084 private static String signature(Method method) {
085 StringBuilder sb = new StringBuilder(method.getName());
086 Class<?>[] pt = method.getParameterTypes();
087 for (Class<?> objectClass : pt) {
088 sb.append(objectClass.getName());
089 }
090 return sb.toString();
091 }
092
093
094 /**
095 * {@inheritDoc} The component has a lifecycle PreDestroy or PostConstruct are on a method
096 */
097 public boolean hasLifecycle(final Class<?> type) {
098 Method[] methods = type.getDeclaredMethods();
099 for (int i = 0; i < methods.length; i++) {
100 Method method = methods[i];
101 if (method.isAnnotationPresent(PreDestroy.class) || method.isAnnotationPresent(PostConstruct.class)) {
102 return true;
103 }
104 }
105 return false;
106 }
107
108 }