As an experiment I'm trying out some tests in integrating JavaFX with JavaServer Faces 2.2. I'm using Eclipse Mars.2 Release 4.5.2 with Java 1.8, which includes JavaFX 8, and the Glassfish 4.1.1 server on a Windows 10 computer. The idea is to see if it's possible to get a JSF application running on a server and invoke some JavaFX GUIs, with the eventual aim of being able to display 3D graphics on the client.
However, I've run into some problems, so show here a very simple example. The xhtml code is just:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Test of JavaFX with JSF</title>
</h:head>
<h:body>
<h1>Test of JavaFX with JSF</h1>
<h:form id="myForm" prependId="false">
<h:commandButton value="Launch JavaFX Application" actionListener="#{myBean.launchApp}" />
<br />
<h:commandButton value="Stop JavaFX Application" actionListener="#{myBean.stopApp}" />
</h:form>
</h:body>
</html>
which simply displays two buttons in the browser's window on localhost:8080/Test
, one to launch the JavaFX application, and one which will eventually be used to close the application.
The code for the bean is:
package shape3dfxjsf;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@SessionScoped
@ManagedBean(name="myBean")
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private static boolean launched = false;
public static void launchApp() {
if (launched) return;
launched = true;
TestJavaFX.main(null);
}
public static void stopApp() {
launched = false;
}
}
and the code for the JavaFX application with all the graphics stripped out and just the screen is:
package shape3dfxjsf;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TestJavaFX extends Application {
@Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
The main()
method in the last listing for the class TestJavaFX is called by the class MyBean when JSF is used on the server, and it can also be called directly when run as a Java application, which is a useful test.
When Glassfish is started up and a browser window is opened, I click on the "Launch JavaFX Application" button and the launchApp()
method in MyBean is invoked. As the launched flag is initially false, the main()
method in TestJavaFX is called, and indeed a JavaFX window appears on my screen exactly as if I had invoked the main()
method directly from TestJavaFX, so this works correctly.
As the launched flag is now true, clicking again on the launch button has no effect (the button can be disabled in a later version of the code). After closing the JavaFX window, the launched flag is still true, so the the "Stop JavaFX Application" button has to be clicked to make it false again to re-enable the "Launch JavaFX Application". This minor issue of manually setting the flag back to false can easily be automated.
However, the main problem is that I cannot restart the JavaFX application, even though it has apparently closed. If I click the "Launch JavaFX Application" after it is re-enabled and after the JavaFX application is closed, I keep getting the error:
java.lang.IllegalStateException: Application launch must not be called more than once
I've read up on this and looked at other postings. The issue is that as far as I know JavaFX has closed down, so I don't understand why I'm getting this error. Trying Platform.exit()
in the JavaTestFX class doesn't work, and invoking System.exit(0)
just kills everything.
How do I restart JavaFX when calling it from a JSF bean without closing everything and starting again? There must be someone who has tried this out, and I would most appreciate some ideas on fixing this problem.