/*******************************************************************************
* Copyright (c) 2008 Scott Stanchfield.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Based on the ANTLR parser generator by Terence Parr, http://antlr.org
* Ric Klaren <klaren@cs.utwente.nl>
* Scott Stanchfield - Modifications for XML Parsing
*******************************************************************************/
package com.javadude.antxr.scanner;
import java.util.LinkedList;
import java.util.List;
/**
* A blocking queue, used as a transport access point between the SAX parser
* and the XML parser. The SAX parser will place tokens into this queue; the
* XML token stream will pull tokens out. The queue will force the token stream
* to wait if there are no tokens ready, and the SAX parser to wait if it's
* loading up too many tokens.
*
*/
public class BlockingQueue <Type> {
private List<Type> data = new LinkedList<Type>();
private int maxQueuedElements;
private int resumeQueuedElements;
private Throwable enqueueException;
private boolean useMaxMin;
private boolean writerWaiting;
private boolean readerWaiting;
/**
* Create an instance of BlockingQueue
*/
public BlockingQueue() {
this(-1,-1);
}
/**
* Create an instance of BlockingQueue
* @param maxQueuedElements
* @param resumeQueuedElements
*/
public BlockingQueue(int maxQueuedElements, int resumeQueuedElements) {
super();
this.maxQueuedElements = maxQueuedElements;
this.resumeQueuedElements = resumeQueuedElements;
if (maxQueuedElements != -1) {
useMaxMin = true;
if (maxQueuedElements <= resumeQueuedElements) {
throw new IllegalArgumentException("maxQueuedElements must be > resumeQueuedElements");
}
}
}
/**
* Enqueue an element
* @param o the element to enqueue
*/
public synchronized void enqueue(Type o) {
// if we've reached the max queued elements, wait to queue it
if (useMaxMin && data.size() >= maxQueuedElements) {
try {
writerWaiting = true;
if (readerWaiting) {
notifyAll(); // notify readers
}
wait(); // wait until enough objects have been read
}
catch (Throwable e) {
enqueueException = e;
}
finally {
writerWaiting = false;
}
}
data.add(o);
if (readerWaiting) {
notifyAll();
}
}
/**
* Dequeue an element
* @return The next object in the queue
* @throws InterruptedException If we were interrupted
*/
public synchronized Type dequeue() throws InterruptedException {
if (enqueueException != null) {
Throwable toReport = enqueueException;
enqueueException = null;
throw new RuntimeException("Exception while enqueueing", toReport);
}
while(data.isEmpty()) {
try {
readerWaiting = true;
wait();
}
finally {
readerWaiting = false;
}
}
Type o = data.remove(0);
// if any sources are waiting and we've reached the "low water mark"
// that makes us resume, wake them
if (writerWaiting && data.size() <= resumeQueuedElements) {
notifyAll();
}
return o;
}
}