/*
* JABM - Java Agent-Based Modeling Toolkit
* Copyright (C) 2013 Steve Phelps
*
* This program 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.
*
* This program 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.
*/
package net.sourceforge.jabm.event;
import java.io.Serializable;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.log4j.Logger;
public abstract class AbstractModel implements Cloneable, Serializable, Model {
/**
* EventListeners that subscribe to all classes of events.
*/
protected ConcurrentLinkedQueue<EventListener> genericListeners;
/**
* A map of EventListeners that subscribe to a specific class of events,
* keyed on the class of the event.
*/
@SuppressWarnings("rawtypes")
protected ConcurrentHashMap<Class, ConcurrentLinkedQueue<EventListener>> specificListeners;
protected Stack<EventListener> deleteQueue;
static Logger logger = Logger.getLogger(AbstractModel.class);
@SuppressWarnings("rawtypes")
public AbstractModel() {
genericListeners = new ConcurrentLinkedQueue<EventListener>();
specificListeners = new ConcurrentHashMap<Class, ConcurrentLinkedQueue<EventListener>>();
deleteQueue = new Stack<EventListener>();
}
/* (non-Javadoc)
* @see net.sourceforge.jabm.event.Model#removeListener(net.sourceforge.jabm.event.EventListener)
*/
@Override
public void removeListener(EventListener listener) {
deleteQueue.add(listener);
}
/* (non-Javadoc)
* @see net.sourceforge.jabm.event.Model#addListener(net.sourceforge.jabm.event.EventListener)
*/
@Override
public void addListener(EventListener listener) {
if (!genericListeners.contains(listener)) {
genericListeners.add(listener);
}
}
/* (non-Javadoc)
* @see net.sourceforge.jabm.event.Model#addListener(java.lang.Class, net.sourceforge.jabm.event.EventListener)
*/
@Override
@SuppressWarnings("rawtypes")
public void addListener(Class eventClass, EventListener listener) {
ConcurrentLinkedQueue<EventListener> listeners = specificListeners.get(eventClass);
if (listeners == null) {
listeners = new ConcurrentLinkedQueue<EventListener>();
specificListeners.put(eventClass, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void fireEvent(SimEvent event) {
processDeleteQueue();
notifyGenericListeners(event);
processDeleteQueue();
notifySpecificListeners(event);
processDeleteQueue();
}
@SuppressWarnings("rawtypes")
protected void processDeleteQueue() {
while (!deleteQueue.isEmpty()) {
EventListener listener = deleteQueue.pop();
genericListeners.remove(listener);
for(Class key : specificListeners.keySet()) {
ConcurrentLinkedQueue<EventListener> listeners = specificListeners.get(key);
@SuppressWarnings("unused")
boolean removed = listeners.remove(listener);
}
}
}
@SuppressWarnings("rawtypes")
public void notifySpecificListeners(SimEvent event) {
for (Class eventClass : specificListeners.keySet()) {
if (eventClass.isInstance(event)) {
ConcurrentLinkedQueue<EventListener> listeners = specificListeners
.get(eventClass);
for (EventListener listener : listeners) {
if (!deleteQueue.contains(listener)) {
listener.eventOccurred(event);
}
}
}
}
}
public void notifyGenericListeners(SimEvent event) {
for (EventListener listener : genericListeners) {
if (!deleteQueue.contains(listener)) {
listener.eventOccurred(event);
}
}
}
public void clearListeners() {
specificListeners.clear();
genericListeners.clear();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}