Sometimes, it is useful to write a custom view mapping. One of the reasons for this would be, for example, to allow for different mechanisms for looking up views, or different behaviour for determining what constitutes a view for a particular action.
The example below illustrates how a custom view mapping can be plugged in to allow for commands specified as parameters to be treated as regular command URL's in terms of views. The desired functionality is to be able to specify myaction!mycommand=foo.jsp in the view properties/XML file, and then have foo.jsp be used as the view when request /myaction.action?command=mycommand
Writing your own ViewMapping involves implementing the webwork.dispatcher.ViewMapping interface.
ViewMappingImpl.java:
public class ViewMappingImpl implements ViewMapping {
public Object getView( String anActionName, String aViewName ) {
return ...;
}
}
WebWork internally uses the webwork.dispatcher.DefaultViewMapping class. A recommended practice is to have your class extend it, and overriding getView() to hook in your behaviour. This means, however, that your class will be first in the default sequence of ViewMapping delegation that WebWork uses. This sequence is:
- ConfigurationViewMapping (which is the class in front of views.properties/actions.xml)
- CachingViewMapping (caches view results to avoid a potentially expensive lookup)
- DynamicViewMapping (Allows for resolving variables in views like ${foo})
Since CachingViewMapping and DynamicViewMapping are wrappers around another ViewMapping, they can easily be used to produce a different order of delegation.
Back to the example at hand. We'd like to specify a view mapping that is command aware with regards to commands specified as parameters. The implementation would be something like this:
CommandAwareViewMapping.java:
public class CommandAwareViewMapping implements ViewMapping {
private ViewMapping delegate;
public CommandAwareViewMapping( ViewMapping delegate ) {
this.delegate = delegate;
}
public Object getView( String actionName, String viewName ) {
if (
ActionContext.getValueStack().findValue( "." ) instanceof CommandDriven
&& ActionContext.getParameters().containsKey( "command" ) &&
actionName.indexOf( '!' ) == -1
) {
String command = ((String[]) ActionContext.getParameters().get(
"command" ))[0];
return delegate.getView( actionName + '!' + command, viewName );
} else {
return delegate.getView( actionName, viewName );
}
}
}
Here is an example of how to implement a seamless redirection mechanism. It works by re-writing the url to views named redirect with a call to the standard redirect action. The code looks like the following:
RedirectViewMapping.java:
public class RedirectViewMapping implements ViewMapping {
private ViewMapping delegate;
private String redirectionPrefix;
public RedirectViewMapping( ViewMapping delegate ) {
this.delegate = delegate;
/* this implies that the WebWork ServletDispatcher is mapped to *.jspa
and that action suffix is "jspa"
and that webwork.properties declares the standard redirect action
Ideally this is read from some property store */
redirectionPrefix = "/redirect.jspa?url=";
}
public Object getView( String anActionName, String aViewName ) {
Object view = delegate.getView( anActionName, aViewName );
if ("redirect".equals( aViewName )) {
view = redirectionPrefix + view;
}
return view;
}
}
Using it involves binding your redirection targets to your actions using the redirect view name like the following (using views.properties):
views.properties:
foo.CreateFoo.redirect = /foo/list.jsp
or (using actions.xml):
actions.xml:
<action name="foo.CreateFoo">
<view name="redirect>/foo/list.jsp</view>
</action>
In both cases, we would also like to modify the delegation order, so the ViewMapping looks something like this:
MyDefaultViewMapping.java:
public class MyDefaultViewMapping implements ViewMapping {
private ViewMapping delegate;
public DefaultViewMapping() {
delegate = new ConfigurationViewMapping();
delegate = new CachingViewMapping( delegate );
delegate = new CommandAwareViewMapping( delegate );
delegate = new RedirectViewMapping( delegate );
}
public Object getView( String actionName, String viewName ) {
return delegate.getView( actionName, viewName );
}
}
This is then easily hooked into WebWork by adding the following line to webwork.properties:
webwork.properties:
webwork.viewmapping=MyDefaultViewMapping
redirect.jspa=webwork.action.standard.Redirect