/* * Copyright (C) 2012 Google Inc. * * 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 org.ros.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; /** * @author damonkohler@google.com (Damon Kohler) * * @param <T> * the listener type */ public class EventDispatcher<T> extends CancellableLoop { private final T listener; private final MessageBlockingQueue<SignalRunnable<T>> events; private final CountDownLatch fullyShutdownLatch = new CountDownLatch(1); private AtomicBoolean isShuttingDown = new AtomicBoolean(false); public EventDispatcher(T listener, int queueCapacity) { this.listener = listener; events = MessageBlockingQueueFactory.newMessageBlockingQueue(queueCapacity, false); } /** * A signal must take place. * * @param signalRunnable * the runnable that contains the signal */ public void signal(final SignalRunnable<T> signalRunnable) { if (isShuttingDown.get()) { try { fullyShutdownLatch.await(); } catch (InterruptedException e) { // Don't care } // Just in case something came in while we were waiting. // Done this way so always in order it was supposed to happen. try { events.put(signalRunnable); } catch (InterruptedException e) { // Don't care. } flush(); } else { try { events.put(signalRunnable); } catch (InterruptedException e) { // Don't care. } } } @Override public void loop() throws InterruptedException { SignalRunnable<T> signalRunnable = events.take(); signalRunnable.run(listener); } @Override protected void cleanup() { isShuttingDown.set(true); flush(); fullyShutdownLatch.countDown(); } /** * Flush all events out of the event dispatcher. * * <p> * This is run after the dispatcher is shut down and empties out any events * which have not been written. */ private void flush() { SignalRunnable<T> signalRunnable; while ((signalRunnable = events.poll()) != null) { try { signalRunnable.run(listener); } catch (Exception e) { e.printStackTrace(); } } } }