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    }