1 /*
   2  * Copyright (c) 2012, 2014, 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  * questions.
  24  */
  25 
  26 package com.sun.javafx.application;
  27 
  28 import java.util.concurrent.CountDownLatch;
  29 import java.util.concurrent.TimeUnit;
  30 import java.util.concurrent.atomic.AtomicBoolean;
  31 import javafx.application.Platform;
  32 import javafx.scene.Group;
  33 import javafx.scene.Scene;
  34 import javafx.scene.paint.Color;
  35 import javafx.stage.Stage;
  36 import junit.framework.AssertionFailedError;
  37 import util.Util;
  38 
  39 import static org.junit.Assert.*;
  40 import static util.Util.TIMEOUT;
  41 
  42 /**
  43  * Test program for Platform finishListener
  44  * Each of the tests must be run in a separate JVM which is why each
  45  * is in its own subclass.
  46  */
  47 public class ListenerTestCommon {
  48 
  49     // Short delay in milliseconds
  50     private static final int DELAY = 10;
  51 
  52     // Sleep time showing/hiding window in milliseconds
  53     private static final int SLEEP_TIME = 1000;
  54 
  55     // Used to launch the platform before running any test
  56     private final CountDownLatch launchLatch = new CountDownLatch(1);
  57 
  58     // Used to determine when the toolkit is shutdown
  59     private CountDownLatch exitLatch;
  60 
  61     // Finish listener used by the various tests
  62     private PlatformImpl.FinishListener listener = null;
  63 
  64     private final CountDownLatch idleNotification = new CountDownLatch(1);
  65     private final CountDownLatch exitNotification = new CountDownLatch(1);
  66     private final AtomicBoolean implicitExit = new AtomicBoolean();
  67 
  68     private Stage stage;
  69 
  70     public enum ThrowableType {
  71         NONE,
  72         EXCEPTION,
  73         ERROR
  74     }
  75 
  76     private void setup() {
  77         // Start the FX Platform
  78         new Thread(() -> PlatformImpl.startup(() -> {
  79             assertTrue(Platform.isFxApplicationThread());
  80             launchLatch.countDown();
  81         })).start();
  82 
  83         try {
  84             if (!launchLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
  85                 throw new AssertionFailedError("Timeout waiting for Platform to start");
  86             }
  87         } catch (InterruptedException ex) {
  88             AssertionFailedError err = new AssertionFailedError("Unexpected exception");
  89             err.initCause(ex);
  90             throw err;
  91         }
  92         exitLatch = PlatformImpl.test_getPlatformExitLatch();
  93         assertEquals(1, exitLatch.getCount());
  94         assertEquals(0, launchLatch.getCount());
  95         assertEquals(1, exitLatch.getCount());
  96         assertNull(listener);
  97 
  98         listener = new PlatformImpl.FinishListener() {
  99             public void idle(boolean flag) {
 100                 implicitExit.set(flag);
 101                 idleNotification.countDown();
 102             }
 103             public void exitCalled() {
 104                 exitNotification.countDown();
 105             }
 106         };
 107         PlatformImpl.addListener(listener);
 108     }
 109 
 110     private Stage makeStage() {
 111         Stage stg = new Stage();
 112         stg.setTitle("Primary stage");
 113         Group root = new Group();
 114         Scene scene = new Scene(root);
 115         scene.setFill(Color.LIGHTYELLOW);
 116         stg.setScene(scene);
 117         stg.setX(0);
 118         stg.setY(0);
 119         stg.setWidth(210);
 120         stg.setHeight(180);
 121         return stg;
 122     }
 123 
 124     // ========================== TEST CASES ==========================
 125 
 126     public void doTestExit() {
 127         setup();
 128         assertNotNull(listener);
 129 
 130         Util.runAndWait(() -> {
 131             assertTrue(Platform.isFxApplicationThread());
 132             assertTrue(Platform.isImplicitExit());
 133         });
 134 
 135         Util.sleep(DELAY);
 136         assertEquals(1, exitNotification.getCount());
 137         assertEquals(1, idleNotification.getCount());
 138 
 139         Platform.exit();
 140         try {
 141             if (!exitNotification.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
 142                 throw new AssertionFailedError("Timeout waiting for exit notification");
 143             }
 144         } catch (InterruptedException ex) {
 145             AssertionFailedError err = new AssertionFailedError("Unexpected exception");
 146             err.initCause(ex);
 147             throw err;
 148         }
 149         assertEquals(0, exitNotification.getCount());
 150 
 151         Util.sleep(DELAY);
 152         assertEquals(1, idleNotification.getCount());
 153         assertEquals(1, exitLatch.getCount());
 154 
 155         PlatformImpl.removeListener(listener);
 156         listener = null;
 157     }
 158 
 159     public void doTestIdleImplicit(final boolean implicit,
 160             final ThrowableType throwableType) {
 161 
 162         setup();
 163         assertNotNull(listener);
 164 
 165         Util.runAndWait(() -> {
 166             assertTrue(Platform.isFxApplicationThread());
 167             assertTrue(Platform.isImplicitExit());
 168             if (!implicit) {
 169                 Platform.setImplicitExit(false);
 170             }
 171             PlatformImpl.addListener(listener);
 172         });
 173 
 174         Util.sleep(DELAY);
 175         assertEquals(1, exitNotification.getCount());
 176         assertEquals(1, idleNotification.getCount());
 177 
 178         Util.runAndWait(() -> {
 179             stage = makeStage();
 180             stage.show();
 181         });
 182 
 183         Util.sleep(SLEEP_TIME);
 184         assertEquals(1, exitNotification.getCount());
 185         assertEquals(1, idleNotification.getCount());
 186 
 187         final CountDownLatch rDone = new CountDownLatch(1);
 188         Platform.runLater(() -> {
 189             try {
 190                 if (throwableType == ThrowableType.EXCEPTION) {
 191                     throw new RuntimeException("this exception is expected");
 192                 } else if (throwableType == ThrowableType.ERROR) {
 193                     throw new InternalError("this error is expected");
 194                 }
 195             } finally {
 196                 rDone.countDown();
 197             }
 198         });
 199 
 200         try {
 201             if (!rDone.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
 202                 throw new AssertionFailedError("Timeout waiting for runLater, throwableType = "
 203                         + throwableType);
 204             }
 205         } catch (InterruptedException ex) {
 206             throw new AssertionFailedError("Unexpected exception waiting for runLater, throwableType = "
 207                         + throwableType);
 208         }
 209 
 210         Util.runAndWait(stage::hide);
 211 
 212         try {
 213             if (!idleNotification.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
 214                 throw new AssertionFailedError("Timeout waiting for exit notification");
 215             }
 216         } catch (InterruptedException ex) {
 217             AssertionFailedError err = new AssertionFailedError("Unexpected exception");
 218             err.initCause(ex);
 219             throw err;
 220         }
 221         assertEquals(0, idleNotification.getCount());
 222         assertEquals(implicit, implicitExit.get());
 223 
 224         Util.sleep(DELAY);
 225         assertEquals(1, exitNotification.getCount());
 226         assertEquals(1, exitLatch.getCount());
 227 
 228         PlatformImpl.removeListener(listener);
 229         listener = null;
 230     }
 231 
 232 }