How to implement a loading screen in JavaFX when opening another application - java

I am currently working on a programm where I try to open another application (such as eg Notepad) from a link.
As sometimes it will take some time to open that programm, I wanted to implement either a loading screen, or simply indicate the program being loaded by changing the cursorstyle, but only for the period, until the application has been launched and is running.
Whenever I try to implement this feature the cursor is only changed after the application is already running.
The application is launched via the following method:
public void run(String path) {
try {
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(path);
try {
Thread.sleep(5000);
} catch (Exception e) {
new Warnings().AppOpenError(dataBean.getLinkPath());
}
process.destroy();
dataBean.getPrimaryStage().getScene().setCursor(Cursor.DEFAULT);
} catch (IOException e) {
new Warnings().ioException(e);
}
}
How can I achieve the loading bar only being shown during loadingtime of the application?

Related

How can I perform an operation when a Spring application ends? [duplicate]

This question already has answers here:
Spring webapp - shutting down threads on Application stop
(1 answer)
Register shutDownHook in web application
(4 answers)
Closed 5 years ago.
I am not so into Spring framework and I have the following problem.
I am implementing a simple console application (it is a batch that obtain some data from a database and perform some call to an external web service).
When the application starts it creates a lock file in the same folder where the executed .jar file is.
My problem is: when the application ends this lock file have to be deleted.
This must be done either when the application terminates successfully or when it terminates for an error.
I read that in Java I can use a ShutdownHook but I am thinking that maybe Spring provide me some more neat way to do it.
So basically I have a situation like this:
public class MainApp {
public static void main(String[] args) {
try {
checkIfRunning();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
new MainApp().execute();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void execute() throws InterruptedException {
System.out.println("Trigger BATCH START");
//TimeUnit.SECONDS.sleep(150);
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("applicationContext.xml");
context.refresh();
System.out.println("OBTAINED CONTEXT");
System.out.println("Trigger BATCH END");
}
/**
* Check if the Trigger batch is alread running:
* #throws FileNotFoundException
*/
private static void checkIfRunning() throws FileNotFoundException {
System.out.println("checkIfRunning() START");
File f = new File(System.getProperty("user.dir") + "/lock.txt");
if(f.exists() && !f.isDirectory()) {
System.out.println("Lock file exists !!!");
}
else {
File file = new File(System.getProperty("user.dir") + "/lock.txt");
FileOutputStream fos = new FileOutputStream(file);
}
}
}
How can I correctly intercept the event related to the application termination to perform the delete of my lock file?
The application can terminate because:
It completed its execution.
The user press CTRL+C and quit it.
An exception occur and it terminate.
What is a smart way to do it using Spring?
Since the file creation happens outside of Spring, I would delete it outside of Spring for consistency.
You can add a shutdown hook:
try {
checkIfRunning();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} finally {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Deleting the lock file...");
// TODO: call a function to delete the lock file if it exists
System.out.println("Lock file delete");
}
});
}
According the documentation: addShutdownHook(Thread hook):
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.

Share Process / Thread

I am facing a problem regarding Process and Threads. My Scenario is:
My Java Application, call it 'Starter-App', starts another exe Application (Diagnosis.exe) with ProcessBuilder within a named Thread:
Thread startGXThread = new Thread(new Runnable() {
#Override
public void run() {
try {
...
File gxExe = new File(pathToGX); // Path to Diagnosis.exe
gxp = pb.start();
gxp.waitFor();
} catch (IOException e) {
LOG.error("Can't start module");
LOG.error(e.getMessage(), e);
} catch (InterruptedException e) {
LOG.debug("thread interrupted. Destroy process");
LOG.debug(e.getMessage(), e);
if (gxp != null) {
gxp.destroy();
LOG.debug("process exit value: " + gxp.exitValue());
}
}
}
}, "diag_thrd");
Afterwards a jetty webserver (ServiceWebApp) is started with a webapp.
start chromium and 'Starter-App' listen when its closed.
Once chromium closes 'Starter-App' recognizes this and stops jetty and also terminate the startet application.Diagnosis.exe. This is done by:
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
stopAsync();
}
});
public static void stopAsync() {
Thread diag = getThread("diag_thrd");
if (diag != null) {
diag.interrupt();
}
if (gxp != null) {
gxp.destroy();
LOG.debug("process exit value: " + gxp.exitValue());
}
}
Question:
I need to be able to stop the startet Diagnosis.exe from within the webapp and start it again, while still be able to destroy/shutdown the Diagnosis.exe once chromium stops within 'Starter-App'.
I hope I could explain my problem and hope for suggestions.
Building on Anands answer, I think you need some form of IPC between the Diagnosis.exe and your Starter-App, using websockets, or a number of other options, for some ideas: How to have 2 JVMs talk to one another.
The webapp would send a request for restarting Diagnosis.exe to the Starter-App and the Starter-App would stay in charge of managing the application trio at all time.
I think there is a solution but a but tricky to implement.
You can always use *nix api's like ps kill #pid as explained in the example here Killing a process using Java
But your webserver has to know which PID's to look for. The only option I see to implement such thing is using sockets or webservices. So you keep track of what is the current pid of Diagnosis.exe process, and use that Id before killing.

Java: Runtime.getRuntime().exec() - how to get reference to launched programs JFrame?

When launching a Java program like this (or equivalent):
Runtime.getRuntime().exec("java -jar someJar.jar")
Is it possible to get a reference to the JFrame of the launched program so it can be automated with libraries like FEST (e.g in tests)?
It's easy to do this when the program is launched inside the same VM, as illustrated in this example below, but for several reasons I cannot do that. The program must be separated from the VM/process launching it like above or similar. However, when using the above code to launch the process, the FEST code below does not find the frame.
Example using FEST with adapted code from Java Reflection. Running a external jar and referring to its classes?: (FrameFixture is just an automation wrapper for a JFrame):
Thread t = new Thread(new Runnable() {
public void run() {
File file = new File("someJar.jar");
URLClassLoader cl;
try {
cl = new URLClassLoader( new URL[]{file.toURI().toURL()} );
}
catch (MalformedURLException e) {}
Class<?> clazz = null;
try {
clazz = cl.loadClass("Main");
}
catch (ClassNotFoundException e) {}
Method main = null;
try {
main = clazz.getMethod("main", String[].class);
}
catch (NoSuchMethodException e) {}
try {
main.invoke(null, new Object[]{new String[]{}});
}
catch (Exception e) {}
}
});
t.start();
GenericTypeMatcher<JFrame> matcher = new GenericTypeMatcher<JFrame>(JFrame.class) {
protected boolean isMatching(JFrame frame) {
return "TestFrame".equals(frame.getTitle()) && frame.isShowing();
}
};
FrameFixture frame = WindowFinder.findFrame(matcher).using(BasicRobot.robotWithCurrentAwtHierarchy());
frame.maximize();
No, you cannot get a reference to a JFrame in another process. When you use Runtime.exec() a totally new OS process is created with its own memory space and protections.
To accomplish what you want you could create a JMX-like interface that accepts commands that will either execute actions within a process or report back information from the process.

Java Swing application terminates unexpectedly

I'm trying to write a Swing application in Java that also runs the Google AppEngine Dev-Server (see Developing a Java Application that uses an AppEngine database) and am running into a strange problem with the Swing Eventloop.
I have the following two classes:
A debug-window, which will eventually receive log messages, etc:
public class DebugWindow {
private static JFrame debugWindow = null;
private static JTextArea debugContent = null;
public static void show() {
debugWindow = new JFrame("Debug");
debugWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
debugContent = new JTextArea("Debug messages go here!");
debugWindow.add(debugContent, BorderLayout.CENTER);
debugWindow.pack();
debugWindow.setVisible(true);
}
}
A helper-class that loads the Google AppEngine Dev-Server:
// other imports
import com.google.appengine.tools.development.DevAppServerMain;
public class DevServer {
public static void launch(final String[] args, boolean waitFor) {
Logger logger = Logger.getLogger("");
logger.info("Launching AppEngine server...");
Thread server = new Thread() {
#Override
public void run() {
try {
DevAppServerMain.main(args); // run DevAppServer
} catch (Exception e) { e.printStackTrace(); }
}
};
server.setDaemon(true); // shut down server when rest of app completes
server.start(); // run server in separate thread
if (!waitFor) return; // done if we don't want to wait for server
URLConnection cxn;
try {
cxn = new URL("http://localhost:8888").openConnection();
} catch (IOException e) { return; } // should never happen
boolean running = false;
while (!running) {
try {
cxn.connect(); // try to connect to server
running = true;
} catch (Exception e) {}
}
logger.info("Server running.");
}
}
My main(...) method looks like this:
public static void main(final String[] args) throws Exception {
DevServer.launch(args, true); // launch and wait for AppEngine dev server
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
DebugWindow.show(); // create and show debug window
}
});
}
With this I'm getting some very strange behavior regarding the Swing Eventloop:
First, the way Swing should work: If I comment out the line DevServer.launch(...) in main(...), the application launches, shows the debug window, keeps running, and when I close the debug window, it shuts down.
If I add DevServer.launch(...) back in, it launches the server as expected, and then quits immediately (it probably also showed the debug window briefly, but it's too quick to see).
If I move DevServer.launch(...) line after SwingUtilities.invokeLater(...), it shows the debug window, then launches the server, and when the server is up, it quits immediately.
Now it get's really weird: If I change the line to DevServer.launch(args, false), i.e. I don't wait for the server to actually launch, but simply let my main(...) method complete immediately, the debug window shows, the server loads correctly, the application keeps running, but doesn't quit if I close the debug window?!
If I then also change JFrame.DISPOSE_ON_CLOSE to JFrame.EXIT_ON_CLOSE, the debug window shows, the server loads correctly, the application keeps running, and it quits correctly if I close the debug window.
Any idea what is going on with the Swing event loop here? I'm stumped... Are there things that will cause the Swing event loop to terminate early (scenario 2 and 3)? Do multi-threaded applications prevent Swing from detecting the last disposed window (scenario 4)?
For reference, here is the source of the Google AppEngine Dev Server.
Items #4 and #5 are actually expected behavior. A Java/Swing application doesn't stop when the last Swing window is disposed, but when the last thread stops executing. These two conditions are equivalent for single-threaded applications, but not for multi-threaded ones.
As for #1, #2 and #3: looking through the AppEngine Dev Server code, I noticed a fair amount of System.exit(int) calls in there. One of these is probably the culprit. If the code you're showing is all that's relevant, then the offending System.exit is likely called in response to the connection established after if (!waitFor) return; (due to #4)

Using threads and ProcessBuilder

I am really unfamiliar with working with threads, so I was hoping someone could help me figure out the best way to do this.
I have a JButton in my java application...when you click on the button, I have a Process Builder that creates a process which executes some external python code. The python code generates some files, and this can take some time. When the python code is done executing, I need to load those files into an applet within my Java application.
In its current form, I have a p.waitFor() within the code that calls the external python file...so when you click on the button, the button hangs (the entire application hangs actually) until the process is done. Obviously, I want the user to be able to interact with the rest of the application while this process is going on, but as soon as it's done, I want my application to know about it, so that it can load the files into the applet.
What is the best way to do this?
Thanks for your help.
You should use SwingWorker to invoke the Python process on a background thread. This way your UI will remain responsive whilst the long-running task runs.
// Define Action.
Action action = new AbstractAction("Do It") {
public void actionPerformed(ActionEvent e) {
runBackgroundTask();
}
}
// Install Action into JButton.
JButton btn = new JButton(action);
private void runBackgroundTask() {
new SwingWorker<Void, Void>() {
{
// Disable action until task is complete to prevent concurrent tasks.
action.setEnabled(false);
}
// Called on the Swing thread when background task completes.
protected void done() {
action.setEnabled(true);
try {
// No result but calling get() will propagate any exceptions onto Swing thread.
get();
} catch(Exception ex) {
// Handle exception
}
}
// Called on background thread
protected Void doInBackground() throws Exception {
// Add ProcessBuilder code here!
return null; // No result so simply return null.
}
}.execute();
}
You really want to create a new thread for monitoring your new process. As you've discovered, using just one thread for both the UI and monitoring the child process will make the UI seem to hang while the child process runs.
Here's some example code that assumes the existence of a log4j logger which I think will illustrate one possible approach...
Runtime runtime = Runtime.getRuntime();
String[] command = { "myShellCommand", "firstArgument" };
try {
boolean done = false;
int exitValue = 0;
Process proc = runtime.exec(command);
while (!done) {
try {
exitValue = proc.exitValue();
done = true;
} catch (IllegalThreadStateException e) {
// This exception will be thrown only if the process is still running
// because exitValue() will not be a valid method call yet...
logger.info("Process is still running...")
}
}
if (exitValue != 0) {
// Child process exited with non-zero exit code - do something about failure.
logger.info("Deletion failure - exit code " + exitValue);
}
} catch (IOException e) {
// An exception thrown by runtime.exec() which would mean myShellCommand was not
// found in the path or something like that...
logger.info("Deletion failure - error: " + e.getMessage());
}
// If no errors were caught above, the child is now finished with a zero exit code
// Move on happily

Categories

Resources