/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.sysactivity;
import java.util.*;
import net.java.sip.communicator.service.sysactivity.*;
import net.java.sip.communicator.service.sysactivity.event.*;
import net.java.sip.communicator.util.*;
/**
* The class implements a dispatch event thread. The thread will
* fire event every time it is added through the fireSystemActivityEvent()
* method and would then deliver it to a registered listener if any.
* If the event has time set we used it as a delay before dispatching the event.
*
* @author Damian Minkov
*/
public class SystemActivityEventDispatcher
implements Runnable
{
/**
* Our class logger.
*/
private static Logger logger =
Logger.getLogger(SystemActivityEventDispatcher.class);
/**
* A list of listeners registered for system activity events.
*/
private final List listeners =
new LinkedList();
/**
* start/stop indicator.
*/
private boolean stopped = true;
/**
* The thread that runs this dispatcher.
*/
private Thread dispatcherThread = null;
/**
* The events to dispatch.
*/
private Map eventsToDispatch
= new LinkedHashMap();
/**
* Registers a listener that would be notified of changes that have occurred
* in the underlying system.
*
* @param listener the listener that we'd like to register for changes in
* the underlying system.
*/
public void addSystemActivityChangeListener(
SystemActivityChangeListener listener)
{
synchronized(listeners)
{
if(!listeners.contains(listener))
{
listeners.add(listener);
if(dispatcherThread == null)
{
dispatcherThread = new Thread(this);
dispatcherThread.start();
}
}
}
}
/**
* Remove the specified listener so that it won't receive further
* notifications of changes that occur in the underlying system
*
* @param listener the listener to remove.
*/
public void removeSystemActivityChangeListener(
SystemActivityChangeListener listener)
{
synchronized(listeners)
{
listeners.remove(listener);
}
}
/**
* Interrupts this dispatcher so that it would no longer disptach events.
*/
public void stop()
{
synchronized(eventsToDispatch)
{
stopped = true;
eventsToDispatch.notifyAll();
dispatcherThread = null;
}
}
/**
* Delivers the specified event to all registered listeners.
*
* @param evt the SystemActivityEvent that we'd like delivered to
* all registered message listeners.
*/
protected void fireSystemActivityEvent(SystemActivityEvent evt)
{
fireSystemActivityEvent(evt, 0);
}
/**
* Delivers the specified event to all registered listeners. Without
* using the thread, but delivering them in the calling thread.
*
* @param evt the SystemActivityEvent that we'd like delivered to
* all registered message listeners.
*/
protected void fireSystemActivityEventCurrentThread(SystemActivityEvent evt)
{
List listenersCopy = new ArrayList
(listeners);
for (int i = 0; i < listenersCopy.size(); i++)
{
fireSystemActivityEvent(
evt,
listenersCopy.get(i));
}
}
/**
* Delivers the specified event to all registered listeners.
*
* @param evt the SystemActivityEvent that we'd like delivered to
* all registered message listeners.
* @param wait time in ms. to wait before firing the event.
*/
protected void fireSystemActivityEvent(SystemActivityEvent evt, int wait)
{
synchronized(eventsToDispatch)
{
eventsToDispatch.put(evt, wait);
eventsToDispatch.notifyAll();
if(dispatcherThread == null && listeners.size() > 0)
{
dispatcherThread = new Thread(this);
dispatcherThread.start();
}
}
}
/**
* Delivers the specified event to the listener.
*
* @param evt the SystemActivityEvent that we'd like delivered to
* the listener.
* @param listener that will receive the event.
*/
private void fireSystemActivityEvent(SystemActivityEvent evt,
SystemActivityChangeListener listener)
{
if (logger.isDebugEnabled())
logger.debug("Dispatching SystemActivityEvent Listeners="
+ listeners.size() + " evt=" + evt);
if(logger.isInfoEnabled() &&
(evt.getEventID() == SystemActivityEvent.EVENT_NETWORK_CHANGE
|| evt.getEventID() == SystemActivityEvent.EVENT_DNS_CHANGE))
{
logger.info("Dispatching SystemActivityEvent Listeners="
+ listeners.size() + " evt=" + evt);
}
try
{
listener.activityChanged(evt);
}
catch (Throwable e)
{
logger.error("Error delivering event", e);
}
}
/**
* Runs the waiting thread.
*/
public void run()
{
try
{
stopped = false;
while(!stopped)
{
Map.Entry eventToProcess = null;
List listenersCopy;
synchronized(eventsToDispatch)
{
if(eventsToDispatch.size() == 0)
{
try {
eventsToDispatch.wait();
}
catch (InterruptedException iex){}
}
//no point in dispatching if there's no one
//listening
if (listeners.size() == 0)
continue;
//store the ref of the listener in case someone resets
//it before we've had a chance to notify it.
listenersCopy = new ArrayList
(listeners);
Iterator> iter =
eventsToDispatch.entrySet().iterator();
if(iter.hasNext())
{
eventToProcess = iter.next();
iter.remove();
}
}
if(eventToProcess != null && listenersCopy != null)
{
if(eventToProcess.getValue() > 0)
synchronized(this)
{
try{
wait(eventToProcess.getValue());
}catch(Throwable t){}
}
for (int i = 0; i < listenersCopy.size(); i++)
{
fireSystemActivityEvent(
eventToProcess.getKey(),
listenersCopy.get(i));
}
}
eventToProcess = null;
listenersCopy = null;
}
} catch(Throwable t)
{
logger.error("Error dispatching thread ended unexpectedly", t);
}
}
}