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             // https://bugs.openjdk.java.net/browse/JDK-8131888
  59             case SWT:
  60                 instantiateOnSWTQueue(cl, args);
  61                 break;
  62             case REMOTE:
  63                 launchOnRemoteStage(cl, args);
  64                 break;
  65             default:
  66                 throw new IllegalStateException("Unknown launch mode: " + mode);
  67 
  68         }
  69     }
  70 
  71     public enum Mode {
  72 
  73         DEFAULT, SWING, SWT, REMOTE
  74     };
  75     private Mode mode = Mode.DEFAULT;
  76     private long testDelay = Long.getLong("test.javafx.testdelay", 1000);
  77     private long testDelayRemote = Long.getLong("test.javafx.testdelayremote", 4000);
  78 
  79     public long getTestDelay() {
  80         return mode == Mode.REMOTE ? testDelayRemote : testDelay;
  81     }
  82 
  83     public Mode getMode() {
  84         return mode;
  85     }
  86 
  87     private AppLauncher() {
  88         if (Boolean.getBoolean("javafx.swinginteroperability")) {
  89             mode = Mode.SWING;
  90         }
  91         if (Boolean.getBoolean("javafx.swtinteroperability")) {
  92             mode = Mode.SWT;
  93         }
  94     }
  95     private final static AppLauncher INSTANCE = new AppLauncher();
  96 
  97     public static AppLauncher getInstance() {
  98         return INSTANCE;
  99     }
 100 
 101     private static void instantiateOnSwingQueue(final Class<? extends Interoperability> cl, String[] args) {
 102         try {
 103             SwingAWTUtils.instantiateOnSwingQueue(cl);
 104         } catch (Exception ex) {
 105             ex.printStackTrace();
 106         }
 107     }
 108 
 109     // https://bugs.openjdk.java.net/browse/JDK-8131888
 110     private static void instantiateOnSWTQueue(final Class<? extends Interoperability> cl, String[] args) {
 111         try {
 112             Interoperability obj = cl.newInstance();
 113             obj.startSWT();
 114         } catch (Exception ex) {
 115             ex.printStackTrace();
 116         }
 117     }
 118 
 119     private void launchOnRemoteStage(final Class<? extends Application> cl, final String[] args) {
 120         Platform.runLater(new Runnable() {
 121 
 122             public void run() {
 123                 try {
 124                     Application obj = (Application) cl.newInstance();
 125                     ParametersImpl.registerParameters(obj, new ParametersImpl(args));
 126                     obj.start(remoteStage);
 127                 } catch (Exception ex) {
 128                     ex.printStackTrace();
 129                 }
 130             }
 131         });
 132     }
 133 
 134     private static void defaultLaunch(final Class<? extends Application> cl, final String[] args) {
 135         final boolean waitToolkit = args != null ? java.util.Arrays.asList(args).contains(WAIT_TOOLKIT_START_ONLY) : false;
 136         
 137         new Thread(new Runnable() {
 138 
 139             public void run() {
 140                 Application.launch(cl, args);
 141             }
 142         }, "FXSQE app launch thread").start();
 143 
 144         new Waiter(new Timeout("FXSQE launch start waiter", TestUtil.isEmbedded() ? 600000 : 10000)).ensureState(new State<Boolean>() {
 145 
 146             public Boolean reached() {
 147 //                try {
 148 //                    Thread.sleep(100); // otherwise mac doesn't start
 149 //                } catch (InterruptedException ex) {
 150 //                }
 151                 if (waitToolkit) {
 152                     try {
 153                         final Toolkit toolkit = com.sun.javafx.tk.Toolkit.getToolkit();
 154                     } catch (Throwable ex) {
 155                         return null;
 156                     }
 157                     return Boolean.TRUE;
 158                 } else {                    
 159                     for (Window w : Stage.getWindows()) {
 160                         if (w.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 }