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 *****************************************************************************/ 008package org.picocontainer.lifecycle; 009 010import org.picocontainer.ComponentMonitor; 011import org.picocontainer.PicoLifecycleException; 012 013import javax.annotation.PostConstruct; 014import javax.annotation.PreDestroy; 015import java.lang.annotation.Annotation; 016import java.lang.reflect.InvocationTargetException; 017import java.lang.reflect.Method; 018import java.util.HashSet; 019import 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") 027public 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}