Wicket causing a long operation and update via ajax

Based on this question, https://stackoverflow.com/a/166268/2128 , I came to understand that Wicket is setting up subsequent AJAX requests. Now my page is accompanied by several AJAX requests, and I would like to add another one that starts a lengthy operation.

public void populateItem(final Item item) { final MyObject object = (MyObject) item.getModelObject(); // ... a couple of fields Label statusLabel = new Label("status", new AbstractReadOnlyModel() { @Override public Object getObject() { return someService.doSomeLengthyOperation(); } }); statusLabel.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(5))); item.add(statusLabel) } 

Once this Ajax request is triggered, it may take up to one minute to complete it. The problem here is that someService.doSomeLengthyOperation() will execute n times the number of rows , which I have, which means that I will queue n times two-minutes . Now, as I have already mentioned, Wicket puts next AJAX requests.

What happens, I need number-of-rows * minutes-it-take-to-finish-the-operation load the page or do other things that require AJAX, for example

 new AjaxButton("ajax-button"){ @Override protected void onSubmit(AjaxRequestTarget target, Form form) { //.. this won't be executed until all the statusLabels have finished invoking getObject() } } 

I would like to avoid creating a web service that provides my service, and I had to write my own AJAX calls. What are my options? (Using Wicket 1.5 / Pax-Wicket)

+4
source share
2 answers

The easiest way is to quickly load the original Ajax request (without any results) and add AjaxSelfUpdatingTimerBehavior to the target component. This behavior then checks for intervals (for example, every 10 seconds or so) if there is a result. If there is a result, it should update the ans component and remove it itself.

This way you can perform the operation in a separate task without blocking Ajax calls.

To develop a bit, I created a runnable quickstart that issues 5 Ajax calls, as you described, each of which starts a random amount of time between 10 seconds and one minute. At the same time there is a responsive AjaxLink with a counter.

The basic idea is to separate the actual Ajax calls from the calls to the slow method.

 add(new ListView<DataHolder>("list", list) { @Override protected void populateItem(ListItem<DataHolder> item) { DataHolder dh = item.getModelObject(); item.add(new Label("itemNumber", new PropertyModel<Integer>(dh, "number"))); Label result = new Label("itemResult", new PropertyModel<String>(dh, "result")); result.setOutputMarkupId(true); result.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(2))); item.add(result); Thread thread = new Thread(new Processor(item.getModelObject())); thread.start(); } }); 

As you can see, the shortcut model no longer calls doSomeLengthyOperation() . Instead, a new thread is created that makes a heavy lift. The Processor class simply implements the Runnable interface and uses the run method to do the work (in your case, it just waits for a while in the demo).

The getter for the PropertyModel encapsulates this trick and makes it transparent, always returning quickly to prevent blocking.

 public String getResult() { String retValue; if (!processed) { retValue = String.format("Still busy after %d requests", counter++); } else { retValue = result; } return retValue; } 

The processed element is just a flag that the processor uses to indicate that it has made an wait (ehr working).

Since you are probably publishing more than 5 threads at a time, I would recommend using some kind of Threadpool, but this is beyond the scope of this small demo.


Disclaimer: This is not a production code. This is just for demonstration. This will not be good for your resources and will not process them gracefully. It will not work if the user clicks restart or something else happens.

+3
source

I'm not quite sure the WicketStuff Async Task can help you, but try:

https://github.com/wicketstuff/core/wiki/Async-tasks

Here is a short demo that is in the Async Tasks project:

 public class DemoPage extends WebPage implements IRunnableFactory { public DemoPage() { Form<?> form = new Form<Void>("form"); AbstractTaskContainer taskContainer = DefaultTaskManager.getInstance() .makeContainer(1000L, TimeUnit.MINUTES); ProgressButton progressButton = new ProgressButton("button", form, Model.of(taskContainer), this, Duration.milliseconds(500L)); ProgressBar progressBar = new ProgressBar("bar", progressButton); add(form); form.add(progressButton); form.add(progressBar); } @Override public Runnable getRunnable() { return new IProgressObservableRunnable() { // Runnable implementation. }; } 
0
source

All Articles