Dear Wiki user, You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for change notification.
The following page has been changed by DavorHrg: http://wiki.apache.org/tapestry/Tapestry5HowToRunTaskInThread ------------------------------------------------------------------------------ - !IMPORTANT this code will work on java 1.6, and will not on java 1.5 until [https://issues.apache.org/jira/browse/TAPESTRY-2141 TAPESTRY-2141] is resolved (there is a workarround for java 5 on the bottom of this page) + !IMPORTANT because [https://issues.apache.org/jira/browse/TAPESTRY-2141 TAPESTRY-2141] is resolved in T5.0.11 + there are two versions of the code Questions about running tasks in separate thread were asked more than few times on the mailing list. The code is simple but some important things must be considered. - Most important thing is to call !ThreadCleanupHub.cleanup() after the thread is finished. + Most important thing is to call !PerthreadManager.cleanup() after the thread is finished. Other thing is that the separate thread will have different instances of any threaded services and will not have any user specific data. For example if you load an Hibernate entity inside the request thread and pass it to the task, the task will get a different Hibernate Session instance and will fail if you try to save the instance while the task is running (in a separate thread that is) - To save you some trouble I've created a simple service that runs tasks in a separate thread and makes sure ThreadCleanupHub.cleanup()is called. You can inject it anywhere and call: + To save you some trouble I've created a simple service that runs tasks in a separate thread and makes sure PerthreadManager.cleanup()is called. You can inject it anywhere and call: {{{#!java _threadSource.runInThread(new Runnable(){ public void run(){ @@ -39, +40 @@ } }}} - implementation (you can implement it way you like it, and even add a thread pool) + == T5.0.11 == + + implementation for T5.0.11 and above (T5.0.11-SNASPSHOT included).You can modify it any way you like it, and even add a thread pool. {{{#!java - import org.apache.tapestry.ioc.services.ThreadCleanupHub; + import org.apache.tapestry.ioc.services.PerthreadManager; import org.slf4j.Logger; public class ThreadSourceImpl implements ThreadSource { - private final ThreadCleanupHub _cleanupHub; + private final PerthreadManager _perthreadManager; private final Logger _logger; - public ThreadSourceImpl(ThreadCleanupHub cleanupHub, Logger logger){ - _cleanupHub = cleanupHub; + public ThreadSourceImpl(PerthreadManager perthreadManager, Logger logger){ + _perthreadManager = perthreadManager; _logger = logger; } @@ -74, +77 @@ } catch (Throwable e) { taskExceptionHandler.exceptionThrown(task, e); } finally { - _cleanupHub.cleanup(); + _perthreadManager.cleanup(); } } }).start(); } - + /** default exception handler that writes exception to the log */ private final TaskExceptionHandler defaultTaskExceptionHandler = new TaskExceptionHandler(){ public void exceptionThrown(Object task, Throwable exception) { @@ -92, +95 @@ }}} - == Workarround == + == before T5.0.11 == + + NOTICE: before T5.0.11 ThreadCleanupHub is used, and for T5.0.11 and later PerthreadManager replaces it. Please notice that this workarround fixes only the issue with !ThreadCleanupHub, but other !ThreadLocal dependant code might fail. + The workarround is also not needed for Java 6. - the bug mentioned for java 5 happens if !ThreadLocal.initialValue() happens inside another !ThreadLocal.initialValue(), this is exactly the case when any other threaded service is initialized. It is because !PerThreadServiceCreator uses ThreadLocal and inside initValue() generates a new instance of a service by calling a build method, and build method for !HibernateSesionManager adds a listener to !ThreadCleanupHub (which gets initialized and calls initialValue()) and things get messed up... I'm probably not makin much sense ... so here's the workarround + The bug mentioned for java 5 happens if !ThreadLocal.initialValue() happens inside another !ThreadLocal.initialValue(), this is exactly the case when any other threaded service is initialized. It is because !PerThreadServiceCreator uses ThreadLocal and inside initValue() generates a new instance of a service by calling a build method, and build method for !HibernateSesionManager adds a listener to !ThreadCleanupHub (which gets initialized and calls initialValue()) and things get messed up... I'm probably not makin much sense ... so here's the workarround declare a dummy listener inside !ThreadSourceImpl: {{{#!java --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
