package org.rubypeople.rdt.internal.debug.core.parsing;
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.rubypeople.rdt.debug.core.RdtDebugCorePlugin;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class MultiReaderStrategy extends AbstractReadStrategy {
private Map<XmlStreamReader, Thread> threads;
private XmlStreamReader currentReader;
private boolean isConnected ;
public MultiReaderStrategy(XmlPullParser xpp) {
super(xpp);
isConnected = true ;
threads = new HashMap<XmlStreamReader, Thread>();
new Thread("xml reader") {
public void run() {
try {
readLoop();
} catch (SocketException e) {
RdtDebugCorePlugin.debug("read loop stopped because socket has been closed.") ;
} catch (Exception e) {
RdtDebugCorePlugin.debug("read loop stopped due to error : ", e);
// needs PDE Junit otherwise
// RdtDebugCorePlugin.log(e);
e.printStackTrace();
} finally {
isConnected = false;
try {
Thread.sleep(1000) ; // Avoid Commodfication Exceptions
} catch (InterruptedException e) {
}
releaseAllReaders();
}
}
}
.start();
}
protected void readLoop() throws XmlPullParserException, IOException, XmlStreamReaderException {
RdtDebugCorePlugin.debug("Starting xml read loop.");
int eventType = xpp.getEventType();
do {
if (eventType == XmlPullParser.START_TAG) {
this.dispatchStartTag();
} else if (eventType == XmlPullParser.END_TAG && currentReader != null) {
if (currentReader.processEndElement(xpp)) {
this.removeReader(currentReader);
currentReader = null;
}
} else if (eventType == XmlPullParser.TEXT) {
if (currentReader != null) {
currentReader.processContent(xpp.getText()) ;
}
}
eventType = xpp.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
RdtDebugCorePlugin.debug("Read loop stopped because end of stream was reached.");
}
protected void dispatchStartTag() throws XmlPullParserException, IOException, XmlStreamReaderException {
RdtDebugCorePlugin.debug("Dispatching start tag " + xpp.getName());
if (currentReader != null) {
// processing sub-elements, eg. <variable> from <variables>
if (currentReader.processStartElement(xpp)) {
return ;
}
else {
// this is an error, the currentReader must be able to process sub-elements
RdtDebugCorePlugin.debug("Current Reader can not process tag " + xpp.getName());
currentReader = null ;
}
}
int missed = 0 ;
RdtDebugCorePlugin.debug("Searching reader for start tag " + xpp.getName());
do {
findReaderForTag();
if (currentReader == null) {
missed += 1 ;
RdtDebugCorePlugin.debug("Missed Start Tag : " + xpp.getName());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
} while (currentReader == null && missed < 10);
}
private synchronized void findReaderForTag() throws XmlStreamReaderException {
// System.out.println("There are no threads:" + threads.size()) ;
for (XmlStreamReader streamReader : threads.keySet()) {
if (streamReader.processStartElement(xpp)) {
currentReader = streamReader;
break;
}
}
}
protected synchronized void releaseAllReaders() {
for (Iterator<Map.Entry<XmlStreamReader, Thread>> iter = threads.entrySet().iterator(); iter.hasNext();) {
Thread thread = iter.next().getValue();
thread.interrupt();
iter.remove();
}
}
protected synchronized void removeReader(XmlStreamReader streamReader) {
threads.get(streamReader).interrupt();
threads.remove(streamReader);
}
protected synchronized void addReader(XmlStreamReader streamReader) {
threads.put(streamReader, Thread.currentThread());
}
public void readElement(XmlStreamReader streamReader) throws IOException {
readElement(streamReader, Long.MAX_VALUE) ;
}
public void readElement(XmlStreamReader streamReader, long maxWaitTime) throws IOException {
if (!isConnected) {
throw new IOException("Read loop has finished") ;
}
this.addReader(streamReader);
try {
RdtDebugCorePlugin.debug("Thread is waiting for input: " + Thread.currentThread());
Thread.sleep(maxWaitTime);
streamReader.setWaitTimeExpired(true) ;
} catch (InterruptedException e) {
RdtDebugCorePlugin.debug("Thread has finished processing : " + Thread.currentThread());
}
}
public boolean isConnected() {
return isConnected;
}
}