/*
* Created on Oct 11, 2006 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
* (jactr.org) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have
* received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jactr.core.event;
import java.util.Collection;
import java.util.Collections;
import java.util.ListIterator;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import javolution.util.FastList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.concurrent.ExecutorServices;
/**
* class that handles the nitty gritty of tracking listeners, executors, and
* propogating that the firing events correctly
*
* @author developer
*/
public class ACTREventDispatcher<S, L>
{
/**
* logger definition
*/
static public final Log LOGGER = LogFactory
.getLog(ACTREventDispatcher.class);
private FastList<Pair> _actualListeners;
private boolean _haveEncounteredREE = false;
public ACTREventDispatcher()
{
}
synchronized public void clear()
{
if (_actualListeners != null)
{
FastList.recycle(_actualListeners);
_actualListeners = null;
}
}
synchronized public void addListener(L listener, Executor executor)
{
if (listener == null)
throw new IllegalArgumentException("Listener must not be null");
if (executor == null) executor = ExecutorServices.INLINE_EXECUTOR;
Pair p = new Pair(listener, executor);
if (_actualListeners == null) _actualListeners = FastList.newInstance();
_actualListeners.add(p);
}
synchronized public void removeListener(L listener)
{
if (_actualListeners == null) return;
ListIterator<Pair> itr = _actualListeners.listIterator();
while (itr.hasNext())
{
Pair pair = itr.next();
if (pair.hasListener(listener)) itr.remove();
}
if (_actualListeners.size() == 0)
{
FastList.recycle(_actualListeners);
_actualListeners = null;
}
}
synchronized public boolean hasListeners()
{
return _actualListeners != null && _actualListeners.size() != 0;
}
public void fire(IACTREvent<S, L> event)
{
FastList<Pair> container = null;
synchronized (this)
{
if (_actualListeners == null) return;
container = FastList.newInstance();
container.addAll(_actualListeners);
}
for (Pair pair : container)
pair.fire(event);
FastList.recycle(container);
}
private class Pair
{
private Executor _executor;
private L _listener;
public Pair(L listener, Executor executor)
{
_executor = executor;
_listener = listener;
}
public boolean hasListener(L listener)
{
return _listener.equals(listener);
}
public void fire(final IACTREvent<S, L> event)
{
Runnable runner = new Runnable() {
public void run()
{
try
{
event.fire(_listener);
}
catch (Exception e)
{
LOGGER.error("Uncaught exception during event firing of " + event
+ " to " + _listener, e);
}
}
};
try
{
_executor.execute(runner);
}
catch (RejectedExecutionException ree)
{
if (!_haveEncounteredREE)
{
if (LOGGER.isWarnEnabled())
{
LOGGER.warn(String.format(
"%s rejected processing of actr event (%s) by listener (%s).",
_executor, event.getClass().getSimpleName(), _listener
.getClass().getName()));
LOGGER
.warn("This is normal during end-of-run processing if your model produced data faster than it could be processed,");
LOGGER
.warn("by the IDE or background tools. If you see this warning mid-run, something may be wrong, please see the exception.");
LOGGER
.warn(String
.format(
"Suppressing further rejection warnings for this event source (%s).",
event.getSource().getClass().getName()));
LOGGER.warn(ree);
}
_haveEncounteredREE = true;
}
}
}
}
/**
* @return
*/
synchronized public Collection<L> getListeners()
{
if (_actualListeners == null) return Collections.EMPTY_LIST;
FastList<L> listeners = FastList.newInstance();
for (Pair pair : _actualListeners)
listeners.add(pair._listener);
return listeners;
}
}