How to use SimpleTimeLimiter (Guava) with Vaadin - java

I'm trying to call some code within the vaadin framework which is longer running that will update the screen using push, however if the process is taking too long I want to be able to cancel it.
With that in mind I'm trying to use Guava's SimpleTimeLimiter class but no matter what I do I can't seem to stop the Vaadin process from stopping. I've tried both to put the SimpleTimeLimiter inside UI.getCurrent().access() method and outside of it but they both just continue to execute the process even if SimpleTimeLimiter throws a TimeoutException. However if I use the same code with a normal thread it seems to work...
public static void limitExecutionTime(Consumer<UI> lambda)
{
UI currentUI = UI.getCurrent();
UI.getCurrent().access(() ->
{
try
{
SimpleTimeLimiter.create(Executors.newSingleThreadExecutor()).callWithTimeout(new Callable<Void>()
{
#Override
public Void call()
{
// This is needed to deal how Vaadin 8 handles UI's
UI.setCurrent(currentUI);
lambda.accept();
return null;
}
}, 1, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException | ExecutionException e) {
NotificationUtils.showError("Execution took beyond the maximum allowed time.");
currentUI.push();
}
});
}
In the above code if the method takes more than 1 second it will throw a TimeoutException and put up the notification window. However it will continue to execute the lambda.
As a result I've tried to do the opposite and put UI.getCurrent().access() in the public Void call() method but this had the exact same result...

You should call UI.access after your background task is ready to update it with some data. You use access method to do changes on the page that the user is viewing.
Background task execution
In your example, you are missing a way to pass task cancellation message to call method. In order to prepare for task cancellation from external event (for example cancel button click) then you need to take this into account in inside the task. The following example shows how you can offer cancel method using Future.cancel.
private void onCancelClick(Button.ClickEvent clickEvent) {
// This method is called from Vaadin UI thread. We will signal
// background task thread to stop.
futureResult.cancel(true);
}
Inside the actual task this can be handled in the following ways
private void simulateLongAndSlowCalculation() {
while (moreWorkTodo) {
if (Thread.currentThread().isInterrupted()) {
return;
}
try {
doSomeBlockingCallThatCanBeInterrupted();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
Starting task and UI.access
When starting task then view should create task and submit it to executor service.
private void onButtonClick(Button.ClickEvent clickEvent) {
// This runTask creates important link to current UI and the background task.
// "this" object in these onTask methods is the UI object that we want
// to update. We need to have someway to pass UI object to background
// thread. UI.getCurrent() could be a parameter that is passed to the
// task as well.
Future<String> futureResult = taskService.runTask(
this::onTaskDone,
this::onTaskCancel,
this::onTaskProgress);
progressDialog = new ProgressDialog(futureResult);
progressDialog.show();
}
Now UI.access method is only needed when we want to update UI. In this example, that can happen in the following cases
Task completed successfully
Task progress was updated
Task got cancelled
Note that all of the following methods this refers to the UI object that started the task. So we are updating the correct UI with result and not some other user's UI.
You should not need to call UI.setCurrent in your code.
private void onTaskProgress(double progress) {
logger.info("onTaskProgress: {}", progress);
access(() -> progressDialog.setProgress(progress));
}
private void onTaskCancel() {
logger.info("onTaskCancel");
access(() -> {
progressDialog.close();
setResult("Cancelled");
});
}
private void onTaskDone(String result) {
logger.info("onTaskDone");
access(() -> {
progressDialog.close();
setResult(result);
});
}
Example project
I pushed another project to github that shows how to cancel a background task from cancel button:
https://github.com/m1kah/vaadin-background-task
Edit: Added sections about background tasks and UI.access. Updated example project link to another example.

Related

How to force progressbar get visible just before a background thread starts its execution?

I think this is a very simple question for many people in this community, however, I can't make this to work after several experiments; I would appreciate any help.
It is JAVA-android platform: The code needs to execute the next steps when the user clicks a button:
Make invisible the button (run in main thread)
Make visible a progress bar (run in main thread)
Download a file from internet (run in background thread)
Wait the download is completed
Make invisible the progress bar
Make visible again the button
That's it. It doesn't seem to be very difficult, however, it is not working as I need it.
This is the issue:
Step 3 get executed before steps 1 and 2, ... I have tried several experiments with not success.
private void f1()
{
mDataBinding.btnPausePlay.setVisibility(btnVisibility);
mDataBinding.progressPausePlay.setVisibility(progressVisibility);
}
private void f2()
{
Thread xThread = new Thread( new Runnable()
{ #Override
public void run() // run in background thread
{ httpRequest_noBackgroundThread( urlStr, urlParams, fileStr, itf ); }
});
try
{
xThread.start();
xThread.join(); // wait for the thread to finish
}
catch( Exception e ){ e.printStackTrace(); }
}
private void f3()
{
f1();
f2();
// continues execution ...
}
###########################################################
Based on Shagun Verma's feedback; It was the fix for my specific issue. Thank you!
private void f3()
{
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() ->
{
f1();
f2();
// continues execution ...
});
}
To accomplish this, you have to use Executors in Java. The below code will be done the job for you-
btnPausePlay.setOnClickListener(view -> {
btnPausePlay.setVisibility(View.GONE);
progressPausePlay.setVisibility(View.VISIBLE);
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
// Implement your file download code here i.e.
// httpRequest_noBackgroundThread( urlStr, urlParams, fileStr, itf );
handler.post(() -> {
btnPausePlay.setVisibility(View.VISIBLE);
progressPausePlay.setVisibility(View.GONE);
});
});
});
When you press the btnPausePlay button, then it will become invisible and the progress bar becomes visible. After that, once the download is completed reverse will happen.

JavaFX 2 StringProperty does not update field until enclosing method returns

I would like to update a Label in a JavaFX application so that the text changes multiple times as the method runs:
private void analyze(){
labelString.setValue("Analyzing"); // (labelString is bound to the Label during initialization)
// <Some time consuming task here>
labelString.setValue("Analysis complete!");
}
But when I run this, the label does not update until the task finishes, and just displays whatever it was before until the analyze() method returns.
How can I force update the label so that it will show "Analyzing" in the beginning followed by "Analysis complete!" when the task is complete?
Assuming you are invoking your analyze() method on the FX Application Thread (e.g. in an event handler), your time consuming code is blocking that thread and preventing the UI from updating until it is complete. As #glen3b says in the comments, you need to use an external thread to manage this code.
JavaFX provides a Task API which helps you do this. In particular, it provides methods which invoke code on the Java FX Application thread for you, allowing you to update the UI safely from your background Task.
So you can do something like
private void analyze() {
Task<Void> task = new Task<Void>() {
public Void call() {
updateMessage("Analyzing");
// time consuming task here
updateMessage("Analysis complete");
}
};
labelString.bind(task.messageProperty());
new Thread(task).start();
}
If you need to unbind the StringProperty when the task is complete, you can do
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
labelString.unbind();
}
});

Create a background task in IntelliJ plugin

I'm developing an IntelliJ-idea plugin and want to run code in background task (visible in the background tasks dialog and in another thread than the UI).
I found the following Helper class and tried it by passing a Runnable object and implement its run method but it still blocking the UI and when I tried to do the threading myself i got the following error
Read access is allowed from event dispatch thread or inside read-action only (see com.intellij.openapi.application.Application.runReadAction())
Details: Current thread: Thread[Thread-69 [WriteAccessToken],6,Idea Thread Group] 532224832
Our dispatch thread:Thread[AWT-EventQueue-1 12.1.4#IU-129.713, eap:false,6,Idea Thread Group] 324031064
SystemEventQueueThread: Thread[AWT-EventQueue-1 12.1.4#IU-129.713, eap:false,6,Idea Thread Group] 324031064
I have found a better way to run the process as background task where you can update the progress bar percentage and text
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Title"){
public void run(#NotNull ProgressIndicator progressIndicator) {
// start your process
// Set the progress bar percentage and text
progressIndicator.setFraction(0.10);
progressIndicator.setText("90% to finish");
// 50% done
progressIndicator.setFraction(0.50);
progressIndicator.setText("50% to finish");
// Finished
progressIndicator.setFraction(1.0);
progressIndicator.setText("finished");
}});
If you need to read some data from another thread you should use
AccessToken token = null;
try {
token = ApplicationManager.getApplication().acquireReadActionLock();
//do what you need
} finally {
token.finish();
}
Here is the general solution
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
// do whatever you need to do
}
});
}
});
New way to run backgroundable task with kotlin
import com.intellij.openapi.progress.runBackgroundableTask
runBackgroundableTask("My Backgrund Task", project) {
for (i in 0..10 step 1) {
it.checkCanceled()
it.fraction = i / 10.0
sleep(i * 100L)
}
}
As described in API :
Causes doRun.run() to be executed asynchronously on the AWT event
dispatching thread. This will happen after all pending AWT events have
been processed. This method should be used when an application thread
needs to update the GUI.
SwingUtilities.invokeLater {
// do something
}

Why is this thread running multiple times in a row?

I just solved the problem myself. I had multiple calls for syncCustomers() due to a dialog closing event problem. I solved it by providing the parent JFrame in the JDialog constructor. Pretty stupid error on my side.
My application contains a task that synchronizes with a webservice and a local database. This task may take up to several minutes. Thus I want to notify the user about this time consuming process with a simple dialog (Swing). The user is not supposed to continue working while the sync process is running.
So I thought of:
open modal dialog with the notification for the user
start the sync process in a separate thread
close modal dialog after sync process is done
User clicked on the button to start sync process:
private void syncCustomers() {
if (checkWebserviceAuth()) {
SyncDialog dialog = new SyncDialog();
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
SyncCustomersTask task = new SyncCustomersTask(dialog, getCoach());
task.run(); // task.start() will result in the same problem
} else {
openAuthorizeDialog(true);
}
}
public class SyncDialog extends javax.swing.JDialog {
public SyncDialog() {
initComponents();
// I already noticed that the modal dialog won't work for me since it interrupts within syncCustomers()
//this.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
this.setTitle(Application.getApplicationTitle());
}
...
}
public class SyncCustomersTask extends Thread {
private void doWork() {
System.out.println("Start doWork() and sleep for 10 seconds...");
try {
// for testing purpose
Thread.sleep(10000);
} catch (InterruptedException ex) {
}
System.out.println("Done with doWork().");
}
#Override
public void run() {
doWork();
if (getCallback() != null) {
System.out.println("Invoke callback...");
getCallback().dispose();
System.out.println("Callback invoked.");
}
}
...
}
This will result in an infinite loop of:
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
If I comment out
getCallback().dispose();
, the loop will stop after the second execution:
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
I don't get it. What fires the thread to execute over and over again?
I guess this whole thing isn't a good idea to start with, but I wasn't able to get things like ProgressMonitor working either. :(
Call start(), not run(). The latter will simply execute the thread, but not in a separate thread! The start() method will instantiate a new thread, and only then invoke your run() method in that new thread.
This is a surprising common problem, btw.
invoking run() does not execute code in a new thread.

Java: Creating a multi threaded reader

I'm creating a reader application. The reader identifies based on the parameters which file to read, does some processing and returns the result to the caller.
I am trying to make this multi-threaded, so that multiple requests can be processed. I thought it was simple but later realized it has some complexity. Even though i create threads using executor service, I still need to return the results back to the caller. So this means waiting for the thread to execute.
Only way i can think of is write to some common location or db and let the caller pick the result from there. Is there any approach possible?
Maybe an ExecutorCompletionService can help you. The submitted tasks are placed on a queue when completed. You can use the methods take or poll depending on if you want to wait or not for a task to be available on the completion queue.
ExecutorCompletionService javadoc
Use an ExecutorService with a thread pool of size > 1, post custom FutureTask derivatives which override the done() method to signal completion of the task to the UI:
public class MyTask extends FutureTask<MyModel> {
private final MyUI ui;
public MyTask(MyUI toUpdateWhenDone, Callable<MyModel> taskToRun) {
super(taskToRun);
ui=toUpdateWhenDone;
}
#Override
protected void done() {
try {
// retrieve computed result
final MyModel computed=get();
// trigger an UI update with the new model
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ui.setModel(computed); // set the new UI model
}
});
}
catch(InterruptedException canceled) {
// task was canceled ... handle this case here
}
catch(TimeoutException timeout) {
// task timed out (if there are any such constraints).
// will not happen if there are no constraints on when the task must complete
}
catch(ExecutionException error) {
// handle exceptions thrown during computation of the MyModel object...
// happens if the callable passed during construction of the task throws an
// exception when it's call() method is invoked.
}
}
}
EDIT: For more complex tasks which need to signal status updates, it may be a good idea to create custom SwingWorker derivatives in this manner and post those on the ExecutorService. (You should for the time being not attempt to run multiple SwingWorkers concurrently as the current SwingWorker implementation effectively does not permit it.)

Categories

Resources