/**
* Copyright (C) 2013 Colorado School of Mines
*
* This file is part of the Interface Software Development Kit (SDK).
*
* The InterfaceSDK is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The InterfaceSDK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the InterfaceSDK. If not, see <http://www.gnu.org/licenses/>.
*/
package edu.mines.acmX.exhibit.input_services.events;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* The EventManager is a singleton responsible for managing events generated
* by input sources. The manager will ensure that the order of events are
* preserved.
*
* <br/><br/>
*
* This manager is neat because it's the core for our event-driven design.
* The need for a ConcurrentQueue/Thread ensures the order that events
* are sent off to their receivers. The other primary reason was to ensure we
* do not busy wait.
*
* The idea is if we attempt to follow the 'synchronized' route, there's no
* guarantee that the next 'event' that enters the synchronized block was
* THE chronologically next event preceding the prior one that was in the
* block.
*
* @author Aakash Shah
* @author Ryan Stauffer
*
*/
public class EventManager {
private static Logger log = LogManager.getLogger(EventManager.class);
private static EventManager instance = null;
private Map<EventType, List<InputReceiver>> eventReceivers;
private Queue<Event> events;
private EventManager() {
eventReceivers = new HashMap<EventType, List<InputReceiver>>();
events = new ConcurrentLinkedQueue<Event>();
}
public static EventManager getInstance() {
if (instance == null) {
instance = new EventManager();
}
return instance;
}
/**
* Adds the event to the event queue and ensures the event will be received
* by all registered listeners in the order this event arrived in.
*
* @param type the type of event to fire the event under
* @param data arbitrary data to package along with the event
*
* @see {@link #sendEvent} {@link EventType}
*/
public void fireEvent(EventType type, Object data) {
Event ev = new Event(type, data);
events.add(ev);
sendEvent();
}
/**
* Registers a receiver to be associated with a type of event.
*
* @param type the type of event
* @param receiver the receiver
*
* @see {@link EventType}
*/
public void registerReceiver(EventType type, InputReceiver receiver) {
// Decide whether to make a new list/append to one already in the map.
if (eventReceivers.containsKey(type)) {
eventReceivers.get(type).add(receiver);
} else {
List<InputReceiver> listOfReceivers = new ArrayList<InputReceiver>();
listOfReceivers.add(receiver);
eventReceivers.put(type, listOfReceivers);
}
}
/**
* Removes all registered receivers for a given event type.
* @param type type of event.
*/
public void removeReceivers(EventType type) {
if (eventReceivers.containsKey(type)) {
eventReceivers.remove(type);
}
}
/**
* A synchronized method that will ensure the head of the event queue is
* received by all registered listeners before moving onto the next event.
* <br/>
* If no receivers are registered for this event, then the event is lost.
*/
public synchronized void sendEvent() {
Event e = events.poll();
// Check if anyone is actually listening for this event
if (eventReceivers.containsKey(e.getName())) {
List<InputReceiver> receivers = eventReceivers.get(e.getName());
for (InputReceiver r : receivers) {
r.receiveInput(e.getName(), e.getData());
}
}
}
}