/*
* $RCSfile: LinkedQueueSynchroBuffer.java,v $
*
* Copyright (C) 2004 European Organization for Nuclear Research.
*
*/
package cern.laser.util.buffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.log4j.Logger;
/**
* A buffer class which uses an Unbounded linked list implementation with the
* similar function signatures to SynchroBuffer.
*
* @author Niall Stapley
* @version $Revision: 1.2 $ $Date: 2006/09/25 08:52:37 $
*/
public class LinkedQueueSynchroBuffer {
/** For logging. */
private static final Logger LOGGER = Logger.getLogger(LinkedQueueSynchroBuffer.class);
/** The single listener to which elements must be delivered. */
private SynchroBufferListener listener = null;
// /** Starts the processing when enabled. */
// private final Latch enabled = new Latch();
/** The buffer. */
private LinkedBlockingQueue buffer = new LinkedBlockingQueue();
/** The thread to run to delivery to the listener. */
private Thread postman = new Thread(new Postman());
/**
* The constructor.
*
*/
public LinkedQueueSynchroBuffer() {
super();
}
/**
* Starts a new thread to take from the tail of the list and deliver the
* element to the listener.
*/
private class Postman implements Runnable {
public void run() {
/*
* If we really need to check that delivery is enabled each time,
* then we could use a lock. But we would have to check on _each_
* delivery that the lock was available. We should only do this if
* necessary.
*/
PullEvent p;
Collection c;
while (true) {
c = new ArrayList(1);
/* If interrupted then null is returned, so just try again. */
try {
c.add(buffer.take());
} catch (InterruptedException e) {
continue;
}
LOGGER.debug("take() returned an element.");
/* This is thrown by consumer for circumstances not
specified, but what are we supposed to do about it? */
try {
listener.pull(new PullEvent(this, c));
LOGGER.debug("Delivered element to listener.");
} catch (PullException pe) {
LOGGER.error("Error while delivering element.", pe);
}
}
}
} // class
/**
* Push an object into the buffer.
*
* @param o the object to push
*/
public void push(Object object) {
// keep trying if thread is interrupted
while (true) {
try {
buffer.put(object);
break;
} catch (InterruptedException e) {
continue;
}
}
}
/**
* Atempt to take an object from the end buffer. There is a chance this was
* interrupted and null is returned.
*
* @return o the object
*
*/
public Object take() {
Object o = null;
while (true) {
try {
o = buffer.take();
break;
} catch (InterruptedException e) {
continue;
}
}
return o;
}
/**
* Push a collection of objects into the buffer.
*
* @param collection the collection of objects to push
*/
public void push(Collection collection) {
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
push(iterator.next());
}
}
/**
* Set the buffer consumer listener.
*
* @param listener the listener
*/
public void setSynchroBufferListener(SynchroBufferListener listener) {
this.listener = listener;
}
/**
* Enable the listener. The listener is disabled by default. In this class, it
* should only be called once after the listener has been set to start
* receiving elements.
*/
public void enable() {
postman.start();
}
/**
* Disable the listener. Pushed object are kept in the buffer and delivered
* when the listener is enabled. In this class, this is not implemented, if
* starting and stopping the listener input is required, use take() instead,
* as this gives full control to the consumer as to when it takes an element.
*/
public void disable() {
// not implemented but could do it with lock or postname.stop() or
// postman.interrupt();
LOGGER.error("disable() called, but not implemented");
}
/**
* Close the input (head) end of the queue. It cannot be opened again. In this
* class, this is not implemented currently.
*/
public void close() {
LOGGER.error("close() called, but it is not implemented.");
}
}