I tried the sample code from HelloGui provided with install4j8.0.2 to download the update of my application using Background update downloader. When the download is completed I want to show a confirm dialog to the user whether they want to run the updater now or later. The problem is the updater is not execute immediately, rather it is scheduled for the next time the launcher will run.
In summary, my requirement is:
Update the download in background
Show a confirmation dialog when download is complete
Execute the updater immediately if the user wants to update now.
I cannot accomplish this as the updater is scheduled to be executed on next run of the launcher.
I see that UpdateChecker.isUpdateScheduled() returns false when the download finishes.
Here is the sample code to execute updater immediately:
private void downloadAndUpdate() {
// Here the background update downloader is launched in the background
// See checkForUpdate(), where the interactive updater is launched for comments on launching an update downloader.
new SwingWorker<Object, Object>() {
#Override
protected Object doInBackground() throws Exception {
// Note the third argument which makes the call to the background updater blocking.
ApplicationLauncher.launchApplication("1160", null, true, null);
// At this point the update downloader has returned and we can check if the "Schedule update installation"
// action has registered an update installer for execution
// We now switch to the EDT in done() for terminating the application
return null;
}
#Override
protected void done() {
try {
get(); // rethrow exceptions that occurred in doInBackground() wrapped in an ExecutionException
if (UpdateChecker.isUpdateScheduled()) {
JOptionPane.showMessageDialog(null, "Download is complete, the new version will now be installed.", "Hello",
JOptionPane.INFORMATION_MESSAGE);
// We execute the update immediately, but you could ask the user whether the update should be
// installed now. The scheduling of update installers is persistent, so this will also work
// after a restart of the launcher.
executeUpdate();
} else {
JOptionPane.showMessageDialog(null, "Update could not be downloaded", "Hello", JOptionPane.ERROR_MESSAGE);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "An error has occurred:" + e.getCause().getMessage(), "Hello", JOptionPane.ERROR_MESSAGE);
}
}
}.execute();
}
private void executeUpdate() {
// The arguments that are passed to the installer switch the default GUI mode to an unattended
// mode with a progress bar. "-q" activates unattended mode, and "-splash Updating hello world ..."
// shows a progress bar with the specified title.
UpdateChecker.executeScheduledUpdate(Arrays.asList("-q", "-splash", "Updating ..."), true, null);
}
To execute the downloaded update (by Background update downloader) immediately:
Open a launcher
Go to Executable info || Auto-update integration
Select Execute downloaded update installers at startup
If we execute downloader and update programmatically, still we need to select this; otherwise newly downloaded update does not run immediately. I have tested this with install4j version 8.0.2.
Related
I have a spring-boot web application to be distributed as jar file. The code to start the application is as follows:
private static ConfigurableApplicationContext ctx;
public static void main(String[] args){
if(ctx == null) {
ctx = SpringApplication.run(MyApplication.class, args);
}
try {
openHomePage("http://localhost:8090/");
}catch(Exception e) {
logger.error("Error occured starting the application: ", e);
ctx.close();
}
}
private static void openHomePage(String url) throws IOException, URISyntaxException {
if(Desktop.isDesktopSupported()) {
URI homePage = new URI(url);
Desktop.getDesktop().browse(homePage);
}else {
Runtime runtime = Runtime.getRuntime();
runtime.exec(new String[]{"cmd", "/c","start chrome " + url});
}
}
which opens the home page in Chrome, both when I run it from Eclipse and by double clicking on the jar file.
The problem is when I start the application from the jar file and close the browser tab, the application continues to run in JVM and I have to kill it from the task manager manually which is annoying. If I don't kill the JVM and double click on the jar file again, then the application doesn't start automatically as it does the first time, and I have to manually open a new browser tab and type http://localhost:8090/ in order to use the application.
Is it possible to kill every process after user closes the browser tab so that when they click on the jar file next time they need to use the application, a fresh browser tab opens automatically?
Thanks in advance..
SOLUTION
This might not be the best solution but it works a treat.
*Step 1 - Send heartbeats from the browser
var heartBeatIntervals = null;
$( document ).ready(function() {
//this ajax call will be fired every 2 seconds as long as the browser tab stays open.
// the time intervals can of course be modified
heartBeatIntervals = setInterval(() => {
$.ajax({
type:'POST',
url: 'http://localhost:8090/MyController/checkHeartbeats'
})
}, 2*1000);
});
*Step 2 - Handle the heartbeats in the server
#Controller
#RequestMapping("/MyController")
public class MyController {
//declare an instance variable to store the number of missed heartbeats
private int missedHeartbeats = 0;
//reset the counter to 0 upon receiving the heartbeats
#PostMapping("/checkHeartbeats")
public void checkHeartbeats() {
missedHeartbeats = 0;
}
//increase the missedHeartbeats by one every 3 seconds - or whatever
#Scheduled(fixedRate = 3000)
public void schedule() {
missedHeartbeats++;
//check how many heartbeats are missed and if it reaches to a certain value
if(missedHeartbeats > 5) {
//terminate the JVM (also terminates the servlet context in Eclipse)
System.exit(0);
}
}
}
*Step - 3 Enable scheduling
In order to use any scheduling in spring-boot application you need to add #EnableScheduling annotation in your class where your main method resides.
And that's it.
There's a stop button in Eclipse. And in case it can't be used:
You can send something from javascript to your server continiously and when server haven't recieved it for 1 sec, which means the web page was closed, stop itself.
Solution 1
Use a method in any #Controller to handle heartbeat requests.
Store the most recent heartbeat time in a static field of any class, the initial value could be 0 or -1 indicating the web page has not been opened yet.
Use a #Scheduled task to retrive last heartbeat time and compare with current time. schedule the task once per 2 second or whatever. https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support
Stop JVM if needed, maybe by System.exit(0).
Solution 2
It would be easier if you can add a Close button on webpage. being clicked, it signals the server to stop, and afterwards it closes the web page itself. https://stackoverflow.com/a/18776480/9399618
I am trying to launch MySql server installer which is in my resources folder but it terminates after a few seconds. However if I launch it manually it runs okay until the end. Below is my code.
Thread t = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
String fileUrl = classloader.getResource("mysql.msi").getFile();
Runtime rf = Runtime.getRuntime();
Process pf = rf.exec("msiexec /i \"\\" + fileUrl + "\"");
} catch (Exception e) {
// System.out.println(e.toString()); // not necessary
e.printStackTrace();
}
}
});
t.start();
Okay, it was just an advice, lets come to your case, Windows OS has certain set of security restrictions which allows only administrator to install or remove any application.
That is why, we see a promt window asking for Administrator password (or Admin's permission as YES/NO type, in case user has logged in as admin), and the promt screen is the heart of it's security, as it don't allow ANY OTHER APPLICATION TO HAVE CONTROL ON IT.
If you do a remote desktop via third party, you will never see the client machines promt screen (this is because of security constraints), so in your case, your java application is third party app which don't have enough permission to continue the operation further.
Hence it closes after few seconds.
How ever, you can start and stop already installed services by allowing permission once in your windows service control. So I was suggesting you to play with service only.
I made a simple application that automatically uploads/downloads files to and from a server given that there are files to upload or download. I am using a Timer Task to periodically check if there are files locally to upload, or files online to download.
Everything is working fine, and I decided that every time that there is a successful upload/download, I'll show a message dialogue to show the user that a file was successfully uploaded/downloaded.
So far, this is what I have, I am calling this function infoBox. Note that I am doing this in the TimerTask:
public static void infoBox(String infoMessage, String titleBar){
Toolkit.getDefaultToolkit().beep();
JOptionPane.showMessageDialog(null, infoMessage, titleBar,
JOptionPane.INFORMATION_MESSAGE);
}
Then based on whether or not I got a file or I sent a file, I call it as such:
infoBox("Files Sent!", "Files were sent successfully!");
Or
infoBox("Files Received!", "Files were downloaded successfully!");
And it works fine. If I get a file from the server, or upload a file to it, the message pops up fine.
However, it seems that the TimerTask stops whenever it shows the message dialogue. I have to click "Ok" for the dialogue to close and for the TimerTask to do its thing again.
What I want to happen is for the TimerTask to execute over and over again, regardless how many message dialogues it has shown.
I have a feeling I misplaced where I declared and called my infoBox function. Is there a way for a programs routine task to continually execute as I show message dialogues?
Found an answer here.
Just run the code in a thread, and it won't stop the main thread any more.
public static void infoBox(String infoMessage, String titleBar){
Thread t = new Thread(new Runnable(){
public void run(){
Toolkit.getDefaultToolkit().beep();
JOptionPane.showMessageDialog(null, infoMessage, titleBar, JOptionPane.INFORMATION_MESSAGE);
}
});
t.start();
}
I have this method which basically waits for items in the singleton queue to become empty, there is a background service which is running and the service stops once it removes all items in the queue and process each one by one. This code runs in the main thread, what will happen when I call wait here? will the alert dialog still be showing and blocking the user from performing any other action?
void waitForService() {
openConnectionToUploadQueue();
if(answersQueue.getCount(objInterviewQuestion.getQid()) <= 0){
answersQueue.close();
return;
}
if(!answersQueue.isInterviewUploadServiceRunning()) {
answersQueue.startInterviewUploadService();
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getString(R.string.auto_submit_alert_title));
builder.setCancelable(false);
builder.setMessage(R.string.uploading_pending_answers);
AlertDialog waitForServiceDialog = builder.create();
waitForServiceDialog.show();
while (answersQueue.getCount(objInterviewQuestion.getQid()) > 0) {
// do nothing and keep loop running till answersQueue is empty
}
waitForServiceDialog.dismiss();
}
You should never block UI Thread. When you hold UI Thread for too long, this is when the system will show a dialog saying XXX is not responding and ask user to kill your application.
Instead, you should use a callback style call, and when the service is up, and you receive the method call from callback, you dismiss the dialog.
Edit:
As discussed, you would need to implement BroadcastReceiver
Here is a demo project of mine for something else, you can use it as a sample on how to create and use BroadcastReceiver.
https://github.com/cyfung/ActivityRecognitionSample
I am doing a networking project. I compiled a code under Java Project console app and it works. But when I create a GUI and assign the code to run when a button is pressed, it hangs on clicking the button.
This is the source code:
#Action
public void EstablishConnection() {
serverAddress = jTextFieldServerAddress.getText();
serverPort = Integer.parseInt(jTextFieldPort.getText());
serverUName = jTextFieldUName.getText();
serverUPwd = jTextFieldUPwd.getText();
try {
client = new FTPClient();
client.connect(serverAddress, serverPort);
boolean login = client.login(serverUName, serverUPwd);
if(login) {
System.out.println("Successfully logged in\n");
}
else {
System.out.println("Unable to login\n");
}
}
catch(Exception ex) {
System.out.println("Exception Raised: " + ex);
}
}
The action is called when a button is pressed in the swing app. It is not working for me. But it is working very fast for a console app.
Anytime I see the word "hang" I assume you need to be using a separate Thread to execute the hanging code. See Concurrency in Swing for the solution.
I would suggest that you should run code that depends on external factors, like accessing a remote server etc., that could delay the response, in a thread of it's own.
Display a MessageDialog with an indeterminate progress bar:
connProgressBar.setIndeterminate(true);
You neither know whether your connection will terminate, nor if it will, so add a button that allows the user to kill the connection thread, whenever she feels like it.
Since you are probably connecting to an ftp server in order to upload and download files, after the connection has been established, use a determinate progressbar that shows the download percentage of the file or files progress, that runs in a new thread.