Added threaded loader to ComponentPresetDatabase following the pattern in ThrustCurveMotorDatabase. Moved the wait into the background thread so the UI starts much faster. Changed the ConcurrentLoadingThrustCurveMotorSetDataBase implementation to have longer timeouts and wait in the background thread.

This commit is contained in:
Kevin Ruland 2012-06-27 02:58:53 +00:00
parent 5aa691c2ab
commit 9eed1653fb
5 changed files with 133 additions and 15 deletions

View File

@ -28,7 +28,12 @@ public class Application extends android.app.Application {
net.sf.openrocket.startup.Application.setPreferences( new PreferencesAdapter() );
net.sf.openrocket.startup.Application.setComponentPresetDao( new ComponentPresetDatabase() );
net.sf.openrocket.startup.Application.setComponentPresetDao( new ComponentPresetDatabase(){
@Override
protected void load() {
// We don't need components
}
} );
MotorDatabaseAdapter db = new MotorDatabaseAdapter(this);

View File

@ -4,17 +4,34 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.startup.Application;
public class ComponentPresetDatabase extends Database<ComponentPreset> implements ComponentPresetDao {
public abstract class ComponentPresetDatabase extends Database<ComponentPreset> implements ComponentPresetDao {
private static final LogHelper logger = Application.getLogger();
private volatile boolean startedLoading = false;
private volatile boolean endedLoading = false;
private final boolean asynchronous;
/** Set to true the first time {@link #blockUntilLoaded()} is called. */
protected volatile boolean inUse = false;
public ComponentPresetDatabase() {
super();
this.asynchronous = false;
}
public ComponentPresetDatabase(boolean asynchronous ) {
super();
this.asynchronous = asynchronous;
}
@Override
public List<ComponentPreset> listAll() {
blockUntilLoaded();
return list;
}
@ -25,6 +42,7 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
@Override
public List<ComponentPreset> listForType( ComponentPreset.Type type ) {
blockUntilLoaded();
if ( type == null ) {
return Collections.<ComponentPreset>emptyList();
}
@ -50,6 +68,7 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
*/
@Override
public List<ComponentPreset> listForType( ComponentPreset.Type type, boolean favorite ) {
blockUntilLoaded();
if ( !favorite ) {
return listForType(type);
@ -67,6 +86,7 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
@Override
public List<ComponentPreset> listForTypes( ComponentPreset.Type ... type ) {
blockUntilLoaded();
if( type == null || type.length == 0 ) {
return Collections.<ComponentPreset>emptyList();
@ -93,11 +113,13 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
@Override
public List<ComponentPreset> listForTypes( List<ComponentPreset.Type> types ) {
blockUntilLoaded();
return listForTypes( (ComponentPreset.Type[]) types.toArray() );
}
@Override
public List<ComponentPreset> find(String manufacturer, String partNo) {
blockUntilLoaded();
List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
for( ComponentPreset preset : list ) {
if ( preset.getManufacturer().getSimpleName().equals(manufacturer) && preset.getPartNo().equals(partNo) ) {
@ -109,9 +131,71 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
@Override
public void setFavorite( ComponentPreset preset, boolean favorite ) {
blockUntilLoaded();
preset.setFavorite(favorite);
Application.getPreferences().setComponentFavorite( preset, favorite );
this.fireAddEvent(preset);
}
/**
* Used for loading the component preset database. This method will be called in a background
* thread to load the presets asynchronously.
*/
protected abstract void load();
/**
* Start loading the presets.
*
* @throws IllegalStateException if this method has already been called.
*/
public void startLoading() {
if (startedLoading) {
throw new IllegalStateException("Already called startLoading");
}
startedLoading = true;
if (asynchronous) {
new LoadingThread().start();
} else {
load();
}
synchronized (this) {
endedLoading = true;
this.notifyAll();
}
}
/**
* Background thread for loading the presets.
*/
private class LoadingThread extends Thread {
@Override
public void run() {
load();
}
}
/**
* Block the current thread until loading of the presets has been completed.
*
* @throws IllegalStateException if startLoading() has not been called.
*/
public void blockUntilLoaded() {
inUse = true;
if (!startedLoading) {
throw new IllegalStateException("startLoading() has not been called");
}
if (!endedLoading) {
synchronized (this) {
while (!endedLoading) {
try {
this.wait();
} catch (InterruptedException e) {
logger.warn("InterruptedException occurred, ignoring", e);
}
}
}
}
}
}

View File

@ -41,8 +41,14 @@ public class Quick3dMain {
Application.setPreferences(new SwingPreferences());
// Must be done after localization is initialized
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
componentPresetDao.load("datafiles", ".*csv");
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase() {
@Override
protected void load() {
// This test app doesn't need any presets loaded - just an empty database.
}
};
Application.setComponentPresetDao( componentPresetDao );
OpenRocketDocument doc = new OpenRocketLoader().loadFromStream(

View File

@ -9,6 +9,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import net.sf.openrocket.database.ThrustCurveMotorSet;
import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
@ -47,6 +48,9 @@ public class ConcurrentLoadingThrustCurveMotorSetDatabase extends ThrustCurveMot
private static final LogHelper log = Application.getLogger();
private final String thrustCurveDirectory;
/** Block motor loading for this many milliseconds */
// Block motor loading for 1.5 seconds to allow window painting to be faster
private static AtomicInteger blockLoading = new AtomicInteger(1500);
public ConcurrentLoadingThrustCurveMotorSetDatabase(String thrustCurveDirectory) {
// configure ThrustCurveMotorSetDatabase as true so we get our own thread in
@ -58,6 +62,18 @@ public class ConcurrentLoadingThrustCurveMotorSetDatabase extends ThrustCurveMot
@Override
protected void loadMotors() {
// Block loading until timeout occurs or database is taken into use
log.info("Blocking motor loading while starting up");
/*
while (!inUse && blockLoading.addAndGet(-100) > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
*/
log.info("Blocking ended, inUse=" + inUse + " blockLoading=" + blockLoading.get());
BookKeeping keeper = new BookKeeping();
keeper.start();
@ -162,9 +178,9 @@ public class ConcurrentLoadingThrustCurveMotorSetDatabase extends ThrustCurveMot
private void waitForFinish() throws InterruptedException {
try {
loaderPool.shutdown();
loaderPool.awaitTermination(10, TimeUnit.SECONDS);
loaderPool.awaitTermination(30, TimeUnit.SECONDS);
writerThread.shutdown();
writerThread.awaitTermination(10, TimeUnit.SECONDS);
writerThread.awaitTermination(30, TimeUnit.SECONDS);
}
finally {
iterator.close();

View File

@ -84,11 +84,23 @@ public class Startup2 {
Splash.init();
// Must be done after localization is initialized
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( componentPresetDao );
presetLoader.load();
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase(true) {
@Override
protected void load() {
ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( this );
presetLoader.load();
try {
presetLoader.await();
} catch ( InterruptedException iex) {
}
}
};
Application.setComponentPresetDao( componentPresetDao );
componentPresetDao.startLoading();
// Setup the uncaught exception handler
log.info("Registering exception handler");
@ -124,11 +136,6 @@ public class Startup2 {
Databases.fakeMethod();
try {
presetLoader.await();
} catch ( InterruptedException iex) {
}
// Starting action (load files or open new document)
log.info("Opening main application window");