And for your curiosity, the THREAD_POOL is nothing but an ExecutorService
inside the WebApplication:

/**
     * Cashed thread pool used for background tasks that are outside of the
Quartz scheduler.
     * TODO: We might be better off using a spring service
     */
    public static final ExecutorService THREAD_POOL =
Executors.newCachedThreadPool();

As per the JavaDoc, this is not the best solution but is working so far for
the single button we have.
Once we'll add a second use-case I'm planning on switching it to a Spring
service so we can inject the pool itself.



On Thu, Jan 2, 2014 at 3:15 PM, Paul Bors <p...@bors.ws> wrote:

> Your "main thread" must be the request cycle's worker thread that wicket
> has for your syncronized on the page.
> If something takes more than 1 sec as you would expect ti to, it must mean
> that whatever you're doing on the page is running your CPU high keeping it
> bussy long enough for the 10 secs.
>
> In other words, you must be doing something wrong.
>
> Here's an example of how to detach a thread from your Wicket page:
> public class DictionaryMappingPage extends AdminPage {
> ...
>     // Background thread's status
>     private TaskStatus taskStatus = new TaskStatus();
>     // Progress bar that will replace the button
>     private ProgressBar progressBar = new ProgressBar("progress", new
> Model<Integer>(0));
>     public DictionaryMappingPage() {
> ...
>         // timer that will be started on the button press
>         final AjaxSelfUpdatingTimerBehavior updatingTimerBehavior = new
> AjaxSelfUpdatingTimerBehavior(Duration.seconds(1)) {
>             private static final long serialVersionUID = 1L;
>             @Override
>             protected void onPostProcessTarget(final AjaxRequestTarget
> target) {
>                 // Progress bar is deterministic, so hack around it to
> make it look non-deterministic (we don't know how long this will take)
>                 if(progressBar.getModelObject() >= 90) {
>                     progressBar.setModelObject(0);
>                 }
>                 progressBar.forward(target, 10);
>                 if (taskStatus.isDone()) {
>                     stop(target);
>                     if (taskStatus.getError() == null) {
>
> info(ResourceKeyHelper.resourceValue("dictionary.mapping.export.success"));
>                         ajaxDownload.initiate(target);
>                     } else {
>
> log.debug(taskStatus.getError().getLocalizedMessage(),
> taskStatus.getError());
>
> error(ResourceKeyHelper.resourceValue(taskStatus.getFeedbackKey()));
>                     }
>                     // Toggle visibility of components on the page (button
> and progress bar)
>                     exportButton.setEnabled(true);
>                     exportButton.setVisible(true);
>                     progressBar.setVisible(false);
>                     MyPageUtils.refreshComp(target, exportButton);
>                     MyPageUtils.refreshComp(target, progressBar);
>                     MyPageUtils.refreshFeedback(target, exportButton);
>                 } else {
>                     if(exportButton.isEnabled()) {
>                         stop(target);
>                     }
>                 }
>             }
>         };
>         // Adds the behaviour somewhere on the page, title in this case
>         pageTitle.add(updatingTimerBehavior);
> ...
>         Form<Void> exportForm = ...
>         add(exportForm);
>         // Default page state
>         progressBar.setVisible(false);
>         progressBar.setOutputMarkupId(true);
>         progressBar.setOutputMarkupPlaceholderTag(true);
>         exportForm.add(progressBar);
>         // There we go...
>         exportButton = new AjaxButton("exportButton", new
> ResourceModel("dictionary.mapping.export.file.button")) {
>             private static final long serialVersionUID = 1L;
>             @Override
>             protected void onSubmit(AjaxRequestTarget target, Form<?>
> form) {
>                 // User selected the Export button, toggle hide the button
> and show the progress bar (they are overlayed)
>                 setEnabled(false);
>                 setVisible(false);
>                 progressBar.setVisible(true);
>                 progressBar.setModelObject(0);
>                 // Let's keep track of the background task
>                 taskStatus = new TaskStatus(taskStatus.getError(),
> taskStatus.getFeedbackKey());
>                 // Start the timer event that will update the UI each
> second via Ajax
>                 updatingTimerBehavior.restart(target);
> // We have a thread pool at the application level to share for background
> tasks
>                 ConsoleApplication.THREAD_POOL.submit(new Runnable() {
> // This is our Runnable detached from the page, updatingTimerBehavior will
> keep refreshing the page
>                     public void run() {
>                         try {
> // Inside working thread, perform your background tasks here
>                         } finally {
>                             taskStatus.setDone(true);
>                         }
>                     }
>                 });
>                 MyPageUtils.refreshComp(target, this);
>                 MyPageUtils.refreshComp(target, progressBar);
>             }
>         };
>         exportButton.setOutputMarkupId(true);
>         exportButton.setOutputMarkupPlaceholderTag(true);
>         exportButton.add(buttonStyle);
>         exportForm.add(exportButton);
>         ...
>     }
> ...
>     /**
>      * Lightweight implementation of a background task's state as it
> integrates with the UI.
>      *
>      * TODO: If we start using more than one background task we might as
> well switch to using wicket-progressbar.
>      * @see <a href="https://github.com/wicketstuff/core/wiki/Progressbar
> ">wicket-progressbar</a>
>      */
>     private class TaskStatus implements IClusterable {
>         private static final long serialVersionUID = 1L;
>         private String feedbackKey;
>         private boolean done;
>         private Throwable error;
>         public TaskStatus() { }
>         public TaskStatus(Throwable error, String feedbackKey) {
>             setError(error);
>             setFeedbackKey(feedbackKey);
>         }
>         public String getFeedbackKey() {
>             return feedbackKey;
>         }
>         public void setFeedbackKey(String feedbackKey) {
>             this.feedbackKey = feedbackKey;
>         }
>         public boolean isDone() {
>             return done;
>         }
>         public void setDone(boolean done) {
>             this.done = done;
>         }
>         public Throwable getError() {
>             return error;
>         }
>         public void setError(Throwable error) {
>             this.error = error;
>         }
>     }
> }
>
>
>
> On Thu, Jan 2, 2014 at 2:40 PM, eaglei22 <jchojnack...@gmail.com> wrote:
>
>> Great catch Paul. I have made the changes reccommended. However, I read
>> the
>> file into the arrayList using the main thread, and then use the worker
>> thread for processing. I don't think the ArrayList is being modified
>> during
>> this time, but just incase something is happening beyond my knowledge
>> under
>> the hood that will need this or in the future I will be modifying the
>> contents of the Array, I have made the neccessary changes as you
>> suggested.
>>
>> The only thing I noticed is after my worker thread finishes, my
>> AbstractAjaxTimerBehavior in the main thread  seems to take about 10
>> seconds
>> or so before it performs a component update on the List, even though I
>> have
>> it set to 1.
>>
>> I don't get any errors anymore though, and the whole list does get
>> processed
>> now.
>>
>> here is my settings for AbstractAjaxTimerBehavior:
>>
>>                 resultsUpdateBehavior = new
>> AbstractAjaxTimerBehavior(Duration.seconds(1))
>>                 {
>>                         /**
>>                          *
>>                          */
>>                         private static final long serialVersionUID =
>> -4790160167650215915L;
>>
>>                         @Override
>>                         public void onTimer(AjaxRequestTarget target)
>>                         {
>>                                 if (!loaderIsRunning && !deleterIsRunning)
>>                                 {
>>                                         target.add(loaderListContainer);
>>
>> resultsUpdateBehavior.stop(target);
>>                                         target.add(progress);
>>                                 //
>>  progressUpdateBehavior.stop(target);
>>                                 }
>>                                 else
>>                                 {
>>                                         target.add(loaderListContainer);
>>                                         target.add(progress);
>>                                 }
>>                         }
>>
>>                 };
>>                 add(resultsUpdateBehavior);
>>
>>
>>
>> --
>> View this message in context:
>> http://apache-wicket.1842946.n4.nabble.com/MultiThreading-issues-with-Wicket-tp4663325p4663394.html
>> Sent from the Users forum mailing list archive at Nabble.com.
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
>> For additional commands, e-mail: users-h...@wicket.apache.org
>>
>>
>

Reply via email to