Added threaded loader to ComponentPresetDatabase following the pattern in ThrustCurve...
authorkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 27 Jun 2012 02:58:53 +0000 (02:58 +0000)
committerkruland2607 <kruland2607@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 27 Jun 2012 02:58:53 +0000 (02:58 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@813 180e2498-e6e9-4542-8430-84ac67f01cd8

android/src/net/sf/openrocket/android/Application.java
core/src/net/sf/openrocket/database/ComponentPresetDatabase.java
core/src/net/sf/openrocket/gui/figure3d/Quick3dMain.java
core/src/net/sf/openrocket/startup/ConcurrentLoadingThrustCurveMotorSetDatabase.java
core/src/net/sf/openrocket/startup/Startup2.java

index 624df23bec72f09727bb342efae37d89c07abec0..9661f400dd3e84f0b534f5d608397d48252fd4ad 100644 (file)
@@ -28,7 +28,12 @@ public class Application extends android.app.Application {
 \r
                        net.sf.openrocket.startup.Application.setPreferences( new PreferencesAdapter() );\r
 \r
-                       net.sf.openrocket.startup.Application.setComponentPresetDao( new ComponentPresetDatabase() );\r
+                       net.sf.openrocket.startup.Application.setComponentPresetDao( new ComponentPresetDatabase(){\r
+                               @Override\r
+                               protected void load() {\r
+                                       // We don't need components\r
+                               } \r
+                       } );\r
 \r
                        MotorDatabaseAdapter db = new MotorDatabaseAdapter(this);\r
 \r
index 8acafcff57c1fa13362a8a16132ac1518036337b..91cfe609f93e1e3246452fd6184797f7b3fd0e91 100644 (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);
+                                       }
+                               }
+                       }
+               }
+       }
+
 }
index 49dbbc9fde19c3f4f67b86902f6d0a71d41e3acd..d7c2e842ce5858e197c4ecdc189ff758c66f2ef6 100644 (file)
@@ -41,8 +41,14 @@ public class Quick3dMain {
                Application.setPreferences(new SwingPreferences());\r
                \r
                // Must be done after localization is initialized\r
-               ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();\r
-               componentPresetDao.load("datafiles", ".*csv");\r
+               ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase() {\r
+\r
+                       @Override\r
+                       protected void load() {\r
+                               // This test app doesn't need any presets loaded - just an empty database.\r
+                       }\r
+                       \r
+               };\r
                Application.setComponentPresetDao( componentPresetDao );\r
 \r
                OpenRocketDocument doc = new OpenRocketLoader().loadFromStream(\r
index a546f739e55ff2c5ccec5b636676c4cabdc27635..c52d72e19e09255e206ed7648f854f2c2ae3248e 100644 (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();
index 85500a361299d3f49668afd4c9c983791406d9a5..6b7b49cdfc962aa351b6321b77f44831a8006788 100644 (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");