Overview
The idea is to have 2 actions, one that execute the ExecuteAndWait action and another one that teminates the already running ExecuteAndWait action. The ExecuteAndWait action will needs to implement a Terminatable interface allowing it to be identified by the terminating action and hence be able to be informed to terminate itself through the terminate() method ( from Terminatable interface ).
XWork.xml configurations
1 2 3 4 5 6 7 8 9 10 |
<span class="code-tag"><action name=<span class="code-quote">"longrunning"</span> class=<span class="code-quote">"com.foo.frontend.action.test.LongRunningAction"</span>></span> <span class="code-tag"><interceptor-ref name=<span class="code-quote">"defaultStack"</span>/></span> <span class="code-tag"><interceptor-ref name=<span class="code-quote">"execAndWait"</span>/></span> <span class="code-tag"><result name=<span class="code-quote">"wait"</span> type=<span class="code-quote">"freemarker"</span>></span>/WEB-INF/content/action/test/longrunning/status.ftl<span class="code-tag"></result></span> <span class="code-tag"><result name=<span class="code-quote">"error"</span> type=<span class="code-quote">"freemarker"</span>></span>/WEB-INF/content/action/test/longrunning/terminated.ftl<span class="code-tag"></result></span> <span class="code-tag"><result name=<span class="code-quote">"success"</span> type=<span class="code-quote">"freemarker"</span>></span>/WEB-INF/content/action/test/longrunning/success.ftl<span class="code-tag"></result></span> <span class="code-tag"></action></span> <span class="code-tag"><action name=<span class="code-quote">"terminatelongrunning"</span> class=<span class="code-quote">"com.foo.frontend.action.test.TerminateLongRunningAction"</span>></span> <span class="code-tag"><result name=<span class="code-quote">"success"</span> type=<span class="code-quote">"freemarker"</span>></span>/WEB-INF/content/action/test/longrunning/terminatesuccess.ftl<span class="code-tag"></result></span> <span class="code-tag"></action></span> |
Action longruning will be the action executing the ExecuteAndWait action where as action terminatelongrunning will be the action to terminate the _ExecuteAndWait action.
Terminatable interface
1 2 3 4 |
<span class="code-keyword">public</span> <span class="code-keyword">interface</span> Terminatable { <span class="code-keyword">public</span> void terminate(); } |
ExecuteAndWait action wish to be informed about its termination such that it could ends itself gracefully should implement this interface.
The ExecuteAndWait Action
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<span class="code-keyword">public</span> class LongRunningAction <span class="code-keyword">extends</span> ActionSupport <span class="code-keyword">implements</span> Terminatable { <span class="code-keyword">private</span> <span class="code-object">boolean</span> terminated=<span class="code-keyword">false</span>; <span class="code-keyword">private</span> <span class="code-object">int</span> i=0; <span class="code-keyword">public</span> <span class="code-object">String</span> execute() { <span class="code-keyword">while</span>( i++ < 100 ) { <span class="code-keyword">if</span>( terminated ) { <span class="code-keyword">return</span> ERROR; } <span class="code-keyword">try</span> { <span class="code-object">Thread</span>.sleep(1000); } <span class="code-keyword">catch</span>( InterruptedException ie ) { <span class="code-comment">// blah </span> } } <span class="code-keyword">return</span> SUCCESS; } <span class="code-keyword">public</span> <span class="code-object">int</span> getProgress() { <span class="code-keyword">return</span> i; } <span class="code-keyword">public</span> void terminate() { <span class="code-keyword">this</span>.terminated = <span class="code-keyword">true</span>; } } |
The ExecuteAndWait action is basically a conditional loop that loop indefintely until it’s informed to ends itself by breaking the loop.
The action to terminate ExecuteAndWait action
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<span class="code-keyword">import</span> java.util.Map; <span class="code-keyword">import</span> com.opensymphony.webwork.interceptor.BackgroundProcess; <span class="code-keyword">import</span> com.opensymphony.webwork.interceptor.SessionAware; <span class="code-keyword">import</span> com.opensymphony.xwork.ActionSupport; <span class="code-keyword">public</span> class TerminateLongRunningAction <span class="code-keyword">extends</span> ActionSupport <span class="code-keyword">implements</span> SessionAware { <span class="code-keyword">private</span> <span class="code-object">String</span> name = <span class="code-quote">"__execWaitlongrunning"</span>; <span class="code-keyword">private</span> Map session; <span class="code-keyword">public</span> <span class="code-object">String</span> execute() { BackgroundProcess bp = (BackgroundProcess) session.get( name ); <span class="code-keyword">if</span>( bp==<span class="code-keyword">null</span> || bp.getAction()==<span class="code-keyword">null</span> || !(bp.getAction() <span class="code-keyword">instanceof</span> Terminatable) ) { <span class="code-keyword">return</span> ERROR; } Terminatable t = (Terminatable) bp.getAction(); t.terminate(); <span class="code-keyword">return</span> SUCCESS; } <span class="code-keyword">public</span> void setSession( Map session ) { <span class="code-keyword">this</span>.session = session; } } |
This action terminates the ExecuteAndWait action simply informing it through the terminate() method.
The freemarker pages
1 2 3 4 5 6 7 8 9 |
<span class="code-tag"><html></span> <span class="code-tag"><head></span> <span class="code-tag"><title></span>Please wait<span class="code-tag"></title></span> <span class="code-tag"><meta http-equiv=<span class="code-quote">"refresh"</span> content=<span class="code-quote">"1;url=<@ww.url includeParams="</span>all<span class="code-quote">" /></span>"</span>/> <span class="code-tag"></head></span> <span class="code-tag"><body></span> Progress: ${Session['__execWaitlongrunning'].action.progress}% <span class="code-tag"></body></span> <span class="code-tag"></html></span> |
1 2 3 4 5 |
<span class="code-tag"><html></span> <span class="code-tag"><body></span> Exited normally. <span class="code-tag"></body></span> <span class="code-tag"></html></span> |
1 2 3 4 5 |
<span class="code-tag"><html></span> <span class="code-tag"><body></span> Terminated. <span class="code-tag"></body></span> <span class="code-tag"></html></span> |
1 2 3 4 5 |
<span class="code-tag"><html></span> <span class="code-tag"><body></span> Process didn't exist or something like that. <span class="code-tag"></body></span> <span class="code-tag"></html></span> |
1 2 3 4 5 |
<span class="code-tag"><html></span> <span class="code-tag"><body></span> The background action was signalled to terminate. <span class="code-tag"></body></span> <span class="code-tag"></html></span> |
Special thanks to Lens that contributed this sollution in WebWork’s forum