org.apache.ambari.event.AsyncDispatcher.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ambari.event.AsyncDispatcher.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.ambari.event;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Dispatches events in a separate thread. Currently only single thread does
 * that. Potentially there could be multiple channels for each event type
 * class and a thread pool can be used to dispatch the events.
 */
@SuppressWarnings("rawtypes")
public class AsyncDispatcher implements Dispatcher {

    private static final Log LOG = LogFactory.getLog(AsyncDispatcher.class);

    private final BlockingQueue<Event> eventQueue;
    private volatile boolean stopped = false;

    private Thread eventHandlingThread;
    protected final Map<Class<? extends Enum>, EventHandler> eventDispatchers;

    public AsyncDispatcher() {
        this(new HashMap<Class<? extends Enum>, EventHandler>(), new LinkedBlockingQueue<Event>());
    }

    AsyncDispatcher(Map<Class<? extends Enum>, EventHandler> eventDispatchers, BlockingQueue<Event> eventQueue) {
        this.eventQueue = eventQueue;
        this.eventDispatchers = eventDispatchers;
    }

    Runnable createThread() {
        return new Runnable() {
            @Override
            public void run() {
                while (!stopped && !Thread.currentThread().isInterrupted()) {
                    Event event;
                    try {
                        event = eventQueue.take();
                    } catch (InterruptedException ie) {
                        LOG.info("AsyncDispatcher thread interrupted", ie);
                        return;
                    }
                    if (event != null) {
                        dispatch(event);
                    }
                }
            }
        };
    }

    @Override
    public void start() {
        eventHandlingThread = new Thread(createThread());
        eventHandlingThread.start();
    }

    public void stop() {
        stopped = true;
        eventHandlingThread.interrupt();
        try {
            eventHandlingThread.join();
        } catch (InterruptedException ie) {
            LOG.debug("Interruped Exception while stopping", ie);
        }

    }

    @SuppressWarnings("unchecked")
    protected void dispatch(Event event) {
        //all events go thru this loop
        LOG.debug("Dispatching the event " + event.getClass().getName() + "." + event.toString());

        Class<? extends Enum> type = event.getType().getDeclaringClass();

        try {
            eventDispatchers.get(type).handle(event);
        } catch (Throwable t) {
            //TODO Maybe log the state of the queue
            LOG.fatal("Error in dispatcher thread. Exiting..", t);
            System.exit(-1);
        }
    }

    @Override
    @SuppressWarnings("rawtypes")
    public void register(Class<? extends Enum> eventType, EventHandler handler) {
        /* check to see if we have a listener registered */
        @SuppressWarnings("unchecked")
        EventHandler<Event> registeredHandler = (EventHandler<Event>) eventDispatchers.get(eventType);
        LOG.info("Registering " + eventType + " for " + handler.getClass());
        if (registeredHandler == null) {
            eventDispatchers.put(eventType, handler);
        } else if (!(registeredHandler instanceof MultiListenerHandler)) {
            /* for multiple listeners of an event add the multiple listener handler */
            MultiListenerHandler multiHandler = new MultiListenerHandler();
            multiHandler.addHandler(registeredHandler);
            multiHandler.addHandler(handler);
            eventDispatchers.put(eventType, multiHandler);
        } else {
            /* already a multilistener, just add to it */
            MultiListenerHandler multiHandler = (MultiListenerHandler) registeredHandler;
            multiHandler.addHandler(handler);
        }
    }

    @Override
    public EventHandler getEventHandler() {
        return new GenericEventHandler();
    }

    class GenericEventHandler implements EventHandler<Event> {
        public void handle(Event event) {
            /* all this method does is enqueue all the events onto the queue */
            int qSize = eventQueue.size();
            if (qSize != 0 && qSize % 1000 == 0) {
                LOG.info("Size of event-queue is " + qSize);
            }
            int remCapacity = eventQueue.remainingCapacity();
            if (remCapacity < 1000) {
                LOG.info("Very low remaining capacity in the event-queue: " + remCapacity);
            }
            try {
                eventQueue.put(event);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
    }

    /**
     * Multiplexing an event. Sending it to different handlers that
     * are interested in the event.
     * @param <T> the type of event these multiple handlers are interested in.
     */
    @SuppressWarnings("rawtypes")
    static class MultiListenerHandler implements EventHandler<Event> {
        List<EventHandler<Event>> listofHandlers;

        public MultiListenerHandler() {
            listofHandlers = new ArrayList<EventHandler<Event>>();
        }

        @Override
        public void handle(Event event) {
            for (EventHandler<Event> handler : listofHandlers) {
                handler.handle(event);
            }
        }

        void addHandler(EventHandler<Event> handler) {
            listofHandlers.add(handler);
        }

    }
}