/*
* ServerQueue.java
*
* Created on May 11, 2003, 9:32 PM
*/
package hep.aida.ref.remote;
import hep.aida.ref.remote.interfaces.AidaTreeClient;
import hep.aida.ref.remote.interfaces.AidaUpdateEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This is thread-safe queue for UpdateEvents.
* Events can be accumulated in the queue and then retrieved
* in one chunk. Mainly used on the server side.
* If client != null new thread will be started with this queue
* to send updates to the client.
*
* @author serbo
*/
public class RemoteServerQueue implements Runnable {
protected AidaTreeClient client;
protected List queue;
protected List holdQueue;
protected long blockingTimeout = 10000;
protected boolean keepRunning;
protected boolean blocking;
protected Object blockingLock;
protected boolean hold;
protected Logger remoteLogger;
/** Creates a new instance of UpdatableQueue */
public RemoteServerQueue() {
this(null);
}
public RemoteServerQueue(AidaTreeClient client) {
queue = new ArrayList(100);
holdQueue = new ArrayList(100);
keepRunning = true;
this.client = client;
this.hold = false;
this.blocking = false;
this.blockingLock = new Object();
remoteLogger = Logger.getLogger("hep.aida.ref.remote");
remoteLogger.fine("RemoteServerQueue: START");
if (client != null) new Thread(this).start();
}
public void setBlocking(boolean b) {
blocking = b;
synchronized (blockingLock) { blockingLock.notify(); }
}
public boolean isBlocking() { return blocking; }
/**
* Once the RemoteServerQueue is closed, it can not be restarted again.
*/
public synchronized void close() {
keepRunning = false;
queue.clear();
queue = null;
holdQueue.clear();
this.notify();
synchronized (blockingLock) { blockingLock.notify(); }
}
/*
* If hold set to "true", do not shedule events, just accumulate till
* hold is set to "false"
*/
public void setHold(boolean h) {
if (h) {
this.hold = h;
} else {
synchronized ( this ) {
this.hold = h;
queue.addAll(holdQueue);
holdQueue.clear();
this.notify();
synchronized (blockingLock) { blockingLock.notify(); }
}
}
}
public int size() { return (queue == null) ? 0 : queue.size(); }
/**
* Add events to the queue.
*/
public void schedule(AidaUpdateEvent event) {
remoteLogger.finest("RemoteServerQueue.schedule id="+event.id()+", path="+event.path()+", type="+event.nodeType()+", event="+event);
if (keepRunning) addToQueue(event);
}
/**
* Returns the array of events that are currently in the queue.
* Also deletes those events from the queue. Never returns null.
*/
public AidaUpdateEvent[] getEvents() {
AidaUpdateEvent[] events = new AidaUpdateEvent[0];
int size = size();
remoteLogger.finest("RemoteServerQueue.getEvents size="+size);
if (size == 0) {
if (client == null && blocking) {
synchronized(blockingLock) {
try {
blockingLock.wait(blockingTimeout);
} catch (Exception e) {
e.printStackTrace();
}
}
} else return events;
}
synchronized ( this ) {
size = size();
if (size == 0) return events;
events = new AidaUpdateEvent[size];
queue.toArray(events);
queue.clear();
}
return events;
}
/**
* This method adds event to the queue and can do some cleanup, like
* remove multiple update events for the same path (not implemented yet), etc.
*/
protected void addToQueue(AidaUpdateEvent event) {
synchronized ( this ) {
if (hold) holdQueue.add(event);
else {
queue.add(event);
this.notify();
synchronized (blockingLock) { blockingLock.notify(); }
}
}
}
// Runnable methods
/**
* In Duplex mode sends updates to AidaTreeClient
*/
public void run() {
int size = 0;
AidaUpdateEvent[] events = null;
while (keepRunning) {
try {
synchronized (this) {
if(size() == 0) this.wait();
if (queue == null) return;
size = size();
if (size > 0) {
events = getEvents();
}
}
remoteLogger.finest("RemoteServerQueue.run Processing: "+size);
if (events != null || events.length > 0) {
if (client != null) client.stateChanged(events);
}
} catch (InterruptedException e2) {
remoteLogger.log(Level.INFO, "RemoteServerOueue InterruptedException.", e2);
remoteLogger.log(Level.FINE, "", e2.getStackTrace());
} catch (Exception e3) {
remoteLogger.log(Level.INFO, "Exception in RemoteServerQueue: ", e3);
remoteLogger.log(Level.FINE, "", e3.getStackTrace());
} // end of try/catch
} // end of while
} //end of run
}