In JavaFX using JxBrowser invokeAndWaitFinishLoadingMainFrame() method crashes JVM - javafx

I'm experimenting with the JXBrowser Chromium browser engine in JavaFX on Mac OS Sierra. I would like to wait until the URL is fully loaded after I call browser.goBack() or browser.goForward() methods so I can check the Navigation History. The simple app below crashes the JVM but the same code works fine in Java (Swing). The same call in a Java swing app works without any issues. Does anyone have any idea why?
public class JavaFXSample extends Application {
#Override
public void init() throws Exception {
// On Mac OS X Chromium engine must be initialized in non-UI thread.
if (Environment.isMac()) {
BrowserCore.initialize();
}
}
#Override
public void start(final Stage primaryStage) {
Browser browser = new Browser();
BrowserView view = new BrowserView(browser);
Scene scene = new Scene(new BorderPane(view), 700, 500);
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
Platform.exit();
System.exit(0);
}
});
Browser.invokeAndWaitFinishLoadingMainFrame(browser, new Callback<Browser>
() {
#Override
public void invoke(Browser browser) {
browser.loadURL("http://www.google.com");
}
});
}
public static void main(String[] args) {
launch(args);
}
}

Looks like you've faced a deadlock because you create the Browser instance in heavyweight mode. You can try solving this issue by using the "jxbrowser.ipc.external=true" VM parameter that enables lightweight rendering mode and runs Chromium engine in separate native process to avoid deadlocks in UI thread.

Related

Is it possible to launch a JavaFX application through another JavaFX application?

Can I know why there is an error when I say.
Stage s = new Stage();
new CaeserCipherFX().start(s);
This is my code below. I need to launch another JavaFX Application from this one. Please help. Thank you.
public class Main extends Application
{
String args[];
#Override
public void start(Stage stage) throws Exception
{
// creating types of encryptions (Button)
Button caeserCipher = new Button("1. Caeser Cipher");
Button runningKeyCipher = new Button("2. Running Key Cipher");
Button trithemiusCipher = new Button("3. Trithemius Cipher");
Button vignereCipher = new Button("4. Vignere Cipher");
//setting styles
caeserCipher.setTextFill(Color.BLUE);
runningKeyCipher.setTextFill(Color.BLUE);
trithemiusCipher.setTextFill(Color.BLUE);
vignereCipher.setTextFill(Color.BLUE);
/*need to add more!*/
//setting action listeners
String arr [] = {"CaeserCipher","RunningKeyCipher","TrithemiusCipher","VignereCipher"};
caeserCipher.setOnAction((ActionEvent event)->{
//open caeser cipher
Stage s = new Stage();
new CaeserCipherFX().start(s);
});
runningKeyCipher.setOnAction((ActionEvent event)->{
//open running key cipher
stage.hide();
});
trithemiusCipher.setOnAction((ActionEvent event)->{
//open trithemius cipher
stage.hide();
});
vignereCipher.setOnAction((ActionEvent event)->{
//open vignere cipher
stage.hide();
});
// creating flowpane(FlowPane)
FlowPane menu = new FlowPane();
menu.setHgap(25);
menu.setVgap(25);
menu.setMargin(caeserCipher, new Insets(20, 0, 20, 20));
//list for Flowpane(ObservableList)
ObservableList list = menu.getChildren();
//adding list to flowpane
list.addAll(caeserCipher,runningKeyCipher,trithemiusCipher,vignereCipher);
//scene for stage
Scene scene = new Scene(menu);
stage.setTitle("Main Menu");
stage.setScene(scene);
// stage.initStyle(StageStyle.UTILITY);
stage.setHeight(100);
stage.setWidth(600);
stage.setResizable(false);
// Show the Stage (window)
stage.show();
}
}
And I want to launch the code below:
public class CaeserCipherFX extends Application
{
#Override
public void start(Stage stage) throws Exception
{//some other code
//some other code
}
}
There is a ubiquitous JavaFX main application thread which takes a while to get used to.
Think of it like the front-end thread. Theoretically, you should use that thread to handle UI updates and complex cpu tasks such as looking up something in a BD or figuring out the 100000th decimal of PI should be done in a background thread. If you don't do this, the UI will become unresponsive until the DB data is returned, or that decimal is found.
public class TestClass extends Application {
public static void main(String[] args) {
System.out.println("here");
Application.launch(TestClass.class, args);
System.out.println("this is called once application launch is terminated.");
}
#Override
public void init() throws Exception {
super.init(); //To change body of generated methods, choose Tools | Templates.
System.out.println("message from init");
}
#Override
public void start(Stage primaryStage) throws Exception { // this is abstract.
System.out.println("message from start");
Platform.exit(); // if you remove this line, the application won't exit.
}
}
Since JavaFX comes with some prerequisites, you need to start you rapplication using a front-end. You can work around this, but technically,
public void start(Stage primaryStage)
is what , for all intensive purposes, starts your program.
From here, you can use the primaryStage to control most of your application. It's a good idea to put a .onCloseRequest() on it in which you call Platform.exit();
If you want to have multiple windows in your application, you could use something like
public class TestClass extends Application {
public static void main(String[] args) {
System.out.println("here");
Application.launch(TestClass.class, args);
System.out.println("this is called once application launch is terminated.");
}
#Override
public void init() throws Exception {
super.init(); //To change body of generated methods, choose Tools | Templates.
System.out.println("message from init");
}
#Override
public void start(Stage primaryStage) throws Exception { // this is abstract.
primaryStage.setScene(new Scene(new TextArea("this is the first stage (window)")));
primaryStage.setTitle("stage 1");
primaryStage.show();
primaryStage.setOnCloseRequest((event) -> {
Platform.exit();
});
Stage secondaryStage = new Stage();
secondaryStage.setTitle("stage 2");
TextArea ta2 = new TextArea("this is a different stage.");
Scene scene = new Scene(ta2);
secondaryStage.setScene(scene);
secondaryStage.show();
primaryStage.setX(200);
secondaryStage.setX(200 + primaryStage.getWidth() + 50);
}
}
This is what I assume you want to do. Basically create a new window whenever you press a button. You can create stages like this.
The reason for which you can't do it your way is because you are attempting to start another javafx thread by invoking new CaeserCipherFX which is an application object, not a Stage.
new CaeserCipherFX().start(s); // this can only be called once.
IF you absolutely want to have 2 distinct applications (note: not application windows), then you need to have 2 distinct processes.
Lastly, the primaryStage parameter used in either examples is in the beginning basically a placeholder (as in it's constructed, but there's nothing really in it... like a new String()). You can use different stage objects as your "primary" UI.
Lastly, if depending on the stuff you want to decrypt, you may need to use background threads if you want to keep the UI responsiveness. For this you will need to check out the concurrency part of the javafx tutorial.
Is it possible to launch a JavaFX application through another JavaFX application? Not really.
Alternatively, you can use java.lang.ProcessBuilder
This class essentially sends command lines to your operating system shell.
You can use it to run something like "java -jar XXX\YYY\CaeserCipherFX.jar" whenever you click a button. (you'll have to build a CaeserCypherFX project into a jar file)
This will create a new JVM. This means no memory state sharing. You can handle this through IPC.

javafx programmatically set arguments for virtual keyboard

I have a desktop application that will be used on computers with no keyboard, input will be on a touch screen. I can get the virtual keyboard to show up on textfields fine when running from eclipse. I used these arguments
-Dcom.sun.javafx.touch=true
-Dcom.sun.javafx.isEmbedded=true
-Dcom.sun.javafx.virtualKeyboard=none
The following link shows me where to add the arguments.
how to add command line parameters when running java code in Eclipse?
When I make a runnable jar file the keyboard does not show up. I am looking for a way to set these arguments programmatically so that the runnable jar file will display the virtual keyboard on any computer. Any help will be greatly appreciated.
The only working solution I could find came from here
Gradle build for javafx application: Virtual Keyboard is not working due to missing System property
Create a wrapper class and set the system properties before invoking the applications original main method.
public class MainWrapper {
public static void main(String[] args) throws Exception
{ // application - package name
Class<?> app = Class.forName("application.Main");
Method main = app.getDeclaredMethod("main", String[].class);
System.setProperty("com.sun.javafx.isEmbedded", "true");
System.setProperty("com.sun.javafx.touch", "true");
System.setProperty("com.sun.javafx.virtualKeyboard", "javafx");
Object[] arguments = new Object[]{args};
main.invoke(null, arguments);
}
}
When making the runnable jar file just point to the MainWrapper class for the launch configuration.
The -D option to the JVM sets a system property. So you can achieve the same by doing the following:
public class MyApplication extends Application {
#Override
public void init() {
System.setProperty("com.sun.javafx.touch", "true");
System.setProperty("com.sun.javafx.isEmbedded", "true");
System.setProperty("com.sun.javafx.virtualKeyboard", "none");
}
#Override
public void start(Stage primaryStage) {
// ...
}
}

Play Youtube Video in JavaFX

Is there is any way to play Youtube videos on JavaFX Application? I was trying this-
public class YoutubeVideoPlayer extends Application
{
#Override
public void start(Stage stage) throws Exception
{
WebView webview = new WebView();
webview.getEngine().load("http://www.youtube.com/embed/_3op5hukpIE?autoplay=1");
webview.setPrefSize(640, 390);
stage.setScene(new Scene(webview));
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
I don't know how, but once it worked fine. But every time it is showing me an error message:
An error occured. Please try again later.
Can anyone explain how did it work and how can I make it work again?
This code is not working when I was running this on IDE(Eclipse, NetBeans or IntelliJ). But when I am Exporting this from Eclipse IDE as "Runnable JAR file", and running the Jar file, it's working perfectly. It seems, it's just not running on IDE.

How can a native Servlet Filter be used when using Spark web framework?

I'm playing around with Spark (the Java web framework, not Apache Spark).
I find it really nice and easy to define routes and filters, however I'm looking to apply a native servlet filter to my routes and can't seem to find a way to do that.
More specifically, I would like to use Jetty's DoSFilter which is a servlet filter (contrast with the Spark Filter definition). Since Spark is using embedded Jetty, I don't have a web.xml to register the DoSFilter. However, Spark doesn't expose the server instance so I can't find an elegant way of registering the filter programatically either.
Is there a way to apply a native servlet filter to my routes?
I thought of wrapping the DoSFilter in my own Spark Filter, but it seemed like a weird idea.
You can do it like this:
public class App {
private static Logger LOG = LoggerFactory.getLogger(App.class);
public static void main(String[] args) throws Exception {
ServletContextHandler mainHandler = new ServletContextHandler();
mainHandler.setContextPath("/base/path");
Stream.of(
new FilterHolder(new MyServletFilter()),
new FilterHolder(new SparkFilter()) {{
this.setInitParameter("applicationClass", SparkApp.class.getName());
}}
).forEach(h -> mainHandler.addFilter(h, "*", null));
GzipHandler compression = new GzipHandler();
compression.setIncludedMethods("GET");
compression.setMinGzipSize(512);
compression.setHandler(mainHandler);
Server server = new Server(new ExecutorThreadPool(new ThreadPoolExecutor(10,200,60000,TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(200),
new CustomizableThreadFactory("jetty-pool-"))));
final ServerConnector serverConnector = new ServerConnector(server);
serverConnector.setPort(9290);
server.setConnectors(new Connector[] { serverConnector });
server.setHandler(compression);
server.start();
hookToShutdownEvents(server);
server.join();
}
private static void hookToShutdownEvents(final Server server) {
LOG.debug("Hooking to JVM shutdown events");
server.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
#Override
public void lifeCycleStopped(LifeCycle event) {
LOG.info("Jetty Server has been stopped");
super.lifeCycleStopped(event);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
LOG.info("About to stop Jetty Server due to JVM shutdown");
try {
server.stop();
} catch (Exception e) {
LOG.error("Could not stop Jetty Server properly", e);
}
}
});
}
/**
* #implNote {#link SparkFilter} needs to access a public class
*/
#SuppressWarnings("WeakerAccess")
public static class SparkApp implements SparkApplication {
#Override
public void init() {
System.setProperty("spring.profiles.active", ApplicationProfile.readProfilesOrDefault("dev").stream().collect(Collectors.joining()));
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ModocContext.class);
ctx.registerShutdownHook();
}
}}

JavaFX UI hangs

I am writing a JavaFX program under ecilpse, It works well on my local machine i.e., I can execute the runable jar after I export. However, when I put the executable jar to another machine, the UI was not responding. Here are the codes I launch the javaFX program.
#Override
public void start(Stage primaryStage) {
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
Platform.exit();
System.exit(0);
}
});
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Server Simulator");
context = new ClassPathXmlApplicationContext("classpath:PrTrSim.xml");
this.displayQueue = (LinkedBlockingQueue<Message>) context.getBean("displayQueue");
this.userInputQueue = (LinkedBlockingQueue<Message>) context.getBean("userInputQueue");
this.outgoingQueue = (LinkedBlockingQueue<Message>) context.getBean("outgoingQueue");
this.incomingQueue = (LinkedBlockingQueue<Message>) context.getBean("incomingQueue");
addQueue.add(this.displayQueue);
addQueue.add(this.outgoingQueue);
addQueue.add(this.incomingQueue);
initRootLayout();
showSimOverview();
}
public static void main(String[] args) {
launch(args);
}
The PrTrSim.xml is for initialization of two components(messageProcessor and SocketIO reader) which are running behind.The 4 blocking queues are for message receiving and handling.
To avoid blocking of the main thread you should use the JavaFX concept of tasks or services as explained in details here: http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

Resources