diff --git a/netx-dist-tests-whitelist b/netx-dist-tests-whitelist
--- a/netx-dist-tests-whitelist
+++ b/netx-dist-tests-whitelist
@@ -1,1 +1,1 @@
-.*
+SingleInst.*
diff --git a/netx/net/sourceforge/jnlp/Launcher.java b/netx/net/sourceforge/jnlp/Launcher.java
--- a/netx/net/sourceforge/jnlp/Launcher.java
+++ b/netx/net/sourceforge/jnlp/Launcher.java
@@ -536,6 +536,9 @@ public class Launcher {
try {
ServiceUtil.checkExistingSingleInstance(file);
} catch (InstanceExistsException e) {
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Single instance application is already running.");
+ }
return null;
}
@@ -653,11 +656,17 @@ public class Launcher {
throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplet"), R("LNotAppletInfo")));
try {
+ ServiceUtil.checkExistingSingleInstance(file);
AppletInstance applet = createApplet(file, enableCodeBase, cont);
applet.initialize();
applet.getAppletEnvironment().startApplet(); // this should be a direct call to applet instance
return applet;
+ } catch (InstanceExistsException ieex) {
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Single instance applet is already running.");
+ }
+ throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")));
} catch (LaunchException lex) {
throw launchError(lex);
} catch (Exception ex) {
@@ -673,9 +682,17 @@ public class Launcher {
throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplet"), R("LNotAppletInfo")));
try {
+ ServiceUtil.checkExistingSingleInstance(file);
+
AppletInstance applet = createApplet(file, enableCodeBase, cont);
applet.initialize();
return applet;
+
+ } catch (InstanceExistsException ieex) {
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Single instance applet is already running.");
+ }
+ throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")));
} catch (LaunchException lex) {
throw launchError(lex);
} catch (Exception ex) {
@@ -688,6 +705,8 @@ public class Launcher {
* a thread in the application's thread group.
*/
protected ApplicationInstance launchInstaller(JNLPFile file) throws LaunchException {
+ // TODO Check for an existing single instance once implemented.
+ // ServiceUtil.checkExistingSingleInstance(file);
throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCNotSupported"), R("LNoInstallers"), R("LNoInstallersInfo")));
}
diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties
@@ -81,6 +81,7 @@ LUnsignedJarWithSecurityInfo=Application
LSignedAppJarUsingUnsignedJar=Signed application using unsigned jars.
LSignedAppJarUsingUnsignedJarInfo=The main application jar is signed, but some of the jars it is using aren't.
LSignedJNLPFileDidNotMatch=The signed JNLP file did not match the launching JNLP file.
+LSingleInstanceExists=Another instance of this applet already exists and only one may be run at the same time.
LNoSecInstance=Error: No security instance for {0}. The application may have trouble continuing
LCertFoundIn={0} found in cacerts ({1})
diff --git a/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java b/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java
--- a/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java
+++ b/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java
@@ -29,6 +29,9 @@ import javax.jnlp.SingleInstanceListener
import javax.management.InstanceAlreadyExistsException;
import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.PluginBridge;
+import net.sourceforge.jnlp.runtime.AppletInstance;
+import net.sourceforge.jnlp.runtime.ApplicationInstance;
import net.sourceforge.jnlp.runtime.JNLPRuntime;
/**
@@ -104,13 +107,14 @@ public class XSingleInstanceService impl
* @throws InstanceAlreadyExistsException if the instance already exists
*/
public void initializeSingleInstance() {
- if (!initialized) {
- // this is called after the application has started. so safe to use
- // JNLPRuntime.getApplication()
- checkSingleInstanceRunning(JNLPRuntime.getApplication().getJNLPFile());
+ // this is called after the application has started. so safe to use
+ // JNLPRuntime.getApplication()
+ JNLPFile jnlpFile = JNLPRuntime.getApplication().getJNLPFile();
+ if (!initialized || jnlpFile instanceof PluginBridge) {
+ // Either a new process or a new applet being handled by the plugin.
+ checkSingleInstanceRunning(jnlpFile);
initialized = true;
SingleInstanceLock lockFile;
- JNLPFile jnlpFile = JNLPRuntime.getApplication().getJNLPFile();
lockFile = new SingleInstanceLock(jnlpFile);
if (!lockFile.isValid()) {
startListeningServer(lockFile);
@@ -134,9 +138,21 @@ public class XSingleInstanceService impl
if (JNLPRuntime.isDebug()) {
System.out.println("Lock file is valid (port=" + port + "). Exiting.");
}
+
+ String[] args = null;
+ if (jnlpFile.isApplet()) {
+ // FIXME Proprietary plug-in is unclear about how to handle
+ // applets and their parameters. Potentially use
+ // jnlpFile.getApplet().getParameters();
+ args = new String[0];
+ } else if (jnlpFile.isInstaller()) {
+ // TODO Implement this once installer service is available.
+ } else {
+ args = jnlpFile.getApplication().getArguments();
+ }
+
try {
- sendProgramArgumentsToExistingApplication(port, jnlpFile.getApplication()
- .getArguments());
+ sendProgramArgumentsToExistingApplication(port, args);
throw new InstanceExistsException(String.valueOf(port));
} catch (IOException e) {
throw new RuntimeException(e);
diff --git a/tests/jnlp_tests/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.html b/tests/jnlp_tests/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.html
new file mode 100644
--- /dev/null
+++ b/tests/jnlp_tests/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
diff --git a/tests/jnlp_tests/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp b/tests/jnlp_tests/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp
new file mode 100644
--- /dev/null
+++ b/tests/jnlp_tests/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp
@@ -0,0 +1,58 @@
+
+
+
+
+ SingleInstance
+ IcedTea
+
+ SingleInstance
+
+
+
+
+
+
+
+
+
diff --git a/tests/jnlp_tests/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java b/tests/jnlp_tests/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java
new file mode 100644
--- /dev/null
+++ b/tests/jnlp_tests/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java
@@ -0,0 +1,92 @@
+/* SingleInstanceChecker.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+import java.applet.Applet;
+
+import javax.jnlp.SingleInstanceListener;
+import javax.jnlp.SingleInstanceService;
+import javax.jnlp.ServiceManager;
+import javax.jnlp.UnavailableServiceException;
+
+public class SingleInstanceChecker extends Applet {
+ private class Killer extends Thread {
+
+ public int n = 5000;
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(n);
+ System.out.println("Applet killing itself after " + n
+ + " ms of life");
+ System.exit(0);
+ } catch (Exception ex) {
+ }
+ }
+ }
+
+ class SingInstTestListener implements SingleInstanceListener {
+ public void newActivation(String[] params) {
+ String paramsString = "";
+ for (String param : params) {
+ paramsString += param + " ";
+ }
+ System.out.println("Paramaters received by SingleInstanceChecker: " + paramsString);
+ killer = new Killer();
+ killer.start();
+ }
+ }
+
+ private Killer killer;
+
+ @Override
+ public void init() {
+ try {
+ SingleInstanceService testService = (SingleInstanceService) ServiceManager
+ .lookup("javax.jnlp.SingleInstanceService");
+ System.out.println("SingleInstanceChecker: Adding listener to service.");
+ SingInstTestListener testListener = new SingInstTestListener();
+ testService.addSingleInstanceListener(testListener);
+ System.out.println("SingleInstanceChecker: Listener added.");
+ } catch (UnavailableServiceException use) {
+ System.err.println("SingleInstanceChecker: Service lookup failed.");
+ use.printStackTrace();
+ return;
+ }
+ }
+}
+
diff --git a/tests/jnlp_tests/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java b/tests/jnlp_tests/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java
new file mode 100644
--- /dev/null
+++ b/tests/jnlp_tests/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java
@@ -0,0 +1,149 @@
+/* SingleInstanceTest.java
+Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+ */
+
+import java.util.List;
+
+import net.sourceforge.jnlp.ServerAccess;
+import net.sourceforge.jnlp.ServerAccess.ProcessResult;
+import net.sourceforge.jnlp.annotations.NeedsDisplay;
+import net.sourceforge.jnlp.annotations.TestInBrowsers;
+import net.sourceforge.jnlp.browsertesting.BrowserTest;
+import net.sourceforge.jnlp.browsertesting.Browsers;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SingleInstanceTest extends BrowserTest {
+
+ private void evaluateApplet(ProcessResult prFirstInst,
+ ProcessResult prSecondInst, String testName) {
+ // First Instance's result should run without exceptions.
+ String s0 = "SingleInstanceChecker: Adding listener to service.";
+ Assert.assertTrue("SingleInstanceTest." + testName
+ + "'s first PR stdout should contain " + s0 + " but didn't",
+ prFirstInst.stdout.contains(s0));
+ String s1 = "Paramaters received by SingleInstanceChecker";
+ Assert.assertTrue("SingleInstanceTest." + testName
+ + "'s first PR stdout should contain " + s1 + " but didn't",
+ prFirstInst.stdout.contains(s1));
+ String ss = "SingleInstanceChecker: Service lookup failed.";
+ Assert.assertFalse("SingleInstanceTest." + testName
+ + "'s first PR stderr should not contain " + ss + " but did",
+ prFirstInst.stderr.contains(ss));
+
+ // Second Instance's result should throw a LaunchException.
+ String s2 = "net.sourceforge.jnlp.LaunchException";
+ Assert.assertTrue("SingleInstanceTest." + testName
+ + "'s second PR stderr should contain " + s2 + " but didn't",
+ prSecondInst.stderr.contains(s2));
+ }
+
+ @NeedsDisplay
+ @Test
+ public void WebstartAppletTest() throws Exception {
+ SingleInstanceProcess firstProc = new SingleInstanceProcess("/SingleInstanceTest.jnlp", true);
+ ServerAccess.logOutputReprint("\n\n\n\n\nStarting it");
+ firstProc.start();
+ ServerAccess.logOutputReprint("Waiting");
+ waitForSingleInstanceProcess(firstProc);
+
+ ProcessResult prSecondInst = server.executeJavawsHeadless(null, "/SingleInstanceTest.jnlp");
+
+ // Initialize after second process has been executed and finished (or timed out).
+ ProcessResult prFirstInst = firstProc.getPr();
+
+ ServerAccess.logOutputReprint("Evaluate\n\n\n\n\n\n\n");
+ evaluateApplet(prFirstInst, prSecondInst, "WebstartAppletTest");
+ Assert.assertFalse(prFirstInst.wasTerminated);
+ Assert.assertEquals((Integer) 0, prFirstInst.returnValue);
+ Assert.assertFalse(prSecondInst.wasTerminated);
+ Assert.assertEquals((Integer) 0, prSecondInst.returnValue);
+ }
+
+ // @NeedsDisplay
+ // @Test
+ // @TestInBrowsers(testIn = { Browsers.one })
+ // public void PluginJNLPHrefTest() throws Exception {
+ // ProcessResult prFirstInst = server.executeBrowser("/SingleInstanceTest.html");
+ // ProcessResult prSecondInst = server.executeBrowser("/SingleInstanceTest.html");
+ // prFirstInst.process.destroy();
+ // evaluateApplet(prFirstInst, prSecondInst, "PluginJNLPHrefTest");
+ // Assert.assertTrue(prFirstInst.wasTerminated);
+ // Assert.assertTrue(prSecondInst.wasTerminated);
+ // }
+
+ public static void waitForSingleInstanceProcess(SingleInstanceProcess sip)
+ throws InterruptedException {
+ while (!sip.getPr().stdout.contains("SingleInstanceChecker: Listener added.")) {
+ Thread.sleep(500);
+ }
+ ServerAccess.logOutputReprint("Finished wait");
+ }
+
+ private static class SingleInstanceProcess extends Thread {
+
+ private ProcessResult pr = null;
+ private String launchFile;
+ private List args;
+ private boolean isJavawsTest;
+
+ SingleInstanceProcess(String launchFile, boolean isJavawsTest) {
+ this(launchFile, null, isJavawsTest);
+ }
+
+ public SingleInstanceProcess(String launchFile, List args,
+ boolean isJavawsTest) {
+ this.launchFile = launchFile;
+ this.args = args;
+ this.isJavawsTest = isJavawsTest;
+ }
+
+ @Override
+ public void run() {
+ try {
+ pr = isJavawsTest ? server.executeJavawsHeadless(args, launchFile)
+ : server.executeBrowser(launchFile);
+ } catch (Exception ex) {
+ ServerAccess.logException(ex);
+ }
+ }
+
+ public ProcessResult getPr() {
+ return pr;
+ }
+ }
+}