Creating an Action
Creating an Action
Actions are unique in the world of Sitemap components. They don't implement the SitemapModelComponent and they merely exist to perform processing. For most business level processing, flowscript usually works better. However there are some systemic things we can implement using actions quite nicely. Actions are also unique in the sense that they do not need to be pooled. There is nothing in the contract that requires you to call multiple methods or do things in a certain order. Now a ThreadSafe component has its own challenges to ensure that the action is not a choke-point. Things to look out for are the use of synchronized when it is not necessary or trying to do too much in the action. Actions can be chained so keep things simple.
Actions have only one method to worry about. The sitemap invokes the method supplying several pieces of information and expects the return result of a java.util.Map. There are three outcomes from processing an action: the action succeeds and returns a java.util.Map, the action fails and return null, or the action throws an Exception. In the sitemap, an Action is invoked like this:
<map:act type="my-action" src="foo"> <map:generate src="{actionval}.xml"/> <map:serialize/> </map:act>
The sitemap only executes the elements internal to the map:act element when the Action returns a Map. If the Action returns null, that snippet is skipped. Using this to your knowledge you can provide confirmation pages that only show up when everything is processed successfully, otherwise we fall through to the remainder of the sitemap. Obviously we don't want to throw an exception if we can help it.
The sitemap provides the following elements:
- Redirector--to perform redirects within the Action based on your logic.
- SourceResolver--to find resources.
- Object Model--to gain access to the request, context, and session objects.
- Source--the string defined in the "src" attribute in the Sitemap.
- Parameters--the parameters defined in the Sitemap at runtime.
<map:choose pattern="**.xhtml" <map:generate src="{1}.xml"/> <map:act type="theme"> <map:transform src="{theme}2xhtml.xsl"/> </map:act> <map:serialize/> </map:choose/>
import java.util.Map; import java.util.HashMap; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.thread.ThreadSafe; import org.apache.excalibur.source.SourceResolver; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Request; import org.apache.cocoon.acting.Action; public class ThemeAction implements Action, ThreadSafe { private static final DEFAULT_THEME = "default"; public Map act( Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters params ) throws Exception { // .... the contents will be called out specifically below. } }
Request request = ObjectModelHelper.getRequest( objectModel ); String theme = request.getParameter("theme");
Ok, so we have the theme from the request object. Now lets check if it is empty and provide a default value if it is empty..
if ( null == theme || theme.length() == 0 ) { theme = DEFAULT_THEME; }
Next, let's check to see if the theme is the "xml" theme. We'll do it in a way that does not matter what case the "xml" value is. We return null in this case so that the transformer in the sitemap snippet above does not get added to the pipeline.
if ( "xml".equalsIgnoreCase(theme.trim()) ) { return null; }
Now we can assume that the value we have in the parameter "theme" is the name of a valid theme. We aren't going to do validation here, that's something you can have if you have inclination.
Map returnValues = new HashMap(); returnValues.put("theme", theme); return returnValues;
That's it! We're done. We have an action that does not have to be pooled, selects a theme, provides a default, and does not apply formatting if the theme is "xml".