/* * 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); } } }