com.mycila.event.MycilaEvent.java Source code

Java tutorial

Introduction

Here is the source code for com.mycila.event.MycilaEvent.java

Source

/**
 * Copyright (C) 2010 Mycila <mathieu.carbou@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mycila.event;

import com.google.common.collect.Iterables;
import com.mycila.event.annotation.Answers;
import com.mycila.event.annotation.Subscribe;
import com.mycila.event.internal.EventQueue;
import com.mycila.event.internal.Message;
import com.mycila.event.internal.Proxy;
import com.mycila.event.internal.PublisherInterceptor;
import com.mycila.event.internal.Subscribers;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.filter;
import static com.mycila.event.internal.Ensure.notNull;
import static com.mycila.event.internal.Reflect.annotatedBy;
import static com.mycila.event.internal.Reflect.findMethods;
import static com.mycila.event.internal.Reflect.getTargetClass;

/**
 * @author Mathieu Carbou (mathieu.carbou@gmail.com)
 */
public final class MycilaEvent {

    private final Dispatcher dispatcher;

    private MycilaEvent(Dispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }

    public <T> BlockingQueue<T> createSynchronousQueue(Topics topics, Class<T> eventType) {
        EventQueue<T> queue = new EventQueue<T>(new SynchronousQueue<T>());
        dispatcher.subscribe(topics, eventType, queue);
        return queue;
    }

    public <T> BlockingQueue<T> createBoundedQueue(Topics topics, Class<T> eventType, int capacity) {
        EventQueue<T> queue = new EventQueue<T>(new ArrayBlockingQueue<T>(capacity));
        dispatcher.subscribe(topics, eventType, queue);
        return queue;
    }

    public <T> BlockingQueue<T> createUnboundedQueue(Topics topics, Class<T> eventType) {
        EventQueue<T> queue = new EventQueue<T>(new LinkedBlockingQueue<T>());
        dispatcher.subscribe(topics, eventType, queue);
        return queue;
    }

    public <T> BlockingQueue<T> createPriorityQueue(Topics topics, Class<T> eventType) {
        EventQueue<T> queue = new EventQueue<T>(new PriorityBlockingQueue<T>());
        dispatcher.subscribe(topics, eventType, queue);
        return queue;
    }

    public Requestor createRequestor(final Topic topic) {
        return new Requestor() {
            @Override
            public Topic getTopic() {
                return topic;
            }

            @Override
            public <R> SendableRequest<R> createRequest() {
                return createRequest(Collections.<Object>emptyList());
            }

            @Override
            public <R> SendableRequest<R> createRequest(Object parameter) {
                return createRequest(Arrays.asList(parameter));
            }

            @Override
            public <R> SendableRequest<R> createRequest(Object... parameters) {
                return createRequest(Arrays.asList(parameters));
            }

            @Override
            public <R> SendableRequest<R> createRequest(final List<?> parameters) {
                checkNotNull(topic, "Missing topic");
                return new SendableRequest<R>() {
                    final Collection<FutureListener<R>> listeners = new CopyOnWriteArrayList<FutureListener<R>>();

                    @Override
                    public List<?> getParameters() {
                        return parameters;
                    }

                    @Override
                    public SendableRequest<R> addListener(FutureListener<R> listener) {
                        listeners.add(listener);
                        return this;
                    }

                    @Override
                    public Topic getTopic() {
                        return topic;
                    }

                    @Override
                    public Future<R> send() {
                        Message<R> msg = new Message<R>(listeners, parameters);
                        dispatcher.publish(topic, msg);
                        return msg;
                    }

                    @Override
                    public String toString() {
                        return "Request on " + topic;
                    }
                };
            }

            @Override
            public String toString() {
                return "Requestor on " + topic;
            }
        };
    }

    public Publisher createPublisher(final Iterable<Topic> topics) {
        return createPublisher(Iterables.toArray(checkNotNull(topics, "Missing topics"), Topic.class));
    }

    public Publisher createPublisher(final Topic... topics) {
        checkNotNull(topics, "Missing topics");
        return new Publisher() {
            @Override
            public Topic[] getTopics() {
                return topics;
            }

            @Override
            public void publish(Object event) {
                for (Topic topic : topics) {
                    dispatcher.publish(topic, event);
                }
            }

            @Override
            public String toString() {
                return "Publisher on " + Arrays.toString(topics);
            }
        };
    }

    public <T> T instanciate(Class<T> abstractClassOrInterface) {
        notNull(abstractClassOrInterface, "Abstract class or interface");
        T t = Proxy.proxy(abstractClassOrInterface, new PublisherInterceptor(this, abstractClassOrInterface));
        register(t);
        return t;
    }

    public void register(Object instance) {
        notNull(instance, "Instance");
        final Iterable<Method> methods = findMethods(getTargetClass(instance.getClass()));
        for (Method method : filter(methods, annotatedBy(Subscribe.class))) {
            Subscribe subscribe = method.getAnnotation(Subscribe.class);
            dispatcher.subscribe(Topic.anyOf(subscribe.topics()), subscribe.eventType(),
                    Subscribers.createSubscriber(instance, method));
        }
        for (Method method : filter(methods, annotatedBy(Answers.class))) {
            Answers answers = method.getAnnotation(Answers.class);
            dispatcher.subscribe(Topic.anyOf(answers.topics()), EventRequest.class,
                    Subscribers.createResponder(instance, method));
        }
    }

    /* STATIC CTOR */

    public static MycilaEvent with(Dispatcher dispatcher) {
        return new MycilaEvent(dispatcher);
    }

}