changeset in /hg/icedtea6: 2009-06-24 Omair Majid <omajid at redh...

Omair Majid omajid at redhat.com
Wed Jun 24 12:03:45 PDT 2009


changeset ed75376cfe3a in /hg/icedtea6
details: http://icedtea.classpath.org/hg/icedtea6?cmd=changeset;node=ed75376cfe3a
description:
	2009-06-24  Omair Majid  <omajid at redhat.com>

	    * rt/net/sourceforge/jnlp/Launcher.java (launchApplication): Check for any
	    existing single instance.  Dont start a second instance.
	    * rt/net/sourceforge/jnlp/resources/Messages.properties: Add RNoLockDir.
	    * rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java:
	    Added USER, TMP_DIR, and changed LOCKS_DIR.
	    * rt/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java
	    New file.
	    * rt/net/sourceforge/jnlp/services/InstanceExistsException.java: New file.
	    * rt/net/sourceforge/jnlp/services/ServiceUtil.java
	    (getSingleInstanceService): New function.
	    (checkExistingSingleInstance): New function.
	    * rt/net/sourceforge/jnlp/services/SingleInstanceLock.java: New file.
	    * rt/net/sourceforge/jnlp/services/XServiceManagerStub.java: Add
	    SingleInstanceService to serviceNames. Create a new instance of
	    XSingleInstanceService as a privileged proxy.
	    * rt/net/sourceforge/jnlp/services/XSingleInstanceService.java: New file.

diffstat:

10 files changed, 602 insertions(+), 12 deletions(-)
ChangeLog                                                           |   19 
rt/net/sourceforge/jnlp/Launcher.java                               |    8 
rt/net/sourceforge/jnlp/resources/Messages.properties               |    1 
rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java                    |   16 
rt/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java |   49 ++
rt/net/sourceforge/jnlp/services/InstanceExistsException.java       |   35 +
rt/net/sourceforge/jnlp/services/ServiceUtil.java                   |   48 +-
rt/net/sourceforge/jnlp/services/SingleInstanceLock.java            |  203 ++++++++
rt/net/sourceforge/jnlp/services/XServiceManagerStub.java           |    6 
rt/net/sourceforge/jnlp/services/XSingleInstanceService.java        |  229 ++++++++++

diffs (truncated from 717 to 500 lines):

diff -r 1ba29bfca5a0 -r ed75376cfe3a ChangeLog
--- a/ChangeLog	Wed Jun 24 12:15:33 2009 -0400
+++ b/ChangeLog	Wed Jun 24 15:02:45 2009 -0400
@@ -1,3 +1,22 @@ 2009-06-24  Omair Majid  <omajid at redhat.
+2009-06-24  Omair Majid  <omajid at redhat.com>
+
+	* rt/net/sourceforge/jnlp/Launcher.java (launchApplication): Check for any 
+	existing single instance.  Dont start a second instance.
+	* rt/net/sourceforge/jnlp/resources/Messages.properties: Add RNoLockDir.
+	* rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java:
+	Added USER, TMP_DIR, and changed LOCKS_DIR.
+	* rt/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java
+	New file.
+	* rt/net/sourceforge/jnlp/services/InstanceExistsException.java: New file.
+	* rt/net/sourceforge/jnlp/services/ServiceUtil.java
+	(getSingleInstanceService): New function.
+	(checkExistingSingleInstance): New function.
+	* rt/net/sourceforge/jnlp/services/SingleInstanceLock.java: New file.
+	* rt/net/sourceforge/jnlp/services/XServiceManagerStub.java: Add
+	SingleInstanceService to serviceNames. Create a new instance of
+	XSingleInstanceService as a privileged proxy.
+	* rt/net/sourceforge/jnlp/services/XSingleInstanceService.java: New file. 
+
 2009-06-24  Omair Majid  <omajid at redhat.com>
 
 	* rt/net/sourceforge/jnlp/Parser.java: Add 1.5 and 6.0 to
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/Launcher.java
--- a/rt/net/sourceforge/jnlp/Launcher.java	Wed Jun 24 12:15:33 2009 -0400
+++ b/rt/net/sourceforge/jnlp/Launcher.java	Wed Jun 24 15:02:45 2009 -0400
@@ -37,6 +37,8 @@ import net.sourceforge.jnlp.runtime.Appl
 import net.sourceforge.jnlp.runtime.ApplicationInstance;
 import net.sourceforge.jnlp.runtime.JNLPClassLoader;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.services.InstanceExistsException;
+import net.sourceforge.jnlp.services.ServiceUtil;
 import net.sourceforge.jnlp.util.Reflect;
 
 /**
@@ -365,6 +367,12 @@ public class Launcher {
             throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplication"), R("LNotApplicationInfo")));
 
         try {
+            
+            try {
+                ServiceUtil.checkExistingSingleInstance(file);
+            } catch (InstanceExistsException e) {
+                return null;
+            }
             
             if (JNLPRuntime.getForksAllowed() && file.needsNewVM()) {
                 List<String> netxArguments = new LinkedList<String>();
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/resources/Messages.properties
--- a/rt/net/sourceforge/jnlp/resources/Messages.properties	Wed Jun 24 12:15:33 2009 -0400
+++ b/rt/net/sourceforge/jnlp/resources/Messages.properties	Wed Jun 24 15:02:45 2009 -0400
@@ -110,6 +110,7 @@ RCantReplaceSM=Changing the SecurityMana
 RCantReplaceSM=Changing the SecurityManager is not allowed.
 RDenyStopped=Stopped applications have no permissions.
 RExitNoApp=Can not exit the JVM because the current application cannot be determined.
+RNoLockDir=Unable to create locks directory ({0})
 RUnexpected=Unexpected {0} at {1}
 
 # Boot options, message should be shorter than this ---------------->
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java
--- a/rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Wed Jun 24 12:15:33 2009 -0400
+++ b/rt/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Wed Jun 24 15:02:45 2009 -0400
@@ -104,6 +104,9 @@ public class JNLPRuntime {
     /** contains the arguments passed to the jnlp runtime */
     private static List<String> initialArguments;
 
+    /** Username */
+    public static final String USER = System.getProperty("user.name");
+
     /** User's home directory */
     public static final String HOME_DIR = System.getProperty("user.home");
 
@@ -119,12 +122,17 @@ public class JNLPRuntime {
     /** the ~/.netx/security/trusted.certs file containing trusted certificates */
     public static final String CERTIFICATES_FILE = SECURITY_DIR + File.separator + "trusted.certs";
 
-    /**
-     * the ~/.netx/locks/ directory containing locks for single instance
+    /** the /tmp/ directory used for temporary files */
+    public static final String TMP_DIR = System.getProperty("java.io.tmpdir");
+
+    /**
+     * the /tmp/$USER/netx/locks/ directory containing locks for single instance
      * applications
      */
-    public static final String LOCKS_DIR = NETX_DIR + File.separator + "locks";
-
+    public static final String LOCKS_DIR = TMP_DIR + File.separator + USER + File.separator
+            + "netx" + File.separator + "locks";
+
+    /** the java.home directory */
     public static final String JAVA_HOME_DIR = System.getProperty("java.home");
     
     /** the JNLP file to open to display the network-based about window */
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/net/sourceforge/jnlp/services/ExtendedSingleInstanceService.java	Wed Jun 24 15:02:45 2009 -0400
@@ -0,0 +1,49 @@
+// Copyright (C) 2009 Red Hat, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+package net.sourceforge.jnlp.services;
+
+import javax.jnlp.SingleInstanceService;
+
+import net.sourceforge.jnlp.JNLPFile;
+
+/**
+ * Extends SingleInstanceService to provide a few additional methods that are
+ * required to initialize SingleInstanceService and check things. These methods
+ * are not exposed publicly
+ * 
+ * @author <a href="mailto:omajid at redhat.com">Omair Majid</a>
+ * 
+ */
+interface ExtendedSingleInstanceService extends SingleInstanceService {
+
+    /**
+     * Check if the instance identified by this jnlp file is already running
+     * 
+     * @param jnlpFile The JNLPFile that specifies the application
+     * 
+     * @throws InstanceExistsException if an instance of this application
+     *         already exists
+     * 
+     */
+    void checkSingleInstanceRunning(JNLPFile jnlpFile);
+
+    /**
+     * Start a single instance service based on the current application
+     */
+    void initializeSingleInstance();
+
+}
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/services/InstanceExistsException.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/net/sourceforge/jnlp/services/InstanceExistsException.java	Wed Jun 24 15:02:45 2009 -0400
@@ -0,0 +1,35 @@
+// Copyright (C) 2009 Red Hat, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+package net.sourceforge.jnlp.services;
+
+/**
+ * 
+ * This class represents an exception indicating that an application instance
+ * already exists for this jnlp file
+ * 
+ * @author <a href="mailto:omajid at redhat.com">Omair Majid</a>
+ * 
+ */
+public class InstanceExistsException extends RuntimeException {
+
+    private static final long serialVersionUID = 7950552292795498272L;
+
+    public InstanceExistsException(String message) {
+        super(message);
+    }
+
+}
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/services/ServiceUtil.java
--- a/rt/net/sourceforge/jnlp/services/ServiceUtil.java	Wed Jun 24 12:15:33 2009 -0400
+++ b/rt/net/sourceforge/jnlp/services/ServiceUtil.java	Wed Jun 24 15:02:45 2009 -0400
@@ -17,12 +17,29 @@
 
 package net.sourceforge.jnlp.services;
 
-import java.lang.reflect.*;
-import java.security.*;
-
-import javax.jnlp.*;
-
-import net.sourceforge.jnlp.runtime.*;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import javax.jnlp.BasicService;
+import javax.jnlp.ClipboardService;
+import javax.jnlp.DownloadService;
+import javax.jnlp.ExtensionInstallerService;
+import javax.jnlp.FileOpenService;
+import javax.jnlp.FileSaveService;
+import javax.jnlp.PersistenceService;
+import javax.jnlp.PrintService;
+import javax.jnlp.ServiceManager;
+import javax.jnlp.SingleInstanceService;
+import javax.jnlp.UnavailableServiceException;
+
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.runtime.ApplicationInstance;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.security.SecurityWarningDialog;
 
 /**
@@ -110,6 +127,25 @@ public class ServiceUtil {
         return (PrintService) getService("javax.jnlp.PrintService");
     }
 
+    /**
+     * Returns the SingleInstanceService reference, or null if the service is
+     * unavailable.
+     */
+    public static SingleInstanceService getSingleInstanceService() {
+        return (SingleInstanceService) getService("javax.jnlp.SingleInstanceService");
+    }
+    
+    /**
+     * Checks that this application (represented by the jnlp) isnt already running
+     * @param jnlpFile the {@link JNLPFile} that specifies the application
+     * 
+     * @throws InstanceExistsException if an instance of this application already exists
+     */
+    public static void checkExistingSingleInstance(JNLPFile jnlpFile) {
+        ExtendedSingleInstanceService esis = (ExtendedSingleInstanceService) getSingleInstanceService();
+        esis.checkSingleInstanceRunning(jnlpFile);
+    }
+    
     /**
      * Returns the service, or null instead of an UnavailableServiceException
      */
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/services/SingleInstanceLock.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/net/sourceforge/jnlp/services/SingleInstanceLock.java	Wed Jun 24 15:02:45 2009 -0400
@@ -0,0 +1,203 @@
+// Copyright (C) 2009 Red Hat, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+package net.sourceforge.jnlp.services;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.BindException;
+import java.net.ServerSocket;
+
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+
+/**
+ * This class represents a Lock for single instance jnlp applications
+ * 
+ * The lock is per-session, per user.
+ * 
+ * @author <a href="mailto:omajid at redhat.com">Omair Majid</a>
+ */
+class SingleInstanceLock {
+
+    JNLPFile jnlpFile;
+    File lockFile = null;
+
+    public static final int INVALID_PORT = Integer.MIN_VALUE;
+
+    int port = INVALID_PORT;
+
+    /**
+     * Create an object to manage the instance lock for the specified JNLP file.
+     * 
+     * @param jnlpFile the jnlpfile to create the lock for
+     */
+    public SingleInstanceLock(JNLPFile jnlpFile) {
+        this.jnlpFile = jnlpFile;
+        lockFile = getLockFile();
+
+    }
+
+    /**
+     * Create/overwrite the instance lock for the jnlp file.
+     * 
+     * @param localPort the network port for the lock
+     * @throws IOException on any io problems
+     */
+    public void createWithPort(int localPort) throws IOException {
+
+        BufferedWriter lockFileWriter = new BufferedWriter(new FileWriter(lockFile, false));
+        lockFileWriter.write(String.valueOf(localPort));
+        lockFileWriter.newLine();
+        lockFileWriter.flush();
+        lockFileWriter.close();
+
+    }
+
+    /**
+     * Returns true if the lock if valid. That is, the lock exists, and port it
+     * points to is listening for incoming messages.
+     */
+    public boolean isValid() {
+        return (exists() && getPort() != INVALID_PORT && !isPortFree(getPort()));
+    }
+
+    /**
+     * Returns the port in this lock file.
+     */
+    public int getPort() {
+        if (!exists()) {
+            return INVALID_PORT;
+        }
+
+        try {
+            parseFile();
+        } catch (NumberFormatException e) {
+            port = INVALID_PORT;
+        } catch (IOException e) {
+            port = INVALID_PORT;
+        }
+        return port;
+
+    }
+
+    /**
+     * Returns true if the lock file already exists.
+     */
+    private boolean exists() {
+        return lockFile.exists();
+    }
+
+    /**
+     * Returns true if the port is free.
+     */
+    private boolean isPortFree(int port) {
+        try {
+            ServerSocket socket = new ServerSocket(port);
+            socket.close();
+            return true;
+        } catch (BindException e) {
+            return false;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Return a file object that represents the lock file. The lock file itself
+     * may or may not exist.
+     */
+    private File getLockFile() {
+        File baseDir = new File(JNLPRuntime.LOCKS_DIR);
+
+        if (!baseDir.isDirectory() && !baseDir.mkdirs()) {
+            throw new RuntimeException(R("RNoLockDir", baseDir));
+        }
+        String lockFileName = getLockFileName();
+        File applicationLockFile = new File(baseDir, lockFileName);
+        return applicationLockFile;
+    }
+
+    /**
+     * Returns the name of the lock file.
+     */
+    private String getLockFileName() {
+        String initialName = "";
+
+        if (jnlpFile.getSourceLocation() != null) {
+            initialName = initialName + jnlpFile.getSourceLocation();
+        } else {
+            initialName = initialName + jnlpFile.getFileLocation();
+        }
+
+        if (jnlpFile.getFileVersion() != null) {
+            initialName = initialName + jnlpFile.getFileVersion().toString();
+        }
+        
+        initialName = initialName + getCurrentDisplay();
+        String encodedName;
+
+        /*
+         * FIXME
+         * 
+         * Assuming safe characters are 'a-z','A-Z','0-9', '_', '.'
+         */
+
+        encodedName = initialName.replaceAll("[^a-zA-Z0-9.]", "_");
+
+        return encodedName;
+
+    }
+
+    /**
+     * Parse the lock file.
+     * 
+     * @throws NumberFormatException
+     * @throws IOException
+     */
+    private void parseFile() throws NumberFormatException, IOException {
+        BufferedReader lockFileReader = new BufferedReader(new FileReader(lockFile));
+        int port = Integer.valueOf(lockFileReader.readLine());
+        lockFileReader.close();
+        this.port = port;
+    }
+
+    /**
+     * Returns a string identifying this display.
+     * 
+     * Implementation note: On systems with X support, this is the DISPLAY
+     * variable
+     * 
+     * @return a string that is guaranteed to be not null.
+     */
+    private String getCurrentDisplay() {
+        String display = System.getenv("DISPLAY");
+        return (display == null) ? "" : display;
+    }
+
+    private static String R(String key) {
+        return JNLPRuntime.getMessage(key);
+    }
+
+    private static String R(String key, Object param) {
+        return JNLPRuntime.getMessage(key, new Object[] { param });
+    }
+
+}
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/services/XServiceManagerStub.java
--- a/rt/net/sourceforge/jnlp/services/XServiceManagerStub.java	Wed Jun 24 12:15:33 2009 -0400
+++ b/rt/net/sourceforge/jnlp/services/XServiceManagerStub.java	Wed Jun 24 15:02:45 2009 -0400
@@ -51,7 +51,8 @@ public class XServiceManagerStub impleme
         "javax.jnlp.FileOpenService",
         "javax.jnlp.FileSaveService",
         "javax.jnlp.ClipboardService",
-        "javax.jnlp.PrintService"
+        "javax.jnlp.PrintService",
+        "javax.jnlp.SingleInstanceService"
     };
 
     private static Object services[] = {
@@ -63,7 +64,8 @@ public class XServiceManagerStub impleme
         ServiceUtil.createPrivilegedProxy(FileOpenService.class, new XFileOpenService()),
         ServiceUtil.createPrivilegedProxy(FileSaveService.class, new XFileSaveService()),
         ServiceUtil.createPrivilegedProxy(ClipboardService.class, new XClipboardService()),
-        ServiceUtil.createPrivilegedProxy(PrintService.class, new XPrintService())
+        ServiceUtil.createPrivilegedProxy(PrintService.class, new XPrintService()),
+        ServiceUtil.createPrivilegedProxy(ExtendedSingleInstanceService.class, new XSingleInstanceService())
     };
 
 
diff -r 1ba29bfca5a0 -r ed75376cfe3a rt/net/sourceforge/jnlp/services/XSingleInstanceService.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rt/net/sourceforge/jnlp/services/XSingleInstanceService.java	Wed Jun 24 15:02:45 2009 -0400
@@ -0,0 +1,229 @@
+// Copyright (C) 2009 Red Hat, Inc.
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 



More information about the distro-pkg-dev mailing list