1 /*
   2  * Copyright (c) 2010, 2017, 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 javafx.application;
  27 
  28 import java.lang.reflect.Module;
  29 import java.security.AccessController;
  30 import java.security.PrivilegedAction;
  31 import java.util.List;
  32 import java.util.Map;
  33 
  34 import javafx.application.Preloader.PreloaderNotification;
  35 import javafx.scene.Scene;
  36 import javafx.stage.Stage;
  37 
  38 import com.sun.javafx.application.LauncherImpl;
  39 import com.sun.javafx.application.ParametersImpl;
  40 import com.sun.javafx.application.PlatformImpl;
  41 import com.sun.javafx.css.StyleManager;
  42 
  43 /**
  44  * Application class from which JavaFX applications extend.
  45  *
  46  * <p><b>Life-cycle</b></p>
  47  * <p>
  48  * The entry point for JavaFX applications is the Application class. The
  49  * JavaFX runtime does the following, in order, whenever an application is
  50  * launched:
  51  * </p>
  52  * <ol>
  53  * <li>Constructs an instance of the specified Application class</li>
  54  * <li>Calls the {@link #init} method</li>
  55  * <li>Calls the {@link #start} method</li>
  56  * <li>Waits for the application to finish, which happens when either of
  57  * the following occur:
  58  * <ul>
  59  * <li>the application calls {@link Platform#exit}</li>
  60  * <li>the last window has been closed and the {@code implicitExit}
  61  * attribute on {@code Platform} is true</li>
  62  * </ul></li>
  63  * <li>Calls the {@link #stop} method</li>
  64  * </ol>
  65  * <p>Note that the {@code start} method is abstract and must be overridden.
  66  * The {@code init} and {@code stop} methods have concrete implementations
  67  * that do nothing.</p>
  68  * <p>The {@code Application} subclass must be declared public, and the
  69  * containing package must be {@link Module#isExported(String,Module) exported}
  70  * to the {@code javafx.graphics} module.</p>
  71  *
  72  * <p>Calling {@link Platform#exit} is the preferred way to explicitly terminate
  73  * a JavaFX Application. Directly calling {@link System#exit} is
  74  * an acceptable alternative, but doesn't allow the Application {@link #stop}
  75  * method to run.
  76  * </p>
  77  *
  78  * <p>A JavaFX Application should not attempt to use JavaFX after the
  79  * FX toolkit has terminated or from a ShutdownHook, that is, after the
  80  * {@link #stop} method returns or {@link System#exit} is called.
  81  * </p>
  82  *
  83  * <p><b>Parameters</b></p>
  84  * <p>
  85  * Application parameters are available by calling the {@link #getParameters}
  86  * method from the {@link #init} method, or any time after the {@code init}
  87  * method has been called.
  88  * </p>
  89  *
  90  * <p><b>Threading</b></p>
  91  * <p>
  92  * JavaFX creates an application thread for running the application start
  93  * method, processing input events, and running animation timelines. Creation
  94  * of JavaFX {@link Scene} and {@link Stage} objects as well as modification of
  95  * scene graph operations to <em>live</em> objects (those objects already
  96  * attached to a scene) must be done on the JavaFX application thread.
  97  * </p>
  98  *
  99  * <p>
 100  * The Java launcher loads and initializes the specified Application class
 101  * on the JavaFX Application Thread. If there is no main method in the
 102  * Application class, or if the main method calls Application.launch(), then
 103  * an instance of the Application is then constructed on the JavaFX Application
 104  * Thread.
 105  * </p>
 106  *
 107  * <p>
 108  * The {@code init} method is called on the launcher thread, not on the
 109  * JavaFX Application Thread.
 110  * This means that an application must not construct a {@link Scene}
 111  * or a {@link Stage} in the {@code init} method.
 112  * An application may construct other JavaFX objects in the {@code init}
 113  * method.
 114  * </p>
 115  *
 116  * <p>
 117  * All the unhandled exceptions on the JavaFX application thread that occur during
 118  * event dispatching, running animation timelines, or any other code, are forwarded
 119  * to the thread's {@link java.lang.Thread.UncaughtExceptionHandler uncaught
 120  * exception handler}.
 121  * </p>
 122  *
 123  * <p><b>Example</b></p>
 124  * <p>The following example will illustrate a simple JavaFX application.</p>
 125  * <pre><code>
 126 import javafx.application.Application;
 127 import javafx.scene.Group;
 128 import javafx.scene.Scene;
 129 import javafx.scene.shape.Circle;
 130 import javafx.stage.Stage;
 131 
 132 public class MyApp extends Application {
 133     public void start(Stage stage) {
 134         Circle circ = new Circle(40, 40, 30);
 135         Group root = new Group(circ);
 136         Scene scene = new Scene(root, 400, 300);
 137 
 138         stage.setTitle("My JavaFX Application");
 139         stage.setScene(scene);
 140         stage.show();
 141     }
 142 }
 143  * </code></pre>
 144  *
 145  * <p>The above example will produce the following:</p>
 146  * <p><img src="doc-files/Application.png"/></p>
 147  * @since JavaFX 2.0
 148  */
 149 public abstract class Application {
 150     /**
 151      * Constant for user agent stylesheet for the "Caspian" theme. Caspian
 152      * is the theme that shipped as default in JavaFX 2.x.
 153      * @since JavaFX 8.0
 154      */
 155     public static final String STYLESHEET_CASPIAN = "CASPIAN";
 156     /**
 157      * Constant for user agent stylesheet for the "Modena" theme. Modena
 158      * is the default theme for JavaFX 8.x.
 159      * @since JavaFX 8.0
 160      */
 161     public static final String STYLESHEET_MODENA = "MODENA";
 162 
 163     /**
 164      * Launch a standalone application. This method is typically called
 165      * from the main method(). It must not be called more than once or an
 166      * exception will be thrown.
 167      *
 168      * <p>
 169      * The launch method does not return until the application has exited,
 170      * either via a call to Platform.exit or all of the application windows
 171      * have been closed.
 172      *
 173      * <p>
 174      * Typical usage is:
 175      * <ul>
 176      * <pre>
 177      * public static void main(String[] args) {
 178      *     Application.launch(MyApp.class, args);
 179      * }
 180      * </pre>
 181      * </ul>
 182      * where <code>MyApp</code> is a subclass of Application.
 183      *
 184      * @param appClass the application class that is constructed and executed
 185      *        by the launcher.
 186      * @param args the command line arguments passed to the application.
 187      *             An application may get these parameters using the
 188      *             {@link #getParameters()} method.
 189      *
 190      * @throws IllegalStateException if this method is called more than once.
 191      * @throws IllegalArgumentException if <code>appClass</code> is not a
 192      *         subclass of <code>Application</code>.
 193      * @throws RuntimeException if there is an error launching the
 194      * JavaFX runtime, or if the application class cannot be constructed
 195      * (e.g., if the class is not public or is not in an exported package), or
 196      * if an Exception or Error is thrown by the Application constructor, init
 197      * method, start method, or stop method.
 198      */
 199     public static void launch(Class<? extends Application> appClass, String... args) {
 200         LauncherImpl.launchApplication(appClass, args);
 201     }
 202 
 203     /**
 204      * Launch a standalone application. This method is typically called
 205      * from the main method(). It must not be called more than once or an
 206      * exception will be thrown.
 207      * This is equivalent to launch(TheClass.class, args) where TheClass is the
 208      * immediately enclosing class of the method that called launch. It must
 209      * be a subclass of Application or a RuntimeException will be thrown.
 210      *
 211      * <p>
 212      * The launch method does not return until the application has exited,
 213      * either via a call to Platform.exit or all of the application windows
 214      * have been closed.
 215      *
 216      * <p>
 217      * Typical usage is:
 218      * <ul>
 219      * <pre>
 220      * public static void main(String[] args) {
 221      *     Application.launch(args);
 222      * }
 223      * </pre>
 224      * </ul>
 225      *
 226      * @param args the command line arguments passed to the application.
 227      *             An application may get these parameters using the
 228      *             {@link #getParameters()} method.
 229      *
 230      * @throws IllegalStateException if this method is called more than once.
 231      * @throws RuntimeException if there is an error launching the
 232      * JavaFX runtime, or if the application class cannot be constructed
 233      * (e.g., if the class is not public or is not in an exported package), or
 234      * if an Exception or Error is thrown by the Application constructor, init
 235      * method, start method, or stop method.
 236      */
 237     public static void launch(String... args) {
 238         // Figure out the right class to call
 239         StackTraceElement[] cause = Thread.currentThread().getStackTrace();
 240 
 241         boolean foundThisMethod = false;
 242         String callingClassName = null;
 243         for (StackTraceElement se : cause) {
 244             // Skip entries until we get to the entry for this class
 245             String className = se.getClassName();
 246             String methodName = se.getMethodName();
 247             if (foundThisMethod) {
 248                 callingClassName = className;
 249                 break;
 250             } else if (Application.class.getName().equals(className)
 251                     && "launch".equals(methodName)) {
 252 
 253                 foundThisMethod = true;
 254             }
 255         }
 256 
 257         if (callingClassName == null) {
 258             throw new RuntimeException("Error: unable to determine Application class");
 259         }
 260 
 261         try {
 262             Class theClass = Class.forName(callingClassName, false,
 263                                Thread.currentThread().getContextClassLoader());
 264             if (Application.class.isAssignableFrom(theClass)) {
 265                 Class<? extends Application> appClass = theClass;
 266                 LauncherImpl.launchApplication(appClass, args);
 267             } else {
 268                 throw new RuntimeException("Error: " + theClass
 269                         + " is not a subclass of javafx.application.Application");
 270             }
 271         } catch (RuntimeException ex) {
 272             throw ex;
 273         } catch (Exception ex) {
 274             throw new RuntimeException(ex);
 275         }
 276     }
 277 
 278     /**
 279      * Constructs a new {@code Application} instance.
 280      */
 281     public Application() {
 282     }
 283 
 284     /**
 285      * The application initialization method. This method is called immediately
 286      * after the Application class is loaded and constructed. An application may
 287      * override this method to perform initialization prior to the actual starting
 288      * of the application.
 289      *
 290      * <p>
 291      * The implementation of this method provided by the Application class does nothing.
 292      * </p>
 293      *
 294      * <p>
 295      * NOTE: This method is not called on the JavaFX Application Thread. An
 296      * application must not construct a Scene or a Stage in this
 297      * method.
 298      * An application may construct other JavaFX objects in this method.
 299      * </p>
 300      */
 301     public void init() throws Exception {
 302     }
 303 
 304     /**
 305      * The main entry point for all JavaFX applications.
 306      * The start method is called after the init method has returned,
 307      * and after the system is ready for the application to begin running.
 308      *
 309      * <p>
 310      * NOTE: This method is called on the JavaFX Application Thread.
 311      * </p>
 312      *
 313      * @param primaryStage the primary stage for this application, onto which
 314      * the application scene can be set. The primary stage will be embedded in
 315      * the browser if the application was launched as an applet.
 316      * Applications may create other stages, if needed, but they will not be
 317      * primary stages and will not be embedded in the browser.
 318      */
 319     public abstract void start(Stage primaryStage) throws Exception;
 320 
 321     /**
 322      * This method is called when the application should stop, and provides a
 323      * convenient place to prepare for application exit and destroy resources.
 324      *
 325      * <p>
 326      * The implementation of this method provided by the Application class does nothing.
 327      * </p>
 328      *
 329      * <p>
 330      * NOTE: This method is called on the JavaFX Application Thread.
 331      * </p>
 332      */
 333     public void stop() throws Exception {
 334     }
 335 
 336     private HostServices hostServices = null;
 337 
 338     /**
 339      * Gets the HostServices provider for this application. This provides
 340      * the ability to get the code base and document base for this application,
 341      * and to access the enclosing web page.
 342      *
 343      * @return the HostServices provider
 344      */
 345     public final HostServices getHostServices() {
 346         synchronized (this) {
 347             if (hostServices == null) {
 348                 hostServices = new HostServices(this);
 349             }
 350             return hostServices;
 351         }
 352     }
 353 
 354     /**
 355      * Retrieves the parameters for this Application, including any arguments
 356      * passed on the command line and any parameters specified in a JNLP file
 357      * for an applet or WebStart application.
 358      *
 359      * <p>
 360      * NOTE: this method should not be called from the Application constructor,
 361      * as it will return null. It may be called in the init() method or any
 362      * time after that.
 363      * </p>
 364      *
 365      * @return the parameters for this Application, or null if called from the
 366      * constructor.
 367      */
 368     public final Parameters getParameters() {
 369         return ParametersImpl.getParameters(this);
 370     }
 371 
 372     /**
 373      * Notifies the preloader with an application-generated notification.
 374      * Application code calls this method with a PreloaderNotification that is
 375      * delivered to the
 376      * {@link Preloader#handleApplicationNotification
 377      * Preloader.handleApplicationNotification} method.
 378      * This is primarily useful for cases where an application wants the
 379      * preloader to show progress during a long application initialization
 380      * step.
 381      *
 382      * <p>
 383      * NOTE: the notification will be delivered only to the preloader's
 384      * handleApplicationNotification() method; this means, for example, that
 385      * if this method is called with a ProgressNotification, that notification
 386      * will not be delivered to the {@link Preloader#handleProgressNotification
 387      * Preloader.handleProgressNotification}
 388      * method.
 389      * </p>
 390      *
 391      * @param info the application-generated preloader notification
 392      */
 393     public final void notifyPreloader(PreloaderNotification info) {
 394         LauncherImpl.notifyPreloader(this, info);
 395     }
 396 
 397     /**
 398      * Encapsulates the set of parameters for an application. This includes
 399      * arguments passed on the command line, unnamed parameters specified
 400      * in a JNLP file, and &lt;name,value&gt; pairs specified in a JNLP file.
 401      *
 402      * <p>
 403      * Note that the application and the preloader both get the same set
 404      * of parameters for a given run of an application.
 405      * </p>
 406      * @since JavaFX 2.0
 407      */
 408     public static abstract class Parameters {
 409 
 410         /**
 411          * Constructs a new {@code Parameters} instance.
 412          */
 413         public Parameters() {
 414         }
 415 
 416         /**
 417          * Retrieves a read-only list of the raw arguments. This list
 418          * may be empty, but is never null. In the case of a standalone
 419          * application, it is the ordered list of arguments specified on the
 420          * command line. In the case of an applet or WebStart application,
 421          * it includes unnamed parameters as well as named parameters. For
 422          * named parameters, each &lt;name,value&gt; pair is represented as
 423          * a single argument of the form: "--name=value".
 424          *
 425          * @return a read-only list of raw application arguments
 426          */
 427         public abstract List<String> getRaw();
 428 
 429         /**
 430          * Retrieves a read-only list of the unnamed parameters. This list
 431          * may be empty, but is never null. The named parameters, that is
 432          * the parameters that are represented as &lt;name,value&gt; pairs, are
 433          * filtered out.
 434          *
 435          * @return a read-only list of unnamed parameters.
 436          */
 437         public abstract List<String> getUnnamed();
 438 
 439         /**
 440          * Retrieves a read-only map of the named parameters. It may be
 441          * empty, but is never null.
 442          * Named parameters include those &lt;name,value&gt; pairs explicitly
 443          * specified in a JNLP file. It also includes any command line
 444          * arguments of the form: "--name=value".
 445          *
 446          * @return a read-only map of named parameters.
 447          */
 448         public abstract Map<String, String> getNamed();
 449 
 450     }
 451 
 452     private static String userAgentStylesheet = null;
 453 
 454     /**
 455      * Get the user agent stylesheet used by the whole application. This is
 456      * used to provide default styling for all ui controls and other nodes.
 457      * A value of null means the platform default stylesheet is being used.
 458      * <p>
 459      * NOTE: This method must be called on the JavaFX Application Thread.
 460      * </p>
 461      *
 462      * @return The URL to the stylesheet as a String.
 463      * @since JavaFX 8.0
 464      */
 465     public static String getUserAgentStylesheet() {
 466         return userAgentStylesheet;
 467     }
 468 
 469     /**
 470      * Set the user agent stylesheet used by the whole application. This is used
 471      * to provide default styling for all ui controls and other nodes. Each
 472      * release of JavaFX may have a new default value for this so if you need
 473      * to guarantee consistency you will need to call this method and choose
 474      * what default you would like for your application. A value of null will
 475      * restore the platform default stylesheet. This property can also be set
 476      * on the command line with {@code -Djavafx.userAgentStylesheetUrl=[URL]}
 477      * Setting it on the command line overrides anything set using this method
 478      * in code.
 479      * <p>
 480      * NOTE: This method must be called on the JavaFX Application Thread.
 481      * </p>
 482      *
 483      *
 484      * @param url The URL to the stylesheet as a String.
 485      * @since JavaFX 8.0
 486      */
 487     public static void setUserAgentStylesheet(String url) {
 488         userAgentStylesheet = url;
 489         if (url == null) {
 490             PlatformImpl.setDefaultPlatformUserAgentStylesheet();
 491         } else {
 492             PlatformImpl.setPlatformUserAgentStylesheet(url);
 493         }
 494     }
 495 }