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 >> >> >