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