diff options
10 files changed, 709 insertions, 8 deletions
@@ -1,3 +1,25 @@ +2012-09-04 Jiri Vanek <[email protected]> + Danesh Dadachanji <[email protected]> + + Single instance support for jnlp-href and tests + * netx/net/sourceforge/jnlp/services/XSingleInstanceService.java: + (initializeSingleInstance) fixed code for catching running instance + (checkSingleInstanceRunning) Added handling of parameters. + * netx/net/sourceforge/jnlp/Launcher.java: (launchApplication), + (launchApplet) Added debug output that instance is already running. + (getApplet) added check for services and debug output + * netx/net/sourceforge/jnlp/resources/Messages.properties: added + (LSingleInstanceExists) entry for exception. + tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp + * tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTestWS.jnlp: + * tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_clasical.html: + * tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_jnlpHref.html: + Applet and application in jnlp or html launching files. + * tests/reproducers/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java + SingleInstance implementing applet/application + * tests/reproducers/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java + Testfile for launching for above jnlps/htmls as testcases. + 2012-08-27 Adam Domurad <[email protected]> Fixes PR920, duplicate loading of classes in certain cases diff --git a/netx/net/sourceforge/jnlp/Launcher.java b/netx/net/sourceforge/jnlp/Launcher.java index 15b1e56..1692b0e 100644 --- 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 index 3c42cb8..1f3a1e5 100644 --- a/netx/net/sourceforge/jnlp/resources/Messages.properties +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties @@ -82,7 +82,8 @@ 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.
LNoSecInstance=Error: No security instance for {0}. The application may have trouble continuing
-LCertFoundIn={0} found in cacerts ({1})
+LCertFoundIn={0} found in cacerts ({1}) +LSingleInstanceExists=Another instance of this applet already exists and only one may be run at the same time.
JNotApplet=File is not an applet.
JNotApplication=File is not an application.
diff --git a/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java b/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java index 1a40794..35da018 100644 --- a/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java +++ b/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java @@ -24,11 +24,14 @@ import java.net.Socket; import java.net.UnknownHostException; import java.util.LinkedList; import java.util.List; +import java.util.Map.Entry; +import java.util.Set; import javax.jnlp.SingleInstanceListener; import javax.management.InstanceAlreadyExistsException; import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.PluginBridge; import net.sourceforge.jnlp.runtime.JNLPRuntime; /** @@ -104,13 +107,14 @@ public class XSingleInstanceService implements ExtendedSingleInstanceService { * @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); @@ -127,6 +131,7 @@ public class XSingleInstanceService implements ExtendedSingleInstanceService { * @throws InstanceExistsException if an instance of this application * already exists */ + @Override public void checkSingleInstanceRunning(JNLPFile jnlpFile) { SingleInstanceLock lockFile = new SingleInstanceLock(jnlpFile); if (lockFile.isValid()) { @@ -134,9 +139,28 @@ public class XSingleInstanceService implements ExtendedSingleInstanceService { 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. + //Right now better to forward at least something + Set<Entry<String, String>> currentParams = jnlpFile.getApplet().getParameters().entrySet(); + args = new String[currentParams.size() * 2]; + int i = 0; + for (Entry<String, String> entry : currentParams) { + args[i] = entry.getKey(); + args[i+1] = entry.getValue(); + i += 2; + } + } 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/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp new file mode 100644 index 0000000..a89f46f --- /dev/null +++ b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest.jnlp @@ -0,0 +1,60 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + + --> +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0" href="SingleInstanceTest.jnlp" codebase="."> + <information> + <title>SingleInstanceApplet</title> + <vendor>IcedTea</vendor> + <homepage href="http://icedtea.classpath.org/wiki/IcedTea-Web#Testing_IcedTea-Web"/> + <description>SingleInstanceApplet</description> + <offline/> + </information> + <resources> + <j2se version="1.4+"/> + <jar href="SingleInstanceServiceTest.jar"/> + </resources> + <applet-desc + documentBase="." + name="SingleInstanceChecker" + main-class="SingleInstanceChecker" + width="100" + height="100"> + <param name="p1" value="v1"/> + <param name="p2" value="v2"/> + </applet-desc> +</jnlp>
\ No newline at end of file diff --git a/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTestWS.jnlp b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTestWS.jnlp new file mode 100644 index 0000000..698ea65 --- /dev/null +++ b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTestWS.jnlp @@ -0,0 +1,55 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + + --> +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0" href="SingleInstanceTest.jnlp" codebase="."> + <information> + <title>SingleInstanceAppletWS</title> + <vendor>IcedTea</vendor> + <homepage href="http://icedtea.classpath.org/wiki/IcedTea-Web#Testing_IcedTea-Web"/> + <description>SingleInstanceAppletWS</description> + <offline/> + </information> + <resources> + <j2se version="1.4+"/> + <jar href="SingleInstanceServiceTest.jar"/> + </resources> + <application-desc main-class="SingleInstanceChecker"> + <argument>v7</argument> + <argument>v8</argument> + </application-desc> +</jnlp>
\ No newline at end of file diff --git a/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_clasical.html b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_clasical.html new file mode 100644 index 0000000..81ff25e --- /dev/null +++ b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_clasical.html @@ -0,0 +1,50 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + +--> +<html> + <head></head> + <body> + <applet codebase="." + archive="SingleInstanceServiceTest.jar" + code="SingleInstanceChecker.class" + width="100" + height="100"> + <param name="p5" value="v5"/> + <param name="p6" value="v6"/> + </applet> + </body> +</html> diff --git a/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_jnlpHref.html b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_jnlpHref.html new file mode 100644 index 0000000..59e69f3 --- /dev/null +++ b/tests/reproducers/simple/SingleInstanceServiceTest/resources/SingleInstanceTest_jnlpHref.html @@ -0,0 +1,47 @@ +<!-- + +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; either version 2, or (at your option) +any later version. + +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. + +--> +<html> + <head></head> + <body> + <applet code="SingleInstanceChecker.class" width="800" height="600"> + <param name="jnlp_href" value="SingleInstanceTest.jnlp"> + <param name="p3" value="v3"/> + <param name="p4" value="v4"/> + </applet> + </body> +</html> diff --git a/tests/reproducers/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java b/tests/reproducers/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java new file mode 100644 index 0000000..9e05132 --- /dev/null +++ b/tests/reproducers/simple/SingleInstanceServiceTest/srcs/SingleInstanceChecker.java @@ -0,0 +1,158 @@ +/* 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 implements SingleInstanceListener { + + private SingleInstanceChecker self; + Killer killer; + + private static class Killer extends Thread { + + private int timeout; + private String timeoutText; + + public Killer() { + timeout = 5000; + timeoutText = Integer.toString(timeout); + } + + public Killer(int n) { + timeout = n; + timeoutText = Integer.toString(timeout); + } + + public Killer(int n, String s) { + timeout = n; + timeoutText = s; + } + + @Override + public void run() { + try { + Thread.sleep(timeout); + System.out.println("Applet killing itself after " + timeoutText + " ms of life"); + System.exit(0); + } catch (Exception ex) { + } + } + } + + public SingleInstanceChecker() { + self = this; + } + + private void proceed() { + + try { + SingleInstanceService testService = (SingleInstanceService) ServiceManager.lookup("javax.jnlp.SingleInstanceService"); + System.out.println("SingleInstanceChecker: Adding listener to service."); + testService.addSingleInstanceListener(this); + System.out.println("SingleInstanceChecker: Listener added."); + } catch (UnavailableServiceException use) { + System.err.println("SingleInstanceChecker: Service lookup failed."); + use.printStackTrace(); + } finally { + new Thread(new Runnable() { + + @Override + public void run() { + try { + Thread.sleep(5000); + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + startKiller(2); + } + } + }).start(); + } + } + + //killer is started when params are received, or when application is running to long + private void startKiller(int a) { + synchronized (self) { + if (killer == null) { + if (a == 2) { + killer = new Killer(5000, "10000"); + killer.start(); + } else { + killer = new Killer(5000); + killer.start(); + } + } + } + } + + @Override + public void newActivation(String[] params) { + String paramsString = ""; + for (String param : params) { + paramsString += " "+param; + } + System.out.println("Parameters received by SingleInstanceChecker:" + paramsString); + startKiller(1); + } + + @Override + public void start() { + System.out.print("Parameters received by during launch:"); + for (int i=1; i<10; i++ ) { + String s=getParameter("p"+i); + if (s!=null){ + System.out.print(" "+s); + } + } + System.out.println(); + proceed(); + } + + public static void main(String[] args) { + System.out.print("Parameters received by during launch:"); + for (String string : args) { + System.out.print(" "+string); + } + System.out.println(); + new SingleInstanceChecker().proceed(); + } +} diff --git a/tests/reproducers/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java b/tests/reproducers/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java new file mode 100644 index 0000000..93e89d8 --- /dev/null +++ b/tests/reproducers/simple/SingleInstanceServiceTest/testcases/SingleInstanceTest.java @@ -0,0 +1,265 @@ +/* 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 net.sourceforge.jnlp.ContentReaderListener; +import net.sourceforge.jnlp.ProcessResult; + +import net.sourceforge.jnlp.ServerAccess; +import net.sourceforge.jnlp.annotations.NeedsDisplay; +import net.sourceforge.jnlp.annotations.TestInBrowsers; +import net.sourceforge.jnlp.browsertesting.BrowserFactory; +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 static boolean isJnlp(String launchFile) { + return launchFile.toLowerCase().endsWith(".jnlp"); + } + + private static boolean isHtml(String launchFile) { + return launchFile.toLowerCase().endsWith(".html"); + } + + private static void checkNulls(String testName, ProcessResult prSecondInst, String var) { + Assert.assertNotNull(var + " SingleInstanceTest." + testName + "result was null ", prSecondInst); + Assert.assertNotNull(var + " SingleInstanceTest." + testName + "result was null ", prSecondInst.stdout); + Assert.assertNotNull(var + " SingleInstanceTest." + testName + "result was null ", prSecondInst.stderr); + } + + private static void evaluateFirstInstance(ProcessResult prFirstInst, String testName) { + checkNulls(testName, prFirstInst, "First"); + // First Instance's result should run without exceptions. + String s0 = "SingleInstanceChecker: Adding listener to service."; + String s1 = "Parameters received by SingleInstanceChecker"; + String ss = "SingleInstanceChecker: Service lookup failed."; + Assert.assertTrue("SingleInstanceTest." + testName + + "'s first PR stdout should contain " + s0 + " but didn't", + prFirstInst.stdout.contains(s0)); + Assert.assertTrue("SingleInstanceTest." + testName + + "'s first PR stdout should contain " + s1 + " but didn't", + prFirstInst.stdout.contains(s1)); + Assert.assertFalse("SingleInstanceTest." + testName + + "'s first PR stderr should not contain " + ss + " but did", + prFirstInst.stderr.contains(ss)); + } + + private static void evaluateSecondInstance(ProcessResult prSecondInst, String testName) { + checkNulls(testName, prSecondInst, "Second"); + // 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)); + } + + private static boolean bothHtml(String app1, String app2) { + return isHtml(app1) && isHtml(app2); + } + + private static class AsyncProcess extends Thread { + + private ProcessResult pr = null; + private String launchFile; + + public AsyncProcess(String launchFile) { + this.launchFile = launchFile; + + } + + @Override + public void run() { + try { + boolean isJavawsTest = isJnlp(launchFile); + pr = isJavawsTest ? server.executeJavawsHeadless(launchFile, null, null) + : server.executeBrowser(launchFile, null, null); + } catch (Exception ex) { + ServerAccess.logException(ex); + } finally { + if (pr == null) { + pr = new ProcessResult("", "", null, true, null, null); + } + } + } + + public ProcessResult getPr() { + return pr; + } + } + + private ProcessResult[] executeSingleInstanceCheck(String app1, String app2) throws Exception { + + final AsyncProcess ap = new AsyncProcess(app2); + ContentReaderListener clr = new ContentReaderListener() { + + @Override + public void charReaded(char ch) { + //nothing to do + } + + @Override + public void lineReaded(String s) { + if (s.contains(listenerConfirmed)) { + ap.start(); + } + } + }; + boolean isJavawsTest = isJnlp(app1); + final ProcessResult pr = isJavawsTest ? server.executeJavawsHeadless(app1, clr, null) + : server.executeBrowser(app1, clr, null); + + int timeout = 0; + while (ap.pr == null) { + timeout++; + Thread.sleep(500); + if (timeout > 20) { + break; + } + } + return new ProcessResult[]{pr, ap.getPr()}; + + } + //files + private static final String jnlpApplet = "/SingleInstanceTest.jnlp"; + private static final String jnlpApplication = "/SingleInstanceTestWS.jnlp"; + private static final String htmlpApplet = "/SingleInstanceTest_clasical.html"; + private static final String htmlJnlpHrefApplet = "/SingleInstanceTest_jnlpHref.html"; + //constants + private static final String listenerConfirmed = "SingleInstanceChecker: Listener added."; + + @Test + @NeedsDisplay + @TestInBrowsers(testIn = Browsers.one) + public void htmlpAppletXhtmlpApplet() throws Exception { + ProcessResult[] results = executeSingleInstanceCheck(htmlpApplet, htmlpApplet); + String id = "htmlpAppletXhtmlpApplet"; + evaluateFirstInstance(results[0], id); + //the first browser is consuming all the output + evaluateSecondInstance(results[0], id); + + } + + @Test + @NeedsDisplay + @TestInBrowsers(testIn = Browsers.one) + public void htmlJnlpHrefAppletXhtmlJnlpHrefApplet() throws Exception { + ProcessResult[] results = executeSingleInstanceCheck(htmlJnlpHrefApplet, htmlJnlpHrefApplet); + String id = "htmlJnlpHrefAppletXhtmlJnlpHrefApplet"; + evaluateFirstInstance(results[0], id); + //the first browser is consuming all the output + evaluateSecondInstance(results[0], id); + + } + + @Test + public void jnlpApplicationXjnlpApplication() throws Exception { + ProcessResult[] results = executeSingleInstanceCheck(jnlpApplication, jnlpApplication); + String id = "jnlpApplicationXjnlpApplication"; + evaluateFirstInstance(results[0], id); + evaluateSecondInstance(results[1], id); + + } + + @Test + @NeedsDisplay + public void jnlpAppleXjnlpApplet() throws Exception { + ProcessResult[] results = executeSingleInstanceCheck(jnlpApplet, jnlpApplet); + String id = "jnlpAppleXjnlpApplet"; + evaluateFirstInstance(results[0], id); + evaluateSecondInstance(results[1], id); + } + + public static void main(String[] args) throws Exception { + new SingleInstanceTest().main(); + } + + /** + * This "test" is testing all possible variations of launches. + * However html x jnlp (or vice versa) tests are failing + * I do not suppose this should ever happen in real life, so I'm not including this as @KnownToFail + * See the list of results on below for couriosity ;) + * + *Passed /SingleInstanceTest.jnlp x /SingleInstanceTest.jnlp + *Passed /SingleInstanceTest.jnlp x /SingleInstanceTestWS.jnlp + *FAILED /SingleInstanceTest.jnlp x /SingleInstanceTest_jnlpHref.html - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTest.jnlp x /SingleInstanceTest_clasical.html - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *Passed /SingleInstanceTestWS.jnlp x /SingleInstanceTest.jnlp + *Passed /SingleInstanceTestWS.jnlp x /SingleInstanceTestWS.jnlp + *java.lang.NoSuchMethodException: SingleInstanceTest.access$000() + *FAILED /SingleInstanceTestWS.jnlp x /SingleInstanceTest_jnlpHref.html - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTestWS.jnlp x /SingleInstanceTest_clasical.html - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTest_jnlpHref.html x /SingleInstanceTest.jnlp - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTest_jnlpHref.html x /SingleInstanceTestWS.jnlp - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *Passed /SingleInstanceTest_jnlpHref.html x /SingleInstanceTest_jnlpHref.html + *FAILED /SingleInstanceTest_jnlpHref.html x /SingleInstanceTest_clasical.html - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTest_clasical.html x /SingleInstanceTest.jnlp - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTest_clasical.html x /SingleInstanceTestWS.jnlp - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *FAILED /SingleInstanceTest_clasical.html x /SingleInstanceTest_jnlpHref.html - java.lang.AssertionError: SingleInstanceTest.main's first PR stdout should contain Parameters received by SingleInstanceChecker but didn't + *Passed /SingleInstanceTest_clasical.html x /SingleInstanceTest_clasical.html + */ + public void main() throws Exception { + //just for fun try all not so probable cominations + String[] args = new String[]{jnlpApplet, jnlpApplication, htmlJnlpHrefApplet, htmlpApplet}; + //normally handled by annotation + server.setCurrentBrowser(BrowserFactory.getFactory().getRandom()); + for (int i = 0; i < args.length; i++) { + String app1 = args[i]; + for (int j = 0; j < args.length; j++) { + String app2 = args[j]; + try { + ProcessResult[] results = executeSingleInstanceCheck(app1, app2); + evaluateFirstInstance(results[0], "main"); + if (bothHtml(app1, app2)) { + evaluateSecondInstance(results[0], "main"); + } else { + evaluateSecondInstance(results[1], "main"); + } + System.out.println("Passed " + app1 + " x " + app2); + } catch (Error ex) { + System.out.println("FAILED " + app1 + " x " + app2 + " - " + ex.toString()); + //ex.printStackTrace(); + } + } + + } + + } + +} |