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;
}
@Override
public List<ComponentPreset> listForType( ComponentPreset.Type type ) {
+ blockUntilLoaded();
if ( type == null ) {
return Collections.<ComponentPreset>emptyList();
}
*/
@Override
public List<ComponentPreset> listForType( ComponentPreset.Type type, boolean favorite ) {
+ blockUntilLoaded();
if ( !favorite ) {
return listForType(type);
@Override
public List<ComponentPreset> listForTypes( ComponentPreset.Type ... type ) {
+ blockUntilLoaded();
if( type == null || type.length == 0 ) {
return Collections.<ComponentPreset>emptyList();
@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) ) {
@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);
+ }
+ }
+ }
+ }
+ }
+
}
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;
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
@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();
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();
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");
Databases.fakeMethod();
- try {
- presetLoader.await();
- } catch ( InterruptedException iex) {
-
- }
// Starting action (load files or open new document)
log.info("Opening main application window");