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
<action name="longrunning" class="com.foo.frontend.action.test.LongRunningAction">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="execAndWait"/>
<result name="wait" type="freemarker">/WEB-INF/content/action/test/longrunning/status.ftl</result>
<result name="error" type="freemarker">/WEB-INF/content/action/test/longrunning/terminated.ftl</result>
<result name="success" type="freemarker">/WEB-INF/content/action/test/longrunning/success.ftl</result>
</action>
<action name="terminatelongrunning" class="com.foo.frontend.action.test.TerminateLongRunningAction">
<result name="success" type="freemarker">/WEB-INF/content/action/test/longrunning/terminatesuccess.ftl</result>
</action>
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
public interface Terminatable
{
public 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
public class LongRunningAction extends ActionSupport implements Terminatable
{
private boolean terminated=false;
private int i=0;
public String execute()
{
while( i++ < 100 )
{
if( terminated )
{
return ERROR;
}
try
{
Thread.sleep(1000);
}
catch( InterruptedException ie )
{
}
}
return SUCCESS;
}
public int getProgress()
{
return i;
}
public void terminate()
{
this.terminated = true;
}
}
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
import java.util.Map;
import com.opensymphony.webwork.interceptor.BackgroundProcess;
import com.opensymphony.webwork.interceptor.SessionAware;
import com.opensymphony.xwork.ActionSupport;
public class TerminateLongRunningAction extends ActionSupport implements SessionAware
{
private String name = "__execWaitlongrunning";
private Map session;
public String execute()
{
BackgroundProcess bp = (BackgroundProcess) session.get( name );
if( bp==null || bp.getAction()==null || !(bp.getAction() instanceof Terminatable) )
{
return ERROR;
}
Terminatable t = (Terminatable) bp.getAction();
t.terminate();
return SUCCESS;
}
public void setSession( Map session )
{
this.session = session;
}
}
This action terminates the ExecuteAndWait action simply informing it through the terminate() method.
The freemarker pages
<html>
<head>
<title>Please wait</title>
<meta http-equiv="refresh" content="1;url=<@ww.url includeParams="all" />"/>
</head>
<body>
Progress: ${Session['__execWaitlongrunning'].action.progress}%
</body>
</html>
<html>
<body>
Exited normally.
</body>
</html>
<html>
<body>
Terminated.
</body>
</html>
<html>
<body>
Process didn't exist or something like that.
</body>
</html>
<html>
<body>
The background action was signalled to terminate.
</body>
</html>
Special thanks to Lens that contributed this sollution in WebWork's forum