package org.argeo.slc.core.test.tree; import java.util.Vector; import org.argeo.slc.core.structure.tree.TreeSPath; import org.argeo.slc.core.test.NumericTRId; import org.argeo.slc.core.test.TestResult; import org.argeo.slc.core.test.TestResultListener; import org.argeo.slc.core.test.TestResultPart; /** * Abstract asynchronous implementation of a listener listening to a * TreeTestResult. * * @see TreeTestResult */ public abstract class AsynchronousTreeTestResultListener implements TestResultListener, Runnable { private Vector partStructs = new Vector(); private Thread thread; private Boolean synchronous = false; protected AsynchronousTreeTestResultListener(){ this(false); } protected AsynchronousTreeTestResultListener(Boolean synchronousByDefault){ synchronous = synchronousByDefault; } /** Starts the underlying thread. */ public void init() { if (!synchronous) { thread = new Thread(this); thread.start(); } } /** Finish the remaining and destroy */ public void close(TestResult testResult) { // FIXME: make behavior more robust when multiple results are // registering this listener. synchronized (partStructs) { // TODO: put a timeout while (partStructs.size() != 0) { try { partStructs.wait(500); } catch (InterruptedException e) { // silent } } thread = null; partStructs.notifyAll(); } postClose((TreeTestResult) testResult); } public final void resultPartAdded(TestResult testResult, TestResultPart testResultPart) { TreeTestResult result = (TreeTestResult) testResult; PartStruct partStruct = new PartStruct(result.getCurrentPath(), (NumericTRId) result.getTestResultId(), testResultPart, result); if (!synchronous) { synchronized (partStructs) { partStructs.add(partStruct); partStructs.notifyAll(); } } else { resultPartAdded(partStruct); } } /** Called when a result part has been added. */ protected abstract void resultPartAdded(PartStruct partStruct); /** * Called at the end of close. Default implementation is empty. To be * overridden. */ protected void postClose(TreeTestResult testResult) { } public void run() { while (thread != null) { synchronized (partStructs) { for (PartStruct partStruct : partStructs) { resultPartAdded(partStruct); } partStructs.clear(); partStructs.notifyAll(); while (partStructs.size() == 0) { try { partStructs.wait(); } catch (InterruptedException e) { // silent } } } } } /** Structure used to pass tree specific information to subclasses. */ protected static class PartStruct { /** The tree path of this part. */ public final TreeSPath path; /** The test result id of the related test result */ public final NumericTRId resultId; /** The part itself */ public final TestResultPart part; /** The tree test result itself. */ public final TreeTestResult result; /** Constructor */ public PartStruct(TreeSPath path, NumericTRId resultId, TestResultPart part, TreeTestResult result) { super(); this.path = path; this.resultId = resultId; this.part = part; this.result = result; } } public Boolean getSynchronous() { return synchronous; } public void setSynchronous(Boolean synchronous) { this.synchronous = synchronous; } }