1 /*
   2  * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  */
  24 
  25 package test.javaclient.shared;
  26 
  27 import com.sun.javafx.application.ParametersImpl;
  28 import com.sun.javafx.tk.Toolkit;
  29 import java.util.Iterator;
  30 import javafx.stage.Stage;
  31 import javafx.application.Application;
  32 import javafx.application.Platform;
  33 import javafx.stage.Window;
  34 import org.jemmy.env.Timeout;
  35 import org.jemmy.timing.State;
  36 import org.jemmy.timing.Waiter;
  37 
  38 /**
  39  * Launcher class which is aware of different run modes we need for our tests
  40  *
  41  * @author Sergey Grinev
  42  */
  43 public class AppLauncher {
  44 
  45     /**
  46      * For tests, which will not wait for stage appearing, and need only toolkit start.
  47      */
  48     public static final String WAIT_TOOLKIT_START_ONLY = "WAIT_TOOLKIT_START_ONLY";
  49 
  50     public void launch(final Class cl, String[] args) {
  51         switch (mode) {
  52             case DEFAULT:
  53                 defaultLaunch(cl, args);
  54                 break;
  55             case SWING:
  56                 instantiateOnSwingQueue(cl, args);
  57                 break;
  58             case SWT:
  59                 instantiateOnSWTQueue(cl, args);
  60                 break;
  61             case REMOTE:
  62                 launchOnRemoteStage(cl, args);
  63                 break;
  64             default:
  65                 throw new IllegalStateException("Unknown launch mode: " + mode);
  66 
  67         }
  68     }
  69 
  70     public enum Mode {
  71 
  72         DEFAULT, SWING, SWT, REMOTE
  73     };
  74     private Mode mode = Mode.DEFAULT;
  75     private long testDelay = Long.getLong("test.javafx.testdelay", 1000);
  76     private long testDelayRemote = Long.getLong("test.javafx.testdelayremote", 4000);
  77 
  78     public long getTestDelay() {
  79         return mode == Mode.REMOTE ? testDelayRemote : testDelay;
  80     }
  81 
  82     public Mode getMode() {
  83         return mode;
  84     }
  85 
  86     private AppLauncher() {
  87         if (Boolean.getBoolean("javafx.swinginteroperability")) {
  88             mode = Mode.SWING;
  89         }
  90         if (Boolean.getBoolean("javafx.swtinteroperability")) {
  91             mode = Mode.SWT;
  92         }
  93     }
  94     private final static AppLauncher INSTANCE = new AppLauncher();
  95 
  96     public static AppLauncher getInstance() {
  97         return INSTANCE;
  98     }
  99 
 100     private static void instantiateOnSwingQueue(final Class<? extends Interoperability> cl, String[] args) {
 101         try {
 102             SwingAWTUtils.instantiateOnSwingQueue(cl);
 103         } catch (Exception ex) {
 104             ex.printStackTrace();
 105         }
 106     }
 107 
 108     private static void instantiateOnSWTQueue(final Class<? extends Interoperability> cl, String[] args) {
 109         try {
 110             Interoperability obj = cl.newInstance();
 111             obj.startSWT();
 112         } catch (Exception ex) {
 113             ex.printStackTrace();
 114         }
 115     }
 116 
 117     private void launchOnRemoteStage(final Class<? extends Application> cl, final String[] args) {
 118         Platform.runLater(new Runnable() {
 119 
 120             public void run() {
 121                 try {
 122                     Application obj = (Application) cl.newInstance();
 123                     ParametersImpl.registerParameters(obj, new ParametersImpl(args));
 124                     obj.start(remoteStage);
 125                 } catch (Exception ex) {
 126                     ex.printStackTrace();
 127                 }
 128             }
 129         });
 130     }
 131 
 132     private static void defaultLaunch(final Class<? extends Application> cl, final String[] args) {
 133         final boolean waitToolkit = args != null ? java.util.Arrays.asList(args).contains(WAIT_TOOLKIT_START_ONLY) : false;
 134 
 135         new Thread(new Runnable() {
 136 
 137             public void run() {
 138                 Application.launch(cl, args);
 139             }
 140         }, "FXSQE app launch thread").start();
 141 
 142         new Waiter(new Timeout("FXSQE launch start waiter", TestUtil.isEmbedded() ? 600000 : 10000)).ensureState(new State<Boolean>() {
 143 
 144             public Boolean reached() {
 145 //                try {
 146 //                    Thread.sleep(100); // otherwise mac doesn't start
 147 //                } catch (InterruptedException ex) {
 148 //                }
 149                 if (waitToolkit) {
 150                     try {
 151                         final Toolkit toolkit = com.sun.javafx.tk.Toolkit.getToolkit();
 152                     } catch (Throwable ex) {
 153                         return null;
 154                     }
 155                     return Boolean.TRUE;
 156                 } else {
 157                     Iterator<Window> it = Stage.impl_getWindows();
 158                     while (it.hasNext()) {
 159 
 160                         if (it.next().isShowing()) {
 161                             return Boolean.TRUE;
 162                         }
 163                     }
 164                 }
 165 
 166                 // following wait method was changed due to problem on Mac+JDK7:
 167                 // we can't use AWT (and consequently Jemmy based on ATW Robot) before FX scene is shown
 168                 // otherwise FX hangs.
 169                 // Root.ROOT.lookup(new ByWindowType(Stage.class)).lookup(Scene.class).wrap(0).getControl();
 170                 return null;
 171             }
 172         });
 173     // more JDK7+Mac tricks
 174     // System.setProperty("java.awt.headless","false");
 175     // java.awt.GraphicsEnvironment.isHeadless();
 176     }
 177 
 178     /**
 179      * Setup stage to be used by launcher. E.g. stage provided by plugin
 180      * launcher
 181      *
 182      * @param remoteStage
 183      */
 184     public void setRemoteStage(Stage remoteStage) {
 185         if (remoteStage == null) {
 186             throw new IllegalArgumentException("Stage can't null");
 187         }
 188         if (this.remoteStage != null) {
 189             throw new IllegalStateException("Current implementation allows only one remote stage per VM");
 190         }
 191         mode = Mode.REMOTE;
 192         this.remoteStage = remoteStage;
 193     }
 194     private Stage remoteStage = null;
 195 }