How to terminate a scheduled thread when JavaFX Runtime exits? - java

I'm looking over similar examples to this problem. We have a JavaFX app which runs some GUI updates via thread running from: ScheduledExecutorService::scheduleAtFixedRate.
This is similar to a couple of other questions. The two I recognised as most like my situation are these:
JavaFX Task threads not terminating
how to stop "JavaFX Application Thread"
The question I need to resolve, however, is about the next step. My target is for an embedded application and there's no opportunity to manually kill the JVM-task, or the other easy answers, etc. I'm afraid a reboot is reserved for something critically-serious.
We need to ensure that all threads are closed off in an orderly way. What I'm looking for is some kind of call back or event that lets me register a clean-up routine to close-down my stuff?
I was thinking that there ought to be 'something' in the base class, JavaFX javafx.application.Application to do the deed.
http://docs.oracle.com/javafx/2/api/javafx/application/Application.html
Is the Stop method something I might use or can I register to be called when there is a stop from my FXMLController?
At present when I run my JavaFX app from Netbeans, the JVM process persists. This stops any further build scripts and locks the JAR file. Netbeans gives you an option to kill the task. The true solution means that the application/JVM closes-down orderly and neatly.
(update) ... I looked into the javafx.Application class that you use to launch the JavaFX app. I implemented a Stop() method. Here I make sure that I've called Platform.exit() ...
/////
// #see
// -- http://docs.oracle.com/javafx/2/api/javafx/application/Application.html#stop%28%29
//
public void stop()
{
Platform.exit();
}
This doesn't cure the problem when running from NetBeans. Sometimes you need to click the stop [X] button two times, but the process does stop when you use the kill button. If you are interested in progress this is reported as bug: [Bug 245284], there's a small clock example to demonstrate the problem. When you close the window, the NetBeans process running panel is still 'running'. You can't build because the JAR file is locked. At least we know to manually kill the development program.
Suggestions welcome . . .

I have a partial solution to cover fellow developers who get caught in this situation. Declare a stop() method in in your JavaFX app (called "MainApp" by the Netbeans Maven JavaFX template). There are questions of course, but first the method.
See: JavaFX Application
Stop is called at the end of your program. I had the call to call Platform.exit() to close-down JavaFX runtime. I've added a call to shutdown other active Executor threads, which I kept in an list for now, to test the solution.
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
.....
}
/**
* Close down the application
* #see
* -- http://docs.oracle.com/javafx/2/api/javafx/application/Application.html#stop%28%29
**/
#Override
public void stop()
{
Platform.exit();
for( ScheduledExecutorService sched : activeExecutorServices )
{
sched.shutdown();
}
}
}//MainAppl class
So by commenting-out the call to shutdown and running my JavaFX program, the application finishes but won't exit, and Netbeans show a running task. You need to manually click on the kill-button in Netbeans.
Uncomment the shutdown() call. When the JavaFX application exits, it also dissappears from the Netbeans running jobs. That appears to be a resolotion.
The remaining questions:
What is the correct order between Platform.exit() and shutdown()?
With more than one ScheduledExecutorService does it matter which order is used to shut them-off? LIFO or FIFO?
Is there a better way?
Ought Netbeans be able to detect the 'process overrun' and report this as a problem. That at least leave you and I with the option to ignore it or fix the program.
Hopefyully that will assist the next someone who faces a similar problem :-)

you can use setOnCloseRequest
#Override
public void start(Stage primaryStage) {
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
ThreadPool.shutdown();
}
});
initGui(primaryStage);
initData();
}

Related

Javafx music player not working

I'm coding a game in java, and I decided to add music to it. I tried with this code:
URL resource = getClass().getResource("music.mp3");
MediaPlayer a = new MediaPlayer(new Media(resource.toString()));
a.setOnEndOfMedia(new Runnable() {
public void run() {
a.seek(Duration.ZERO);
}
});
a.play();
But for some reason, I get this error:
https://pastebin.com/UPkTbWHh
The file music.mp3 is in the same folder as the class I'm running it from, and the code is running in the tick() method. Do anybody have an idea about how I can fix this?
Thanks, Lukas
You're attempting to execute the above code from outside the context of a JavaFX app. MediaPlayer is a JavaFX component, so relies on the Toolkit being initialised, you can't (by default) just spin up a JFX component as you please.
The "proper" way is to subclass a JFX Application and then launch your application from there, which will initialise the JFX platform properly.
The "hack" way is to run the following line of code in the Swing EDT:
new JFXPanel();
...which will also have the side effect of initialising the JFX toolkit and allow you to create other JFX components.
As pointed out in the comments, since Java 9 you can use the less hacky method of:
Platform.startup(() -> {
//Code to run on JFX thread
});

UISpec4J and external application

I am trying to launch an external application for testing using UISpec4J.
Here are the questions and their answers I referred so far:
How to automate a swing java web start application which runs clicking a link into a web application, which is automated with Selenium WebDriver?
Getting all windows using UISpec4J
UISpec4J Capturing modal dialog, before the trigger finish
my.exe referred below is a Java application wrapped in exe using some tool. Internally it uses the jars and is Java GUI application.
This executable launches a splash screen first, then a dialog to choose where you want to connect to and after that main window is shown. Unless I can automate where I can connect to I won't get main window.
Based on these questions I have come up with following code fragments:
this.setAdapter(new UISpecAdapter() {
#Override
public Window getMainWindow() {
return WindowInterceptor.run(new Trigger() {
#Override
public void run() throws Exception {
// running jnlp by netx launcher
Runtime.getRuntime().exec("C:\\my.exe");
Thread.sleep(10000);
}
});
}
});
In the approach above I simple get "No window was shown" error.
this.setAdapter(new UISpecAdapter() {
#Override
public Window getMainWindow() {
final Window[] result = new Window[1];
WindowInterceptor
.init(new Trigger() {
#Override
public void run() throws Exception {
Runtime.getRuntime().exec("C:\\my.exe");
//Thread.sleep(10000);
}
})
//.processTransientWindow()
.process(new WindowHandler() {
public Trigger process(Window window) throws Exception {
result[0] = window;
return Trigger.DO_NOTHING;
}
})
.run();
return result[0];
}
});
In the second approach above, I still get "No window shown" error AND control never reaches to overriden "process" method.
I referred to http://www.uispec4j.org/reports/apidocs/org/uispec4j/interception/WindowInterceptor.html and recommended approach is to use init to capture modal dialog is init\process sequence.
To capture non-modal it is recommended that we should use following:
Window window = WindowInterceptor.run(panel.getButton("open").triggerClick());
But I have NO idea where and how I am supposed to call it..
From the first question I referred, mentioned above, we should be able to do that because the answer to it mentions launching jnlp application which is external application.
I tried with jre 6 update 0 and I can at least run test. In java update 37, from the third question I referred above, I get abstract method not implemented error.
What am I doing wrong? Any idea?
I am using latest UISpec4J package - version 2.4.
Thanks in advance,
-Neel.
I'm very new to UISpec4J but I'm guessing it needs to run in the same JVM in order to intercept and interact with the GUI components. When you start the exe file with exec, it will create a new process and a new, separate JVM. That'll not work, if I understand UISpec4J correctly.
Regarding the non-modal example, the documentation says "You would retrieve the window from within the test...", so in a setup method or in a test should work.

Display.getDefault().asyncExec not running correctly

I am using eclipse's jobs API to run big task as a job, once task is completed I am setting boolean variable to true and if that variable is true I am executing WizardDialog in UI thread. My current code looks like this:
Job longRunningJob = new Job("Long running job...") {
#Override
protected IStatus run(IProgressMonitor monitor) {
boolean shouldShowDialog = doLongRunningJob();
if(shouldShowDialog) {
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
//Will open wizard dialog here
WizardDialog wizardDialog = new WizardDialog(Display.getCurrent().getActiveShell(), new TestWizard());
wizardDialog.setBlockOnOpen(true);
wizardDialog.open();
}
});
}
}
}
longRunningJob.setUser(true);
longRunningJob.schedule();
My problem is run inside Display thread not executing in reliable way, means sometime it goes inside run method where as sometimes it doesn't, I tried putting breakpoint inside run method and testing it out but same happens.
My question is, is what I am doing is correct way? Is this expected behaviour? So how do I handle this scenario ie once shouldShowDialog is true how do I execute code inside Display thread?
Edit: One behaviour I observed while debugging is dialog gets displayed but suddenly it get closes, I think it's exiting the thread.
The problem with disappearing dialogs is most commonly caused by using currently active Shell as the parent for the dialog. E.g. if there is a ProgressDialog open when you create your dialog then that other dialog will be the parent of your dialog. And when the other dialog closes, so does yours.
Instead, use something like:
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

Problem with java.awt.Desktop

I have a button in my program that, when pressed, is supposed to take you to my wiki page about the program. I used the following line to do so:
java.awt.Desktop.getDesktop().browse(new java.net.URI("http://supuh.wikia.com/wiki/BHT"));
The problem is that, no matter what environment in which the program is run, I always get the following error:
java.security.AccessControlException: access denied (java.awt.AWTPermission showWindowWithoutWarningBanner)
does anyone know how I can fix this? Note that this only works in the one program. Any other program I make can use the same method with no problem.
Exit hook
At the start of my program, this hook is added. The program runs fine without it...
System.setSecurityManager(new SecurityManager()
{
#Override
public void checkExit(int status)
{
closeFile(status);
}
});
this hook is needed, but the browse(URI uri) method in question won't work with it. Solutions?
This means you are running with a security manager:
SecurityException - if a security manager exists and it denies the AWTPermission("showWindowWithoutWarningBanner") permission, or the calling thread is not allowed to create a subprocess; and not invoked from within an applet or Java Web Started application
If this is an applet, or a Java Web Start app - sign your jar.
Update Adding a security manager to detect program exit is wrong. There are multiple ways to do this properly. In your case I guess this would be most appropriate:
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
closeFile();
}
));
Swing-specific solutions are:
if you don't have to perform extra actions, use frame.setDefaultCloseAction(Frame.EXIT_ON_CLOSE)
use addWindowStateListener and check for WindowEvent.WINDOW_CLOSED
That said, two notes:
you must not hold files open for a long time. Use try/catch/finally to open and close them whenever they are needed.
if you really need a security manager at some point, make sure you override the appropriate method of the SecurityManager that checks whether you can open the link. (won't tell you which one, so that you are not tempted to jump onto this solution, which is wrong)
To summarize, I'd go for setDefaultActionOnClose, and close each file right after I finish reading/writing it.
Update 2: After you linked to your original question describing what exactly are you trying to achieve, things change a bit. You are trying to prevent exit, so you do need a SecurityManager. This makes it so that you should override the checkPermission method and do nothing there (i.e. don't throw exceptions), at least when these permissions are checked (they are checked when browse is called):
new AWTPermission("showWindowWithoutWarningBanner")
new FilePermission("<<ALL FILES>>", SecurityConstants.FILE_EXECUTE_ACTION)
Update 3 Here's how exactly to override the method:
#Override
public void checkPermission(Permission permission) {
if (permission instanceof AWTPermission) {
if (permission.getName().equals("showWindowWithoutWarningBanner")) {
return;
}
}
if (permission instanceof FilePermission) {
if (permission.getActions().equalsIgnoreCase("execute")) {
return;
}
}
java.security.AccessController.checkPermission(permission);
}
(you can go without the outer if-s)
Update 4 The above method will work only if you have given permissions to your program. Otherwise it is a not-well documented behaviour of the JVM that overriding security managers are not allowed to be unprivileged. Take a look at this report - the comments say how to work it around.
To make your life simpler, you can simply #Override public void checkPermission(..) with an empty method body.
Instead of using your own SecurityManager, install a shutdown hook instead:
Runnable runnable = new Runnable() {
closeFile(status);
}
Runtime.getRuntime().addShutdownHook(new Thread (runnable, "Close file"));

Rendering Problem with Swing App and Modal Dialogs

I have a Java/Swing desktop application (Java 6u16 on Windows XP) which occasionally appears to the users to hang. I say appears to because in reality what is happening is that the application is showing a modal dialog but this dialog is not being rendered. If the user uses Alt-Tab to switch away from the application and then subsequently returns to it, the dialog gets rendered correctly. Additionally, if a remote user connects to the session via NetOp (a VNC/Remote Desktop workalike) this also causes the GUI to be redrawn correctly.
The app runs via JavaWebstart. Since I've heard of rendering issues being caused by DirectDraw, I added the following to the JNLP
<property name="sun.java2d.noddraw" value="true"/>
but the problem still occurs (If I have understood correctly, this will switch off DirectDraw and Direct3d completely: see http://download.oracle.com/javase/1.5.0/docs/guide/2d/flags.html#noddraw)
I'm out of ideas on this one, any suggestions would be greatly appreciated.
Thanks,
Phil
Edit...
I have an abstract dialog class which extends JDialog and which all other dialogs extend. It contains the following method:
public void showDialog() {
initKeyBindings();
Application.getApplication().deactivateScannerListener();
setVisible(true);
}
Whenever I want to display a dialog, I call showDialog(). The initKeyBindings method sets up an ActionMap while the second line is application specific (Application is a singleton, I'm disabling the JPOS scanner listener while the dialog is displaying).
There is a corresponding hideDialog() method as follows:
public void hideDialog() {
setVisible(false);
Application.getApplication().activateScannerListener();
dispose();
}
Thanks,
Phil
Edit...
Sorry about this, one more edit: all of the dialogs have a parent. The AbstractDialog class will default to the main application frame if no other parent is specified.
FYI
For anyone following this, I've added the following to my code:
if (SwingUtilities.isEventDispatchThread()) {
initialiseAndShowDialog();
} else {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
initialiseAndShowDialog();
}
});
}
This ensures that the dialog is only opened from the EDT.
Which thread are you calling showDialog() from? Swing components should be accessed on the Event Dispatch Thread only.
You could try SwingUtilities.invokeAndWait()
and the Runnable argument passed to it should call showDialog().
Let us know if it fixed the problem.

Categories