DoubleAsynchronousSource.java
/*
* Created on 2010/01/04
* Copyright (C) 2010 Koga Laboratory. All rights reserved.
*
*/
package org.mklab.tool.control.system.source;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.ode.SolverStopException;
/**
* 非同期のソースを同期するソースです。 <p> このソースの {@link #outputEquation(double)}では、入力が発生するまでブロックすることにより、全体の同期を行っています。
*
* @author Yuhi Ishikura
* @version $Revision$, 2010/01/04
*/
public abstract class DoubleAsynchronousSource extends DoubleContinuousSource implements Importer {
// /** 時間から値へのマップです。 */
// private BlockingSortedMap<Double, double[]> map = new BlockingSortedMap<Double, double[]>();
/** 入力中に例外が発生した場合の例外保存変数です。 */
Throwable thrown;
/** 入力処理が終了したことを示します。 */
private boolean done;
/** 入力ソースの待機のロックに使用します。 */
private final Object inputSourceLock = new Object();
/** {@link #open()}が実行されたかどうかを示します。 */
private boolean opened;
/**
* {@link DoubleAsynchronousSource}オブジェクトを構築します。
*/
protected DoubleAsynchronousSource() {
super();
}
/**
* {@link DoubleAsynchronousSource}オブジェクトを構築します。
*
* @param outputSize 出力数
*/
protected DoubleAsynchronousSource(int outputSize) {
super(outputSize);
}
/**
* {@inheritDoc}
*/
@Override
public final DoubleMatrix outputEquation(double t) throws SolverStopException {
// バッファが空の間待ち続ける
synchronized (this.inputSourceLock) {
while (isReadyFor(t) == false) {
// これ以上データの入力がない場合
if (isDone()) {
break;
}
try {
this.inputSourceLock.wait();
} catch (InterruptedException e) {
throw new SolverStopException(Messages.getString("AsynchronousSource.0"), e); //$NON-NLS-1$
}
}
}
checkSourceError();
try {
return getOutput(t);
} catch (Exception ex) {
// TODO ここでキャッチしなくてもいいようにする。
// FixedRateAsynchronousSourceで、値取得の際に、範囲外参照、未来の参照が起こり得る
// どう防ぐか。
throw new SolverStopException(Messages.getString("AsynchronousSource.2"), ex); //$NON-NLS-1$
}
}
/**
* 入力処理中に発生した例外のチェックを行います。
*
* @throws SolverStopException 入力処理中に例外が発生していた場合
*/
private void checkSourceError() throws SolverStopException {
final Throwable thrownInSource = getThrown();
if (thrownInSource != null) {
throw new SolverStopException(Messages.getString("AsynchronousSource.1"), thrownInSource); //$NON-NLS-1$
}
}
/**
* バッファの変更を通知します。
*/
protected void bufferChanged() {
synchronized (this.inputSourceLock) {
this.inputSourceLock.notifyAll();
}
}
/**
* doneを取得します。
*
* @return done
*/
protected final boolean isDone() {
return this.done;
}
/**
* 入力の終了を通知します。 <p> このメソッドは、読み込み処理終了時にこのクラスで呼び出されるため、このクラスのサブクラスで呼び出す必要はありません。
*/
final void done() {
this.done = true;
bufferChanged();
}
/**
* 与えられた時間の入力が準備できているか調べます。
*
* @param t 調べる時間
* @return 準備ができていればtrue,できていなければfalse
*/
protected abstract boolean isReadyFor(double t);
/**
* 与えられた時間の入力を取得します。
*
* @param t 取得する時間
* @return 出力
*/
protected abstract DoubleMatrix getOutput(double t);
/**
* 別スレッドを開始し、入力処理を行います。
*
* @see org.mklab.tool.control.system.source.Importer#open()
*/
@Override
public final void open() {
if (this.opened) {
throw new IllegalStateException();
}
final Thread importerThread = new ImporterThread();
importerThread.start();
this.opened = true;
}
/**
* @see org.mklab.tool.control.system.source.Importer#importData()
*/
@Override
public final void importData() {
// do nothing
}
/**
* thrownを設定します。
*
* @param thrown thrown
*/
protected final void setThrown(Throwable thrown) {
this.thrown = thrown;
}
/**
* 入力処理中の例外を取得します。
*
* @return thrown 入力処理中の例外。例外が発生しなかった場合はnull
*/
protected final Throwable getThrown() {
return this.thrown;
}
/**
* @see org.mklab.tool.control.system.source.Importer#isActive()
*/
@Override
public final boolean isActive() {
return this.opened && isDone() == false;
}
/**
* ソースの記録を開始します。 <p> このメソッドは別スレッドにて呼び出されるため、ブロックしてかまいません。
*
* @throws Throwable 入力処理中に例外が発生した場合
*/
protected abstract void processImport() throws Throwable;
/**
* 入力処理を行うスレッドです。
*
* @author Yuhi Ishikura
* @version $Revision$, 2010/01/04
*/
class ImporterThread extends Thread {
/**
* @see java.lang.Thread#run()
*/
@Override
public void run() {
try {
processImport();
} catch (Throwable e) {
setThrown(e);
}
done();
}
}
}