Lifecycle.java

129 lines | 4.02 kB Blame History Raw Download
package com.ning.billing.beatrix.lifecycle;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Supplier;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.ning.billing.beatrix.lifecycle.LyfecycleHandlerType.LyfecycleLevel;


public class Lifecycle {

    private final static Logger log = LoggerFactory.getLogger(Lifecycle.class);


    private final class LifecycleHandler {
        private final Object target;
        private final Method method;

        public LifecycleHandler(Object target, Method method) {
            this.target = target;
            this.method = method;
        }

        public Object getTarget() {
            return target;
        }

        public Method getMethod() {
            return method;
        }
    }

    private final SetMultimap<LyfecycleLevel, LifecycleHandler> handlersByLevel;

    private final Injector injector;

    @Inject
    public Lifecycle(Injector injector) {
        this.handlersByLevel = Multimaps.newSetMultimap(new ConcurrentHashMap<LyfecycleLevel, Collection<LifecycleHandler>>(),

                new Supplier<Set<LifecycleHandler>>() {
                  @Override
                  public Set<LifecycleHandler> get() {
                    return new CopyOnWriteArraySet<LifecycleHandler>();
                  }
                });
        this.injector = injector;
    }

    public void init() {
        List<? extends LifecycleService> services = findServices();
        Iterator<? extends LifecycleService> it = services.iterator();
        while (it.hasNext()) {
        //for (<? extends LifecycleService> cur : services) {
            handlersByLevel.putAll(findAllHandlers(it.next()));
        }
    }



    public void fireStages() {
        for (LyfecycleLevel level : LyfecycleLevel.values()) {
            log.info("Firing stage {}", level);
            Set<LifecycleHandler> handlers = handlersByLevel.get(level);
            for (LifecycleHandler cur : handlers) {
                log.info("Calling handler {}", cur.getMethod().getName());
                try {
                    Method method = cur.getMethod();
                    Object target = cur.getTarget();
                    method.invoke(target);
                } catch (Exception e) {
                    log.warn("Faikled to invoke lifecycle handler", e);
                }

            }
        }
    }

    private List<? extends LifecycleService> findServices() {

        List<LifecycleService> result = new LinkedList<LifecycleService>();

        ClassFinder classFinder = new ClassFinder(Lifecycle.class.getClassLoader());
        List<Class<? extends LifecycleService>> services =  classFinder.getServices();
        for (Class<? extends LifecycleService> cur : services) {
            log.info("Found service {}", cur);
            result.add(injector.getInstance(cur));
        }
        return result;
    }


    public Multimap<LyfecycleLevel, LifecycleHandler> findAllHandlers(Object service) {
        Multimap<LyfecycleLevel, LifecycleHandler> methodsInService =
            HashMultimap.create();
        Class clazz = service.getClass();
        for (Method method : clazz.getMethods()) {
            LyfecycleHandlerType annotation = method.getAnnotation(LyfecycleHandlerType.class);

            if (annotation != null) {

                LyfecycleLevel level = annotation.value();
                LifecycleHandler handler = new LifecycleHandler(service, method);
                methodsInService.put(level, handler);
            }
        }
        return methodsInService;
    }


}