package jas2.util.rmi;

import java.rmi.*;
import java.rmi.server.*;
import java.io.*;
import java.util.*;


/** This class deals with delivering events to a remote process using RMI.
 * Since RMI does not have any asychronous method of delivering events, 
 * they are queued up and delivered in a chunk by an event delivery thread.
 * Events placed in the queue can be "Preemptable", in which case a later
 * event may preempt an earlier one, making it unnecessary to deliver the
 * earlier events.
 */
public class RMIEventQueue extends Thread
{
	public RMIEventQueue(RemoteEventReceiver receiver)
	{
		this.receiver = receiver;
		start();
	}
	public void dispose()
	{
		Enumeration e = m_obs.elements();
		while (e.hasMoreElements())
		{
			RMIObserver obs = (RMIObserver) e.nextElement();
			obs.stop();
		}
		interrupt(); // stop the event delivery thread, and allow it to clean up
	}
	public Observer setEventSource(RMIDestination destination)
	{
		RMIObserver obs = new RMIObserver(destination);
		m_obs.addElement(obs);
		return obs;
	}
	public void run()
	{
		try
		{
			for (;;)
			{
				boolean messageWaiting = false;
				synchronized (this)
				{
					Enumeration e = m_obs.elements();		
					while (e.hasMoreElements())
					{
						RMIObserver a = (RMIObserver) e.nextElement();
						messageWaiting = a.hasMessages();
						if (messageWaiting) break;
					}
					if (!messageWaiting) wait();
				}
				
				int n = 0;
				Enumeration e = m_obs.elements();		
				while (e.hasMoreElements())
				{
					RMIObserver a = (RMIObserver) e.nextElement();
					int i = a.getNUpdates();
					if (i>0) n += i+1;
				}

				if (n == 0) continue;
				else
				{
					Serializable[] s = new Serializable[n];
					int i = 0;

					e = m_obs.elements();
					while (e.hasMoreElements())
					{
						RMIObserver a = (RMIObserver) e.nextElement();
						Vector v = a.getUpdates();
						if (!v.isEmpty())
						{
							s[i++] = a.getDestination();
							Enumeration e2 = v.elements();
							while (e2.hasMoreElements())
							{
								s[i++] = (Serializable) e2.nextElement();
							}
						}	
					}
					receiver.remoteUpdate(s);
				}
			}
		}
		catch (InterruptedException e) 
		{
			System.out.println("RMIEventQueue Thread terminating");
			receiver = null;
		}
		catch (RemoteException e)
		{
			System.out.println("Error dispatching events "+e);
		}
		finally
		{
			receiver = null;
			m_obs = null;
		}
	}
	private RemoteEventReceiver receiver;
	private Vector m_obs = new Vector();

	private class RMIObserver implements Observer
	{
		RMIObserver(RMIDestination dest)
		{
			this.dest = dest;
		}
		RMIDestination getDestination()
		{
			return dest;
		}
		void stop()
		{
			stopped = true;
		}
		public void update(Observable obs, Object arg)
		{
			if (stopped) return;
			if (arg instanceof Serializable)
			{
				boolean wasEmpty = m_active.isEmpty();
				m_active.addElement(arg);
				if (wasEmpty) synchronized (RMIEventQueue.this) { RMIEventQueue.this.notifyAll(); }
			}
			else throw new RuntimeException("Argument for RMIObserver not serializable");
		}
		boolean hasMessages()
		{
			return !stopped && !m_active.isEmpty();
		}
		int getNUpdates() 
		{
			m_result.removeAllElements();
			if (m_active.isEmpty()) return 0;

			Vector v = m_active;
			m_queue.removeAllElements();
			m_active = m_queue; // Updates after this go to new queue;	
			m_queue = v;

			int size = v.size();

			outer: for (int i=0; i 

Ads help maintain this website.