diff --git a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java new file mode 100644 index 000000000..10f044405 --- /dev/null +++ b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java @@ -0,0 +1,235 @@ +/* + * 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 net.java.sip.communicator.service.sysactivity.*; +import net.java.sip.communicator.service.sysactivity.event.*; +import net.java.sip.communicator.util.*; + +import java.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. + * + * @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); + + 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); + } + } +} diff --git a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java index 705d2ea2e..f88fc9077 100644 --- a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java +++ b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java @@ -30,10 +30,10 @@ public class SystemActivityNotificationsServiceImpl SystemActivityNotificationsServiceImpl.class.getName()); /** - * A list of listeners registered for system activity events. + * The thread dispatcher of network change events. */ - private final List activityChangeListeners = - new LinkedList(); + private SystemActivityEventDispatcher eventDispatcher = + new SystemActivityEventDispatcher(); /** * A list of listeners registered for idle events. @@ -130,6 +130,8 @@ public void stop() NetworkManagerListenerImpl.getInstance().stop(); } + eventDispatcher.stop(); + running = false; synchronized(this) @@ -148,13 +150,7 @@ public void stop() public void addSystemActivityChangeListener( SystemActivityChangeListener listener) { - synchronized (activityChangeListeners) - { - if (!activityChangeListeners.contains(listener)) - { - activityChangeListeners.add(listener); - } - } + eventDispatcher.addSystemActivityChangeListener(listener); } /** @@ -166,10 +162,7 @@ public void addSystemActivityChangeListener( public void removeSystemActivityChangeListener( SystemActivityChangeListener listener) { - synchronized (activityChangeListeners) - { - activityChangeListeners.remove(listener); - } + eventDispatcher.removeSystemActivityChangeListener(listener); } /** @@ -416,28 +409,15 @@ else if(idleTime != 0) */ protected void fireSystemActivityEvent(SystemActivityEvent evt) { - Collection listeners; - synchronized (this.activityChangeListeners) - { - listeners = new ArrayList( - this.activityChangeListeners); - } - - if (logger.isDebugEnabled()) - logger.debug("Dispatching SystemActivityEvent Listeners=" - + listeners.size() + " evt=" + evt); - - for (SystemActivityChangeListener listener : listeners) + // give time to java to dispatch same + // event and populate its network interfaces + if(evt.getEventID() == SystemActivityEvent.EVENT_NETWORK_CHANGE + && OSUtils.IS_WINDOWS) { - try - { - listener.activityChanged(evt); - } - catch (Throwable e) - { - logger.error("Error delivering event", e); - } + eventDispatcher.fireSystemActivityEvent(evt, 500); } + else + eventDispatcher.fireSystemActivityEvent(evt); } /**