All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.deephacks.confit.spi.NotificationManager Maven / Gradle / Ivy

There is a newer version: 0.17.0
Show newest version
package org.deephacks.confit.spi;

import org.deephacks.confit.ConfigChanges;
import org.deephacks.confit.ConfigChanges.ConfigChange;
import org.deephacks.confit.model.Bean;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public abstract class NotificationManager {
    private static Conversion conversion = Conversion.get();

    public abstract void register(Observer observer);

    public abstract void fire(ConfigChanges changes);

    public final void fireCreate(Collection beans) {
        ConfigChanges beanChanges = new ConfigChanges();
        ConfigChanges objectChanges = new ConfigChanges();
        for (Bean bean : beans) {
            beanChanges.add(ConfigChange.created(bean));
            Object object = conversion.convert(bean, bean.getSchema().getClassType());
            objectChanges.add(ConfigChange.created(object));
        }
        fire(beanChanges);
        Map, ConfigChanges> typed = arrangeTyped(objectChanges);
        for (Class cls : typed.keySet() ) {
            fire(typed.get(cls));
        }
    }

    public final void fireDelete(Collection beans) {
        ConfigChanges changes = new ConfigChanges();
        ConfigChanges objectChanges = new ConfigChanges();
        for (Bean bean : beans) {
            changes.add(ConfigChange.deleted(bean));
            Object object = conversion.convert(bean, bean.getSchema().getClassType());
            objectChanges.add(ConfigChange.created(object));
        }
        fire(changes);
        Map, ConfigChanges> typed = arrangeTyped(objectChanges);
        for (Class cls : typed.keySet() ) {
            fire(typed.get(cls));
        }
    }

    public final void fireUpdated(Collection beans) {
        ConfigChanges changes = new ConfigChanges();
        ConfigChanges objectChanges = new ConfigChanges();
        for (Bean bean : beans) {
            changes.add(ConfigChange.updated(bean, bean));
            Object object = conversion.convert(bean, bean.getSchema().getClassType());
            objectChanges.add(ConfigChange.created(object));
        }
        fire(changes);
        Map, ConfigChanges> typed = arrangeTyped(objectChanges);
        for (Class cls : typed.keySet() ) {
            fire(typed.get(cls));
        }
    }

    private Map, ConfigChanges> arrangeTyped(ConfigChanges changes) {
        Map, ConfigChanges> typed = new HashMap<>();
        for (ConfigChange change : changes.getChanges()) {
            ConfigChanges cc = typed.get(change.getChangeClass());
            if (cc == null) {
                cc = new ConfigChanges();
                typed.put(change.getChangeClass(), cc);
            }
            cc.add(change);
        }
        return typed;
    }

    public final static class Observer {
        private Object instance;
        private HashMap, Method> observerMethods = new HashMap<>();

        public Observer(Object observer) {
            this.instance = observer;
            for (Method method : observer.getClass().getDeclaredMethods()) {
                method.setAccessible(true);
                Class[] params = method.getParameterTypes();

                if (params.length != 1) {
                    continue;
                }

                if (ConfigChanges.class.isAssignableFrom(params[0])) {
                    Class changeClass = getConfigChangeParameter(method);
                    if (changeClass != null) {
                        observerMethods.put(changeClass, method);
                    }
                }
            }
        }


        public Collection> getObservedClasses() {
            return observerMethods.keySet();
        }

        public void notify(ConfigChanges changes) {
            Collection c = changes.getChanges();
            Class changeClass = c.iterator().next().getChangeClass();
            Method observerMethod = observerMethods.get(changeClass);
            if (observerMethod == null) {
                return;
            }
            try {
                observerMethod.invoke(instance, changes);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }

        private Class getConfigChangeParameter(Method method) {
            Type[] types =  method.getGenericParameterTypes();
            for (Type type : types) {
                if (!ParameterizedType.class.isAssignableFrom(type.getClass())) {
                    return null;
                }
                ParameterizedType ptype = (ParameterizedType) type;
                Type[] targs = ptype.getActualTypeArguments();
                for (Type aType : targs) {
                    return (Class) aType;
                }
            }
            return null;
        }

        private Class extractClass(Class ownerClass, Type arg) {
            if (arg instanceof ParameterizedType) {
                return extractClass(ownerClass, ((ParameterizedType) arg).getRawType());
            } else if (arg instanceof GenericArrayType) {
                throw new UnsupportedOperationException("GenericArray types are not supported.");
            } else if (arg instanceof TypeVariable) {
                throw new UnsupportedOperationException("GenericArray types are not supported.");
            }
            return (arg instanceof Class ? (Class) arg : Object.class);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy