There are two parts to webwork actions. There's the JSP, and there is the Java class. The JSP looks like this:
<ww:action id="myActionObj" name="'myActionType'"/>
For the sake of clarity, I haven't shown how the name attribute wires through XWork to Spring: there's a diagram in an earlier post. I don't know why you need single quotes around it.
The Java class looks like this:
import com.opensymphony.xwork.ActionSupport;
public class MyAction extends ActionSupport
{
public String execute()
{
return SUCCESS;
}
}A webwork action is roughly equivalent to a droplet, only instead of calling service(), it calls execute(). However, there is an important difference between droplets and actions. An ATG droplet is typically stateless and global: you define a single component in Nucleus, set up all the global references in the properties file, and pull all the session scoped and request scoped objects through request.resolveName("myComponent").
As best as I can tell, Webwork actions are request scoped. That is, there's a new instance of the class created on every request. This is because instead of setting output parameters on DynamoHttpServletRequest, the properties of the action itself are used as output parameters.
This means that where you would normally do:
public void service(DynamoHttpServletRequest pRequest, DynamoHttpServletResponse pResponse)
throws IOException, ServletException
{
pRequest.setParameter("value", "I am an output parameter");
pRequest.serviceParameter("output", pRequest, pResponse);
}you would do:
public String execute()
{
setValue("I am an output parameter");
return SUCCESS;
}and then in the JSP page you would do:
<ww:action id="myActionObj" name="'myActionType'"/> <ww:property value="#myActionObj.value"/>
Note that the action object hangs around at least for the lifetime of the page render. If you are using the same action multiple times in the same page, you should use different ids.
So that takes care of output parameters. How do you get input into a Webwork action?
You use the ActionContext class. This class uses ThreadLocal behind the scenes to give you access to your request and session state.
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.ActionSupport;
import javax.servlet.http.*;
import java.util.*;
public class MyAction extends ActionSupport
{
public String execute()
{
// if you want raw access to the request...
HttpServletRequest request = ServletActionContext.getRequest();
Map httpParameters = request.getParameters();
// ... or if you want to remove any dependency on servlets...
ActionContext context = ActionContext.getContext();
Map parameters = context.getParameters();
return SUCCESS;
}
}Now, the following section I cant speak to. Sebastiano defined the following interceptors here in xwork.xml, so I have no idea what they do or why he defined it:
<interceptors>
[
]
<!-- a small stack used for the actions in ww:action tags -->
<interceptor-stack name="simpleStack">
<interceptor-ref name="prepare" />
<interceptor-ref name="servlet-config" />
<interceptor-ref name="params" />
</interceptor-stack>
</interceptors>
<!--
Anything you would normally use for display is defined with the simple stack.
Here, we count an array.
-->
<action name="countArrayAction" class="countArrayAction">
<interceptor-ref name="simpleStack"></interceptor-ref>
</action>
We can then get down to counting how many items are in an array. Using this pattern, parameters can be defined explicitly:
<ww:action id="countArrayObj" name="'countArrayAction'"> <ww:param name="'array'" value="#someArray"/> </ww:action>
The code for this goes:
public String execute()
{
ActionContext context = ActionContext.getContext();
Map parameters = context.getParameters();
// Note that while this is a contrived example, Webwork does like to return
// string parameters as String[], even if there's only one of them passed in.
Object[] randomParamArray = (Object[]) parameters.get("array");
int count = (randomArray == null) 0 ? randomArray.length;
setCount(count);
return SUCCESS;
}And that's Webwork actions in a nutshell.
You can simply use the setters in your action - so if you have a setArray(String[] array), you just have to add a request parameters to your url (blah.action?array=foo&array=bar). XWork will take care of the conversion for you and set the values in the action for you.
If you want use the ww:action tag, you can simply place a couple of ww:param tag inside it, and it will do exactly the same. No need to get the ServletRequest yourself.
Btw, 2.2 is almost out with some big improvements. Might wanna check it out ;)
I defined this stack to have XWork interceptors applied to my actions. It's code that XWork executes before and/or after your action, in the example you cited I put in servlet-config to be able to retrieve the webapp ServletContext from my action, and params to be able to retrieve the values passed thru ww:param tags. I forgot why I put in the prepare interceptor, but I'm sure I had a good reason to... I defined this minimal stack to apply only those 3 interceptors to the action I call with the ww:action tag (the droplet-like actions), since I didn't need to do all the processing done by the more complex stacks.
See http://www.opensymphony.com/xwork/wikidocs/Interceptors.html for the interceptor doc.
So, in summary, you can drop the prepareInterceptor and servlet-config. Static params is only necessary if you want to set some variables in your xwork configuration file.
Hope that helps - and if not, visit the WW forum - bunch of very friendly zealots over there ;)
.............
// if you want raw access to the request...
HttpServletRequest request = ServletActionContext.getRequest();
Map httpParameters = request.getParameters();
// ... or if you want to remove any dependency on servlets...
ActionContext context = ActionContext.getContext();
Map parameters = context.getParameters();
..................
Just create public setters and getters. Its much easier and you can test all your action classes easily in JUnit.
@Jason, I at least do not want to always go thru the dispatcher, sometimes calling an action from the middle of a page is very useful.