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 <name,value> 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 <name,value> 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 <name,value> 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 <name,value> 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 }