// Path: src/main/java/ru/vyarus/guice/ext/core/method/MethodPostProcessor.java
// public interface MethodPostProcessor<T extends Annotation> {
// 
//     /**
//      * Called to post process annotated bean method.
//      * It is safe to avoid explicit exception handling (except special cases required by processor logic).
//      *
//      * @param annotation annotation instance
//      * @param method     annotated method
//      * @param instance   bean instance
//      * @throws Exception on any unrecoverable error
//      * @see ru.vyarus.guice.ext.core.method.AnnotatedMethodTypeListener
//      */
//     void process(T annotation, Method method, Object instance) throws Exception;
// }
// 
// Path: src/main/java/ru/vyarus/guice/ext/core/util/Utils.java
// public final class Utils {
// 
//     private Utils() {
//     }
// 
//     /**
//      * Important check, because JDK proxies of public interfaces have no package
//      * (thanks to @binkley https://github.com/99soft/lifegycle/pull/5).
//      *
//      * @param type class type to check
//      * @return true if package could be resolved, false otherwise
//      */
//     public static boolean isPackageValid(final Class type) {
//         boolean res = false;
//         if (type != null) {
//             final Package packaj = type.getPackage();
//             res = !(packaj == null || packaj.getName().startsWith("java"));
//         }
//         return res;
//     }
// 
//     /**
//      * Checks that method has no parameters, otherwise throws exception.
//      *
//      * @param method method to check
//      */
//     public static void checkNoParams(final Method method) {
//         if (method.getParameterTypes().length > 0) {
//             throw new IllegalStateException("Method without parameters required");
//         }
//     }
// 
//     /**
//      * Note: versions below 1.8 are not supported.
//      *
//      * @return true if current java is 1.8, otherwise assumed 9 or above
//      */
//     public static boolean isJava8() {
//         final String version = System.getProperty("java.version");
//         return version.startsWith("1.8");
//     }
// }
// 
// Path: src/main/java/ru/vyarus/guice/ext/managed/destroyable/AnnotatedMethodDestroyable.java
// public class AnnotatedMethodDestroyable implements Destroyable {
// 
//     private final Method method;
//     private final Object instance;
// 
//     public AnnotatedMethodDestroyable(final Method method, final Object instance) {
//         this.method = method;
//         this.instance = instance;
//     }
// 
//     @Override
//     public void preDestroy() throws Exception {
//         method.invoke(instance);
//     }
// }
// 
// Path: src/main/java/ru/vyarus/guice/ext/managed/destroyable/DestroyableManager.java
// public class DestroyableManager implements Runnable {
//     private final Logger logger = LoggerFactory.getLogger(DestroyableManager.class);
// 
//     private final List<Destroyable> destroyListeners = new ArrayList<>();
// 
//     /**
//      * Register destroyable instance to be called on context shutdown.
//      * Not thread safe (assuming single thread injector initialization)
//      *
//      * @param destroyable destroyable instance
//      * @see ru.vyarus.guice.ext.managed.PostConstructAnnotationProcessor regsters annotated methods
//      * @see ru.vyarus.guice.ext.managed.DestroyableTypeProcessor registers beans anootated with {@code Destroyable}
//      */
//     public void register(final Destroyable destroyable) {
//         // assuming single thread injector creation
//         destroyListeners.add(destroyable);
//     }
// 
//     /**
//      * Called on context shutdown to call all registered destroyable instances.
//      * By default called on jvm shutdown, but may be called manually to synchronise with
//      * some other container shutdown (e.g. web container)
//      * Safe to call many times, but all destroy instances will be processed only on first call.
//      * Thread safe.
//      */
//     public void destroy() {
//         // just for the case
//         synchronized (this) {
//             for (Destroyable destroyable : destroyListeners) {
//                 try {
//                     destroyable.preDestroy();
//                 } catch (Exception ex) {
//                     logger.error("Failed to properly destroy bean", ex);
//                 }
//             }
//             destroyListeners.clear();
//         }
//     }
// 
//     @Override
//     public void run() {
//         destroy();
//     }
// }


import ru.vyarus.guice.ext.core.method.MethodPostProcessor;
import ru.vyarus.guice.ext.core.util.Utils;
import ru.vyarus.guice.ext.managed.destroyable.AnnotatedMethodDestroyable;
import ru.vyarus.guice.ext.managed.destroyable.DestroyableManager;
import javax.annotation.PreDestroy;
import java.lang.reflect.Method;
package ru.vyarus.guice.ext.managed;



/**
 * Registers bean methods annotated with @PostConstruct in {@code DestroyableManager} to be called on shutdown.
 *
 * @author Vyacheslav Rusakov
 * @since 30.06.2014
 */
public class PreDestroyAnnotationProcessor implements MethodPostProcessor<PreDestroy> {

    private final DestroyableManager manager;

    public PreDestroyAnnotationProcessor(final DestroyableManager manager) {
        this.manager = manager;
    }

    @Override
    public void process(final PreDestroy annotation, final Method method, final Object instance) throws Exception {
// Path: src/main/java/ru/vyarus/guice/ext/core/method/MethodPostProcessor.java
// public interface MethodPostProcessor<T extends Annotation> {
// 
//     /**
//      * Called to post process annotated bean method.
//      * It is safe to avoid explicit exception handling (except special cases required by processor logic).
//      *
//      * @param annotation annotation instance
//      * @param method     annotated method
//      * @param instance   bean instance
//      * @throws Exception on any unrecoverable error
//      * @see ru.vyarus.guice.ext.core.method.AnnotatedMethodTypeListener
//      */
//     void process(T annotation, Method method, Object instance) throws Exception;
// }
// 
// Path: src/main/java/ru/vyarus/guice/ext/core/util/Utils.java
// public final class Utils {
// 
//     private Utils() {
//     }
// 
//     /**
//      * Important check, because JDK proxies of public interfaces have no package
//      * (thanks to @binkley https://github.com/99soft/lifegycle/pull/5).
//      *
//      * @param type class type to check
//      * @return true if package could be resolved, false otherwise
//      */
//     public static boolean isPackageValid(final Class type) {
//         boolean res = false;
//         if (type != null) {
//             final Package packaj = type.getPackage();
//             res = !(packaj == null || packaj.getName().startsWith("java"));
//         }
//         return res;
//     }
// 
//     /**
//      * Checks that method has no parameters, otherwise throws exception.
//      *
//      * @param method method to check
//      */
//     public static void checkNoParams(final Method method) {
//         if (method.getParameterTypes().length > 0) {
//             throw new IllegalStateException("Method without parameters required");
//         }
//     }
// 
//     /**
//      * Note: versions below 1.8 are not supported.
//      *
//      * @return true if current java is 1.8, otherwise assumed 9 or above
//      */
//     public static boolean isJava8() {
//         final String version = System.getProperty("java.version");
//         return version.startsWith("1.8");
//     }
// }
// 
// Path: src/main/java/ru/vyarus/guice/ext/managed/destroyable/AnnotatedMethodDestroyable.java
// public class AnnotatedMethodDestroyable implements Destroyable {
// 
//     private final Method method;
//     private final Object instance;
// 
//     public AnnotatedMethodDestroyable(final Method method, final Object instance) {
//         this.method = method;
//         this.instance = instance;
//     }
// 
//     @Override
//     public void preDestroy() throws Exception {
//         method.invoke(instance);
//     }
// }
// 
// Path: src/main/java/ru/vyarus/guice/ext/managed/destroyable/DestroyableManager.java
// public class DestroyableManager implements Runnable {
//     private final Logger logger = LoggerFactory.getLogger(DestroyableManager.class);
// 
//     private final List<Destroyable> destroyListeners = new ArrayList<>();
// 
//     /**
//      * Register destroyable instance to be called on context shutdown.
//      * Not thread safe (assuming single thread injector initialization)
//      *
//      * @param destroyable destroyable instance
//      * @see ru.vyarus.guice.ext.managed.PostConstructAnnotationProcessor regsters annotated methods
//      * @see ru.vyarus.guice.ext.managed.DestroyableTypeProcessor registers beans anootated with {@code Destroyable}
//      */
//     public void register(final Destroyable destroyable) {
//         // assuming single thread injector creation
//         destroyListeners.add(destroyable);
//     }
// 
//     /**
//      * Called on context shutdown to call all registered destroyable instances.
//      * By default called on jvm shutdown, but may be called manually to synchronise with
//      * some other container shutdown (e.g. web container)
//      * Safe to call many times, but all destroy instances will be processed only on first call.
//      * Thread safe.
//      */
//     public void destroy() {
//         // just for the case
//         synchronized (this) {
//             for (Destroyable destroyable : destroyListeners) {
//                 try {
//                     destroyable.preDestroy();
//                 } catch (Exception ex) {
//                     logger.error("Failed to properly destroy bean", ex);
//                 }
//             }
//             destroyListeners.clear();
//         }
//     }
// 
//     @Override
//     public void run() {
//         destroy();
//     }
// }


// Path: src/main/java/ru/vyarus/guice/ext/managed/PreDestroyAnnotationProcessor.java
import ru.vyarus.guice.ext.core.method.MethodPostProcessor;
import ru.vyarus.guice.ext.core.util.Utils;
import ru.vyarus.guice.ext.managed.destroyable.AnnotatedMethodDestroyable;
import ru.vyarus.guice.ext.managed.destroyable.DestroyableManager;
import javax.annotation.PreDestroy;
import java.lang.reflect.Method;

package ru.vyarus.guice.ext.managed;



/**
 * Registers bean methods annotated with @PostConstruct in {@code DestroyableManager} to be called on shutdown.
 *
 * @author Vyacheslav Rusakov
 * @since 30.06.2014
 */
public class PreDestroyAnnotationProcessor implements MethodPostProcessor<PreDestroy> {

    private final DestroyableManager manager;

    public PreDestroyAnnotationProcessor(final DestroyableManager manager) {
        this.manager = manager;
    }

    @Override
    public void process(final PreDestroy annotation, final Method method, final Object instance) throws Exception {
        Utils.checkNoParams(method);