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

com.savl.ripple.client.pubsub.Publisher Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
package com.savl.ripple.client.pubsub;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Publisher {
    static final Logger logger = Logger.getLogger(Publisher.class.getName());
    private void log(Level level, String message, Object... params) {
        logger.log(level, message, params);
    }

    public static interface Callback {
        public void called(T args);
    }

    public static interface ErrBack extends Callback {
        public void erred(RuntimeException args);
    }

    public > void on(Class key, T cb) {
        add(key, cb);
    }

    public > void on(Class key, CallbackContext executor, T cb) {
        add(key, executor, cb);
    }

    public > void once(final Class key, final T cb) {
        once(key, null, cb);
    }

    public > void once(final Class key, CallbackContext executor, final T cb) {
        add(key, executor, cb, true);
    }

    public > int emit(Class key, A args) {
        if (logger.isLoggable(Level.FINE)) {
            log(Level.FINE, "Emitting {0} from thread: {1}", key.getSimpleName(), Thread.currentThread());
        }

        int executed = 0;
        CallbackList callbacks = (cbs.get(key));

        if (callbacks != null) {
            CallbackList copy = new CallbackList(callbacks);

            for (ContextedCallback pair : copy) {
                boolean removed = false;

                CallbackContext context = pair.context;
                if (context == null) {
                    execute(args, pair);
                    executed++;
                } else {
                    if (context.shouldExecute()) {
                        context.execute(pair.runnableWrappedCallback(args));
                        executed++;
                    } else if (context.shouldRemove()) {
                        callbacks.remove(pair);
                        removed = true;
                    }
                }
                // we only want to call remove once
                if (pair.oneShot && !removed) {
                    callbacks.remove(pair);
                }
            }
        }
        return executed;
    }

    @SuppressWarnings("unchecked")
    public static void execute(Object args, ContextedCallback pair) {
        pair.callback.called(args);
    }

    private static class ContextedCallback {
        CallbackContext context;
        Callback callback;
        boolean oneShot;

        public ContextedCallback(Callback callback, CallbackContext context, boolean oneShot) {
            this.context = context;
            this.callback = callback;
            this.oneShot = oneShot;
        }

        public Runnable runnableWrappedCallback(final Object args) {
            return new Runnable() {
                @Override
                public void run() {
                    execute(args, ContextedCallback.this);
                }
            };
        }
    }

    private static class CallbackList extends ArrayList {
        public CallbackList() {}
        public CallbackList(CallbackList callbacks) {
            super(callbacks);
        }

        @Override
        public ContextedCallback get(int index) {
            return super.get(index);
        }

        public boolean remove(Callback t) {
            Iterator iter = iterator();
            while (iter.hasNext()) {
                ContextedCallback next = iter.next();
                if (next.callback == t) {
                    iter.remove();
                    return true;
                }
            }
            return false;
        }

        public void add(CallbackContext exec, Callback cb, boolean oneShot) {
            add(new ContextedCallback(cb, exec, oneShot));
        }
    }

    private class DefaultCallbackListMap extends HashMap, CallbackList> {
        public CallbackList getDefault(Class key) {
            CallbackList list = super.get(key);
            if (list == null) {
                CallbackList newList = new CallbackList();
                put(key, newList);
                return newList;
            }
            return list;
        }
    }

    @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    private final DefaultCallbackListMap cbs = new DefaultCallbackListMap();

    private CallbackList listFor(Class key) {
        return cbs.getDefault(key);
    }

    private > void add(Class key, Callback cb) {
        add(key, null, cb, false);
    }

    private > void add(Class key, CallbackContext executor, Callback cb) {
        add(key, executor, cb, false);
    }

    private > void add(Class key, CallbackContext executor, final Callback cb, boolean b) {
        listFor(key).add(executor, cb, b);
    }

    public > boolean removeListener(Class key, Callback cb) {
        return listFor(key).remove(cb);
    }

    public void clearAllListeners() {
        cbs.clear();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy