Helper Actions
Here's one way to bind FreeMarker template fragments to Stripes view helpers. (JSP could also be used, but the syntax here is for FreeMarker.)
For example, say you want to include a "Recent Posts" html block on a variety of different pages. You can create an action that's just responsible for feeding the needed objects to that view, and create a corresponding FreeMarker template that's just responsible for rendering that html block.
In the FreeMarker template fragment, bind it to a Stripes action with useActionBean
:
<@stripes.useActionBean beanclass="path.to.package.TheAction" event="view" var="recentPosts"/>
After setting the needed variables, the "view" event handler would just return null for its resolution. The FreeMarker fragment can access the getters using something like: ${recentPosts.variable
}
The resulting Recent Posts fragment would then be placed on other pages with
#include or #import.
Scripting with Stripes
I've build a new abstract ActionBean class to execute scripts interpretable by BSF compatiple scripting engines.
Therefore you need the bsf library in your classpath if you want to use the BSFActionBean explained here.
Configuration
The BSFActionBean requires some additional components. Mainly this is a ScriptResolver implementation which
provides the requested scripts to be executed to the ActionBean. The integration is mainly a result of playing around
with the internal of Stripes core. The library provides an extended version of the RuntimeConfiguration of Stripes.
I see that this setup is not really comfortable, since you have to configure the new RuntimeConfiguration to use in
the StripesFilter configuration using the following initialization parameter:
<init-param> <param-name>Configuration.Class</param-name> <param-value>org.syracus.stripes.config.RuntimeConfiguration</param-value> </init-param>
I now see, that this nothing to be held up in near future. If the BSFScripting facitilites are really of interest, i will
find some time to change this.
But back to the configuration required for the BSFActionBean.
After the new RuntimeConfiguration is setup, you need to specify how scripts are resolved. At the moment there are two implementations
provided. A non-caching version named ResourceScriptResolver and a caching version with reloading support.
Booth resolvers need to know where to look for the script files to load. The default is the root of web application context. But
in most cases it's more usefull to have all scripts located in a specific directory like /WEB-INF/scripts and don't have to specify
the full qualified path everytime. So you can provide a comma separated list of locations where the resolvers look for requested scripts
using
<init-param> <param-name>ResourceScriptResolver.ResourcePrefix</param-name> <param-value>/WEB-INF/scripts,/WEB-INF/testScripts</param-value> </init-param>
The caching version CachingResourceScriptResolver additionally provides two optional configuration parameters.
Name | Value |
---|---|
CachingResourceScriptResolver.CachingEnabled | Defaults to true. Specifies if the caching mechanism should be used. |
CachingResourceScriptResolver.ReloadEnabled | Defaults to true. Specifies if the Scripts should be checked for modifications. |
Although this is more configuration work than the average stripes user is used to do i think it's not too hard to get done
Implementation
Now you can use the scripting facilities in your application. As in the Best Practice section of Stripes Home described you should
implement a base action class for the context assignment. For your script enabled actions you should therefore create an application wide
base implementation like
public class MyScriptAction extends BSFActionBean { private MyActionContext context; public MyActionContext getContext() { return( this.context ); } public void setContext( ActionBeanContext context ) { this.context = (MyActionContext)context; } }
The BSFActionBean provides two handler methods.
eval()
The evaluation of scripts requires that you return a Resolution instance from your scripting code. If you don't return
a proper resolution the context specific sourcePageResolution is used to forward to the view.
exec()
The execution never expects a return value from your scripts and therefore always forwards to the sourcePageResolution.
Usage
To call you scripts assuming the MyScriptAction is bound to the URL /actions/script.action
you can call /actions/script.action?eval=/WEB-INF/scripts/hello.bsh
. If you configured the resource location using ResourceScriptResolver.ResourcePrefix
you could simply write /actions/script.action?eval=hello.bsh
.
With your scripting code you will have access to the following properies exported to the scripting context.
Name | Description |
---|---|
request | The HttpServletRequest object. |
response | The HttpServletResponse object. |
application | The ServletContext object. |
context | The current ActionBeanContext. |
action | The ActionBean itself. |
Property binding
The greate property binding and validation features collide a little bit with the scripting. So if you need complicated
object web binding and validation you should think about it's really a good idea to implement this as script at least.
What i'm neverthelss thinking about is to provide an annotation like @ScriptBean which you can apply to getter methods in your
ActionBeans. This would allow to populate those annotated ActionBean properties into the scripting context before the
script is actually executed or evaluated. But since this is about to come you can do something like
public class PopulatedScriptAction extends MyScriptAction { private Integer value; public void setValue( Integer value ) { this.value = value; } public Integer getValue() { return( this.value }; } }
and access the value property in your scripts using
... value = $action.getValue();
For the interested ones out there you can download the binary and source distributions from
syracus-stripes