package net.sf.openrocket.database;
/**
* A class that manages calling a DatabaseLoader in the background.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public abstract class AsynchronousDatabaseLoader {
private final long startupDelay;
private volatile boolean startedLoading = false;
private volatile boolean endedLoading = false;
private volatile boolean inUse = false;
/**
* Sole constructor.
* <p>
* The startupDelay parameter defines a time to delay after calling startLoading before
* actually starting the loading. This allows other actions such as GUI opening
* to proceed faster. The delay can be cancelled by calling setInUse().
*
* @param startupDelay number of milliseconds to delay before starting actual loading.
*/
public AsynchronousDatabaseLoader(long startupDelay) {
this.startupDelay = startupDelay;
}
/**
* Start loading the database. Creates a new thread for the loading and returns immediately.
*
* @throws IllegalStateException if this method has already been called.
*/
public void startLoading() {
if (startedLoading) {
throw new IllegalStateException("Already called startLoading");
}
startedLoading = true;
new LoadingThread().start();
}
/**
* Return whether loading the database has ended.
*/
public boolean isLoaded() {
return endedLoading;
}
/**
* Cancel the startup delay (if still ongoing), and start loading the database immediately.
*/
public void cancelStartupDelay() {
if (!inUse) {
synchronized (this) {
inUse = true;
this.notifyAll();
}
}
}
/**
* Block the current thread until loading of the motors has been completed.
* This also cancels any ongoing startup delay.
*
* @throws IllegalStateException if startLoading() has not been called.
*/
public void blockUntilLoaded() {
if (!startedLoading) {
throw new IllegalStateException("startLoading() has not been called");
}
if (!endedLoading) {
cancelStartupDelay();
synchronized (this) {
while (!endedLoading) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
}
}
}
private void doLoad() {
// Pause for indicated startup time
long startLoading = System.currentTimeMillis() + startupDelay;
while (!inUse && System.currentTimeMillis() < startLoading) {
synchronized (this) {
try {
this.wait(startLoading - System.currentTimeMillis());
} catch (InterruptedException e) {
}
}
}
loadDatabase();
synchronized (this) {
endedLoading = true;
this.notifyAll();
}
}
protected abstract void loadDatabase();
/**
* Background thread for loading the database.
*/
private class LoadingThread extends Thread {
private LoadingThread() {
this.setName("DatabaseLoadingThread");
this.setPriority(MIN_PRIORITY);
}
@Override
public void run() {
doLoad();
}
}
}