Dispatcher.java

/*******************************************************************************
 * Copyright (c) 2004, 2013 Steve Flasby
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * <ul>
 *     <li>Redistributions of source code must retain the above copyright notice,
 *         this list of conditions and the following disclaimer.</li>
 *     <li>Redistributions in binary form must reproduce the above copyright notice,
 *         this list of conditions and the following disclaimer in the documentation
 *         and/or other materials provided with the distribution.</li>
 * </ul>
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
package org.flasby.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import lombok.extern.log4j.Log4j2;


/**
 * invokes a list of registered Callbacks with either an error or a success
 * message.
 * Can be used to easily add event listeners to event-driven, network socket listeners.
 * I use it to dispatch messages to registers listeners:
 * <pre>
 * {@code
 * 				Dispatcher<Msg> dispatcher = new Dispatcher<Msg>();
 * 				Msg msg; 
 * 				do {
 * 					try {;
 * 						msg = readMessage();
 * 						if ( msg!=null ) {
 * 							dispatcher.dispatch(msg);
 * 						}
 * 					} catch ( Exception ioe ) {
 * 						ex = ioe;
 * 						dispatcher.dispatchError(ioe);
 * 					}
 * 				} while ( ex==null && !(msg instanceof EndOfSessionMsg) );
 * }
 *  </pre>
 * @author steve
 *
 * @param <T>
 */
@Log4j2
public class Dispatcher <T> {
	private Map<Integer, Callback<T>> mCallbacks = new ConcurrentHashMap<Integer, Callback<T>>(); // Maps.newConcurrentMap();
	
	public void dispatch(T toDispatch) {
		for (Callback<T> callback : mCallbacks.values()) {
			callback.onSuccess( toDispatch );
		}
		
	}

	private AtomicInteger mInteger = new AtomicInteger();
	
	public void dispatchError(Exception ex) {
		for (Callback<T> callback : mCallbacks.values()) {
			callback.onFailure( ex );
		}
	}

	public int register( Callback<T> callback ) {
		mCallbacks.put(mInteger.incrementAndGet(), callback);
		return mInteger.get();
	}

	public void unregister(int idFrom ) {
		mCallbacks.remove(idFrom);
	}
	
	/**
	 * is a polite thing to do.
	 */
	public void close() {
		if (mCallbacks.size()!=0) {
			LOG.error( "There are callbacks still registered, they will not be cleaned up.", new RuntimeException() );
		}
	}
}