package net.java.xpath.ui;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPathExpressionException;
import org.openide.util.Exceptions;
import org.xml.sax.SAXException;
final class XPathEvaluatorThread extends Thread {
private volatile boolean updated = false;
private final JTextComponent component;
private final Runnable edtRunner;
private final XPathEvaluator eval;
private String xpath;
private String xml;
private String result;
XPathEvaluatorThread(JTextComponent component) {
super("XPath-evaluator");
this.component = component;
this.setDaemon(true);
this.eval = new XPathEvaluator();
this.edtRunner = new Runnable() {
@Override
public void run() {
XPathEvaluatorThread.this.component.setText(result);
}
};
}
@Override
public void run() {
while (!Thread.interrupted()) {
// don't sleep if values have changed
if (!updated) {
try {
synchronized (this) {
wait();
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return;
}
}
try {
updated = false;
result = eval.evalXPathToString(xpath, xml);
} catch (SAXException ex) {
result = "unable to parse document";
ex.printStackTrace();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
} catch (TransformerException ex) {
Exceptions.printStackTrace(ex);
} catch (XPathExpressionException ex) {
// return localized exception message on illegal xpath expr.
result = ex.getCause().getLocalizedMessage();
}
/*
* don't update if dirty (racecondition possible but doeasn't matter)
*/
if (updated && (result == null || result.isEmpty())) {
continue;
}
try {
SwingUtilities.invokeAndWait(edtRunner);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return;
} catch (InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
}
}
/**
* Starts asynchronous evaluation of the xpath expression. This method
* can be called concurrently even if a evaluation is in progress.
*/
synchronized void asyncEval(String xpath, String xml) {
this.updated = true;
this.xml = xml;
this.xpath = xpath;
if (isAlive()) {
notify();
} else {
start();
}
}
}