package cern.laser.util.buffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
/**
* A buffering utility class. It is an adapter for a SynchroBuffer instance allowing to detach the buffer consumer
* thread from the SynchroBuffer itself for slow consumers.
*
* @author F.Calderini
*/
public class SynchroBufferAdapter {
private static final Logger LOGGER = Logger.getLogger(SynchroBufferAdapter.class.getName());
private List queue;
private SynchroBuffer adaptee;
private SynchroBufferListener listener;
private Thread pullingThread;
private Boolean enabled = Boolean.TRUE;
private Boolean closed = Boolean.FALSE;
private Boolean firing = Boolean.FALSE;
private Boolean semaphore = Boolean.FALSE;
/**
* Constructor. The listener is disabled by default.
*
* @param listener the buffer listener
* @param buffer the SynchroBuffer instance
*/
public SynchroBufferAdapter(SynchroBufferListener listener, SynchroBuffer buffer) {
this.listener = listener;
adaptee = buffer;
adaptee.setSynchroBufferListener(createSynchroBufferListener());
queue = Collections.synchronizedList(new ArrayList());
pullingThread = createPullingThread();
pullingThread.start();
}
/**
* Push an object into the buffer.
*
* @param object the object to push
*/
public void push(Object object) {
adaptee.push(object);
}
/**
* Push a collection of objects into the buffer.
*
* @param collection the collection of objects to push
*/
public void push(Collection collection) {
adaptee.push(collection);
}
/**
* Enable the listener. The listener is disabled by default.
*/
public void enable() {
adaptee.enable();
setEnabled(true);
LOGGER.debug("SynchroBufferAdapter listener enabled");
}
/**
* Disable the listener. Pushed object are kept in the buffer and delivered when the listener is enabled.
*/
public void disable() {
adaptee.disable();
setEnabled(false);
LOGGER.debug("SynchroBufferAdapter listener disabled");
}
/**
* SynchroBufferListener method.
*/
private SynchroBufferListener createSynchroBufferListener() {
return new SynchroBufferListener() {
public void pull(PullEvent event) throws PullException {
synchronized (queue) {
queue.add(event);
semNotify();
}
}
};
}
private void fire() {
if (isEnabled()) {
setFiring(true);
//System.out.println("firing...");
while ((!isEmpty()) && isEnabled()) {
List queue_copy = new ArrayList();
synchronized (queue) {
for (int i = 0; i < queue.size(); i++) {
queue_copy.add(queue.get(i));
}
queue.clear();
}
Iterator iterator = queue_copy.iterator();
while (iterator.hasNext()) {
PullEvent event = (PullEvent) iterator.next();
try {
listener.pull(event);
} catch (PullException e) {
e.printStackTrace();
}
}
}
//System.out.println("fired");
setFiring(false);
}
}
/**
* Thread method.
*/
private Thread createPullingThread() {
return new Thread() {
public void run() {
while ((!isClosed()) || ((!isEmpty()) && isEnabled())) {
semWait();
fire();
}
System.out.println("SynchroBufferAdapter pulling thread exited");
}
};
}
private void semNotify() {
//System.out.println("notifying...");
synchronized (semaphore) {
semaphore.notify();
}
}
private void semWait() {
//System.out.println("waiting...");
synchronized (semaphore) {
try {
semaphore.wait();
} catch (InterruptedException e) {
}
}
}
private boolean isEmpty() {
synchronized (queue) {
return queue.isEmpty();
}
}
private boolean isEnabled() {
synchronized (enabled) {
return enabled.booleanValue();
}
}
private void setEnabled(boolean value) {
synchronized (enabled) {
if (value == true) {
enabled = Boolean.TRUE;
semNotify();
} else {
enabled = Boolean.FALSE;
}
}
}
private boolean isClosed() {
synchronized (closed) {
return closed.booleanValue();
}
}
private void setClosed(boolean value) {
synchronized (closed) {
closed = (value ? Boolean.TRUE : Boolean.FALSE);
}
}
private void setFiring(boolean value) {
synchronized (firing) {
firing = (value ? Boolean.TRUE : Boolean.FALSE);
}
}
private boolean isFiring() {
synchronized (firing) {
return firing.booleanValue();
}
}
/**
* Close the buffer and deallocate resources.
*/
public void close() {
adaptee.close();
setClosed(true);
semNotify();
while (((!isEmpty()) && isEnabled()) || isFiring()) {
try {
Thread.sleep(200);
} catch (Exception e) {
}
}
LOGGER.debug("SynchroBufferAdapter closed");
}
}