JSAMP HUB waits for callee before returning to caller

Laurent Bourgès bourges.laurent at gmail.com
Wed Jul 2 09:30:51 PDT 2014


Mark,

I tested today the JSAMP async variant concerning shutdown issues I spotted
two years ago.


1/ It takes me some time to update my test classes (+ shells) related to
both client & hub shutdown.

For me, everything is fine: no ghost or leaking client / hub encountered.

Just surprised by the connection listener that is not called during
shutdown, but it seems normal:
- HubConnection.unregister() called => hub
- GuiConnector (GUI wrapper on low-level hub connection) not notified => no
listener called


2/ I also updated my favorite application Aspro2 to use JSAMP async in the
JavaWebStart (JNLP) environment.

As we had problems previously, we explicitly perform SAMP clean-up
(SampManager class) before shutdown: connector.setActive(false) and
Hub.getRunningHubs() => shutdown().

As you improved the shutdown code in JSAMP, I disabled our explicit
shutdown code to test JSAMP as provided and it works well.


I enabled the java console tracing to get javaws exceptions and there is
still one related to WebHubProfile.stop():

14:26:21.650 INFO  [AWT-EventQueue-2] fr.jmmc - Exiting with status code
'0'.
WARNING: Shutdown hook failure: java.lang.IllegalStateException: zip file
closed
java.lang.IllegalStateException: zip file closed
    at java.util.zip.ZipFile.ensureOpen(ZipFile.java:634)
    at java.util.zip.ZipFile.getEntry(ZipFile.java:305)
    at java.util.jar.JarFile.getEntry(JarFile.java:227)
    at com.sun.deploy.cache.CachedJarFile.getEntry(Unknown Source)
    at java.util.jar.JarFile.getJarEntry(JarFile.java:210)
    at
com.sun.deploy.security.DeployURLClassPath$JarLoader.getResource(Unknown
Source)
    at com.sun.deploy.security.DeployURLClassPath.getResource(Unknown
Source)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:358)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at com.sun.jnlp.JNLPClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)

*    at org.astrogrid.samp.web.WebHubProfile.stop(WebHubProfile.java:117)*
at org.astrogrid.samp.hub.Hub.shutdown(Hub.java:116)
    at org.astrogrid.samp.hub.Hub$4.run(Hub.java:526)
    at org.astrogrid.samp.ShutdownManager.doCleanup(ShutdownManager.java:92)

To fix it, I modified this class to preload the Runnable class invoked in
the stop() method.

Here is the patch (coming soon in my JSAMP fork on github):
# This patch file was generated by NetBeans IDE
# It uses platform neutral UTF-8 encoding and \n newlines.
--- HEAD
+++ Modified In Working Tree
@@ -7,7 +7,6 @@
 import java.util.logging.Logger;
 import javax.swing.JToggleButton;
 import javax.swing.SwingUtilities;
-import org.astrogrid.samp.Message;
 import org.astrogrid.samp.client.ClientProfile;
 import org.astrogrid.samp.httpd.HttpServer;
 import org.astrogrid.samp.hub.ConfigHubProfile;
@@ -32,8 +31,10 @@
     private MessageRestriction mrestrict_;
     private boolean controlUrls_;
     private InternalServer xServer_;
-    private WebHubXmlRpcHandler wxHandler_;
     private JToggleButton.ToggleButtonModel[] configModels_;
+    /* LBO: preload runnable classes to enable/disable toggle buttons used
by EDT during start/stop and shutdown (JNLP issue) */
+    private final ConfigModelsStateManager configModels_disabler = new
ConfigModelsStateManager(false);
+    private final ConfigModelsStateManager configModels_enabler  = new
ConfigModelsStateManager(true);
     private static final Logger logger_ =
         Logger.getLogger( WebHubProfile.class.getName() );

@@ -91,16 +92,11 @@
         xServer_.addHandler( wxHandler );
         hServer.addHandler( wxHandler.getUrlTranslationHandler() );
         hServer.start();
+
         if ( configModels_ != null ) {
-            SwingUtilities.invokeLater( new Runnable() {
-                public void run() {
-                    for ( int i = 0; i < configModels_.length; i++ ) {
-                        configModels_[ i ].setEnabled( false );
+            SwingUtilities.invokeLater(configModels_disabler);
                     }
                 }
-            } );
-        }
-    }

     public synchronized boolean isRunning() {
         return xServer_ != null;
@@ -114,15 +110,24 @@
         xServer_.getHttpServer().stop();
         xServer_ = null;
         if ( configModels_ != null ) {
-            SwingUtilities.invokeLater( new Runnable() {
-                public void run() {
-                    for ( int i = 0; i < configModels_.length; i++ ) {
-                        configModels_[ i ].setEnabled( true );
+            SwingUtilities.invokeLater(configModels_enabler);
                     }
                 }
-            } );
+
+    private final class ConfigModelsStateManager implements Runnable {
+        private final boolean state_;
+
+        ConfigModelsStateManager(final boolean state) {
+            this.state_ = state;
         }
+
+        public void run() {
+            final JToggleButton.ToggleButtonModel[] models =
getConfigModels();
+            for ( int i = 0; i < models.length; i++ ) {
+                models[ i ].setEnabled( this.state_ );
     }
+        }
+    }

     public synchronized JToggleButton.ToggleButtonModel[]
getConfigModels() {
         if ( configModels_ == null ) {


Finally all my tests are OK and I provide a minor patch to avoid any
exception thrown in JNLP environment:
Good job, mark !


PS: I think the documentation related to multi-threading in the SAMP
protocol & implementations could be improved as there is two API levels:
- low-level: creates one SAMP threads per message and can lead to
concurrency issues (take care)
- GUI level (Java): using the Event Dispatcher Thread (single thread)
ensures Swing components are consistent and thread-safe

But in JSamp, there is so many features (hub, profiles, connections) that
it is not always obvious which threading model is in use (low-level or GUI)
ie single (thread-safe) / multiple threads and if it is a blocking / non
blocking behaviour.


Cheers,
Laurent
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.ivoa.net/pipermail/apps-samp/attachments/20140702/4861724f/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SampClientTest.java
Type: text/x-java
Size: 8117 bytes
Desc: not available
URL: <http://www.ivoa.net/pipermail/apps-samp/attachments/20140702/4861724f/attachment-0003.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SampShutdownTest.java
Type: text/x-java
Size: 6789 bytes
Desc: not available
URL: <http://www.ivoa.net/pipermail/apps-samp/attachments/20140702/4861724f/attachment-0004.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test-sampClient.sh
Type: application/x-sh
Size: 129 bytes
Desc: not available
URL: <http://www.ivoa.net/pipermail/apps-samp/attachments/20140702/4861724f/attachment-0002.sh>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test-sampHub.sh
Type: application/x-sh
Size: 618 bytes
Desc: not available
URL: <http://www.ivoa.net/pipermail/apps-samp/attachments/20140702/4861724f/attachment-0003.sh>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: WebHubProfile.java
Type: text/x-java
Size: 15755 bytes
Desc: not available
URL: <http://www.ivoa.net/pipermail/apps-samp/attachments/20140702/4861724f/attachment-0005.bin>


More information about the apps-samp mailing list