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