/*
* Copyright 2012 Research Studios Austria Forschungsges.m.b.H.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package won.bot.framework.eventbot.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import won.bot.framework.eventbot.EventListenerContext;
import won.bot.framework.eventbot.event.Event;
import won.bot.framework.eventbot.event.impl.lifecycle.ErrorEvent;
import won.bot.framework.eventbot.event.impl.listener.FinishedEvent;
import won.bot.framework.eventbot.filter.EventFilter;
/**
* Base class for event listeners
*/
public abstract class BaseEventListener implements EventListener
{
protected final Logger logger = LoggerFactory.getLogger(getClass());
private EventListenerContext context;
private int eventCount = 0;
private int exceptionCount = 0;
private long millisExecuting = 0;
private boolean unsubscribeOnException = true;
protected EventFilter eventFilter = null;
protected String name = getClass().getSimpleName();
/**
* Constructor is private so that subclasses must implement the one-arg constructor.
*/
private BaseEventListener(){}
protected BaseEventListener(final EventListenerContext context)
{
this.context = context;
}
protected BaseEventListener(final EventListenerContext context, final EventFilter eventFilter)
{
this(context);
this.eventFilter = eventFilter;
}
protected BaseEventListener(final EventListenerContext context, final String name)
{
this(context);
this.name = name;
}
protected BaseEventListener(final EventListenerContext context, final String name, final EventFilter eventFilter)
{
this(context,eventFilter);
this.name = name;
}
@Override
public final void onEvent(final Event event) throws Exception{
if (!shouldHandleEvent(event)){
//allow for ignoring events. Such event are not counted.
return;
}
if (logger.isDebugEnabled()){
logger.debug("handling event {} with listener {}",event, this);
}
countEvent(event);
long startTime = System.currentTimeMillis();
try {
doOnEvent(event);
} catch (Throwable e) {
logger.warn("Caught Throwable during event processing by EventListener. Swallowing and publishing an ErrorEvent",
e);
if (unsubscribeOnException) {
context.getEventBus().unsubscribe(this);
}
context.getEventBus().publish(new ErrorEvent(e));
countThrowable(e);
} finally {
noteTimeExecuting(startTime);
}
}
/**
* Publishes an event indicating that the listener is finished. Useful for chaining listeners.
* Only use when this is really the case.
*/
protected void publishFinishedEvent()
{
getEventListenerContext().getEventBus().publish(new FinishedEvent(this));
}
public long getMillisExecuting()
{
return millisExecuting;
}
public int getExceptionCount()
{
return exceptionCount;
}
public int getEventCount()
{
return eventCount;
}
public boolean isUnsubscribeOnException() {
return unsubscribeOnException;
}
public void setUnsubscribeOnException(final boolean unsubscribeOnException) {
this.unsubscribeOnException = unsubscribeOnException;
}
protected synchronized void countThrowable(final Throwable e){
this.exceptionCount ++;
}
private synchronized void noteTimeExecuting(final long startTime)
{
this.millisExecuting += System.currentTimeMillis() - startTime;
}
private synchronized void countEvent(final Event event)
{
this.eventCount ++;
}
protected abstract void doOnEvent(Event event) throws Exception;
protected EventListenerContext getEventListenerContext(){
return context;
}
/**
* Determines whether the given event should be processed or ignored. If it is ignored,
* it is not counted and does not influence the listener's behavior. The default implementation
* accepts all events.
* @param event
* @return
*/
protected final boolean shouldHandleEvent(final Event event){
return eventFilter == null ? true : eventFilter.accept(event);
}
@Override
public String toString()
{
return getClass().getSimpleName()+"{" +
"name='" + name + '\'' +
", eventCount=" + eventCount +
'}';
}
}