// ---------------------------------------------------------------------------
// jWebSocket - EventsPlugIn
// Copyright (c) 2010 Innotrade GmbH, jWebSocket.org
// ---------------------------------------------------------------------------
// This program 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 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 Lesser General Public License for
// more details.
// You should have received a copy of the GNU Lesser General Public License along
// with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>.
// ---------------------------------------------------------------------------
package org.jwebsocket.eventmodel.observable;
import java.lang.reflect.InvocationTargetException;
import org.jwebsocket.eventmodel.api.IObservable;
import org.jwebsocket.eventmodel.api.IListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.Collection;
import java.util.Map;
import javolution.util.FastMap;
import java.util.Set;
import javolution.util.FastSet;
import java.lang.reflect.Method;
import org.jwebsocket.eventmodel.util.CommonUtil;
/**
*
* @author kyberneees
*/
public abstract class ObservableObject implements IObservable {
private Integer maxExecutionTime = 60;
private Set<Class<? extends Event>> events = new FastSet<Class<? extends Event>>();
private Map<Class<? extends Event>, Set<IListener>> listeners = new FastMap<Class<? extends Event>, Set<IListener>>();
private void checkEvent(Class<? extends Event> aEventClass) throws Exception {
if (!events.contains(aEventClass)) {
throw new IndexOutOfBoundsException("The event '" + aEventClass + "' is not registered. Add it first!");
}
}
public void on(Class<? extends Event> aEventClass, IListener aListener) throws Exception {
checkEvent(aEventClass);
if (getListeners().containsKey(aEventClass)) {
getListeners().get(aEventClass).add(aListener);
} else {
getListeners().put(aEventClass, new FastSet<IListener>());
on(aEventClass, aListener);
}
}
public void on(Collection<Class<? extends Event>> aEventClassCollection, IListener aListener) throws Exception {
for (Class<? extends Event> c : aEventClassCollection) {
on(c, aListener);
}
}
public void addEvents(Class<? extends Event> aEventClass) {
if (!getEvents().contains(aEventClass)) {
getEvents().add(aEventClass);
}
}
public void addEvents(Collection<Class<? extends Event>> aEventClassCollection) {
for (Class<? extends Event> c : aEventClassCollection) {
addEvents(c);
}
}
public void removeEvents(Class<? extends Event> aEventClass) {
if (getEvents().contains(aEventClass)) {
getEvents().remove(aEventClass);
}
if (getListeners().containsKey(aEventClass)) {
getListeners().remove(aEventClass);
}
}
public void removeEvents(Collection<Class<? extends Event>> aEventClassCollection) {
for (Class<? extends Event> c : aEventClassCollection) {
removeEvents(c);
}
}
public void un(Class<? extends Event> aEventClass, IListener aListener) {
if (getListeners().containsKey(aEventClass)) {
getListeners().get(aEventClass).remove(aListener);
}
}
public void un(Collection<Class<? extends Event>> aEventClassCollection, IListener aListener) {
for (Class<? extends Event> c : aEventClassCollection) {
un(c, aListener);
}
}
public ResponseEvent notify(Event aEvent, ResponseEvent aResponseEvent, boolean useThreads) throws Exception {
checkEvent((Class<? extends Event>) aEvent.getClass());
aEvent.setSubject(this);
if (null == aResponseEvent) {
aResponseEvent = new ResponseEvent();
aResponseEvent.setId(aEvent.getId());
}
long initTime = System.currentTimeMillis();
if (getListeners().containsKey(aEvent.getClass()) && null != getListeners().get(aEvent.getClass())) {
if (getListeners().get(aEvent.getClass()).size() > 0) {
Set<IListener> calls = getListeners().get(aEvent.getClass());
if (true == useThreads) {
ExecutorService pool = Executors.newCachedThreadPool();
//Running in Threads
for (IListener it : calls) {
pool.submit(new CallableListener(it, aEvent, aResponseEvent));
}
//Wait for ThreadPool termination
CommonUtil.shutdownThreadPoolAndAwaitTermination(pool, getMaxExecutionTime());
} else {
//Iterative execution
for (IListener it : calls) {
ObservableObject.callProcessEvent(it, aEvent, aResponseEvent);
}
}
}
}
aResponseEvent.setElapsedTime(System.currentTimeMillis() - initTime);
return aResponseEvent;
}
public static void callProcessEvent(IListener aListener, Event aEvent, ResponseEvent aResponseEvent) throws Exception {
Class<? extends Event> aEventClass = aEvent.getClass();
Class<? extends IListener> aListenerClass = aListener.getClass();
Class<? extends ResponseEvent> aResponseClass = aResponseEvent.getClass();
try {
Method aMethod = aListenerClass.getMethod("processEvent", aEventClass, aResponseClass);
aMethod.invoke(aListener, aEventClass.cast(aEvent), aResponseClass.cast(aResponseEvent));
} catch (NoSuchMethodException ex) {
//Calling the base method
aListener.processEvent(aEvent, aResponseEvent);
} catch (InvocationTargetException ex) {
throw (Exception) ex.getTargetException();
}
}
public ResponseEvent notifyUntil(Event aEvent, ResponseEvent aResponseEvent) throws Exception {
checkEvent(aEvent.getClass());
aEvent.setSubject(this);
if (null == aResponseEvent) {
aResponseEvent = new ResponseEvent();
aResponseEvent.setId(aEvent.getId());
}
long initTime = System.currentTimeMillis();
if (getListeners().containsKey(aEvent.getClass()) && null != getListeners().get(aEvent.getClass())) {
if (getListeners().get(aEvent.getClass()).size() > 0) {
Set<IListener> calls = getListeners().get(aEvent.getClass());
for (IListener it : calls) {
ObservableObject.callProcessEvent(it, aEvent, aResponseEvent);
if (aEvent.isProcessed()) {
break;
}
}
}
}
aResponseEvent.setElapsedTime(System.currentTimeMillis() - initTime);
return aResponseEvent;
}
public boolean hasListeners(Class<? extends Event> aEventClass) throws Exception {
checkEvent(aEventClass);
if (getListeners().containsKey(aEventClass) && getListeners().get(aEventClass).size() > 0) {
return true;
}
return false;
}
public boolean hasListener(Class<? extends Event> aEventClass, IListener aListener) throws Exception {
checkEvent(aEventClass);
if (getListeners().containsKey(aEventClass) && getListeners().get(aEventClass).contains(aListener)) {
return true;
}
return false;
}
public void purgeListeners() {
getListeners().clear();
}
public void purgeEvents() {
getEvents().clear();
purgeListeners();
}
public boolean hasEvent(Class<? extends Event> aEventClass) {
return getEvents().contains(aEventClass);
}
/**
* @return the maxExecutionTime
*/
public Integer getMaxExecutionTime() {
return maxExecutionTime;
}
/**
* @param maxExecutionTime the maxExecutionTime to set
*/
public void setMaxExecutionTime(Integer maxExecutionTime) {
this.maxExecutionTime = maxExecutionTime;
}
/**
* @return the listeners
*/
public Map<Class<? extends Event>, Set<IListener>> getListeners() {
return listeners;
}
/**
* @param listeners the listeners to set
*/
public void setListeners(Map<Class<? extends Event>, Set<IListener>> listeners) {
this.listeners = listeners;
}
/**
* @return the events
*/
public Set<Class<? extends Event>> getEvents() {
return events;
}
/**
* @param events the events to set
*/
public void setEvents(Set<Class<? extends Event>> events) {
this.events = events;
}
}