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