Action mappings is a feature that will benefit greatly from a rewrite and inclusion of other capabilities. By ActionMappings, I mean code that extracts from a URI the following:
- The namespace (xwork) or module prefix (struts)
- The action name
- Any extra parameters
While the first two are obvious, the last isn't necessarily. This is a feature that is currently in development for the next version of WebWork2. For WW2, ActionMapper is an interface which allows implementations to extract the above information. One particular implementation, CoolActionMapper provides greater ReST-style support by allowing parameters to be embedded into the URL, so the framework could support the pattern:
to allow url's like:
There are a couple of reasons why I'd suggest copying the code rather than using it unmodified:
- It is tied to the servlet API and I've been trying hard to not require the core to know about servlets
It assumes one servlet mapping, and I believe we need to support multiple. As for this writing, the mappings can be retrieved from the WebContext
- Related to above, ours would need to know about the mappings in order to recreate a URI from and action, namespace, and servlet mapping
Do we follow WW2 and use an ActionMapping interface or just embed the information directly into the web context?
- If we create an interface, we'd have to add a "mapping" property to store the optional servlet mapping
I'd assume we'd pass in a WebContext rather than a servlet request
How do we integrate any extracted parameters into the WebContext? The request parameters map is read-only yet we want smooth integration of the parameters to the rest of the app and it seems cumbersome to require every piece of code to check in two places for parameters.
- Again, shouldn't require servlet, although implementations certainly will
- Support for multiple servlet mappings
Comment by rich on Thu Jul 7 22:59:42 2005
Having this capability sounds great to me.
It does raise a general question: should we try to influence/contribute to other projects in order to fulfill our needs? e.g., is this something that could be abstracted and pushed into xwork?
- Why do we need to support multiple servlet mappings?
I like the idea of wrapping up action information into an ActionMapping, since it seems like there could end up being a lot there that could get lost in the shuffle of the general context. Also, maybe there will be different types of ActionMappings? It would still hang off the context (getActionInfo()?).
Assuming we have an extension of WebContext, can't we have this combine the underlying parameter map with the params from the ActionMapper?
Comment by mrdon on Fri Jul 8 09:17:27 2005
Good point, and to that end, I've invited Jason and Patrick from WebWork/XWork to join the discussion. They are very interested in working together to develop solutions that meet both our needs. While our projects will remain separate, I'm hoping we can use common infrastructure and ideas wherever possible.
- One usecase that I've run across is trying to have both an HTML and ReST interface for the same app. The HTML interface is fine with *.do, but the ReST is cleaner with /rest/* If we allowed multiple instances of Ti, I could just use two servlets, but combining them into one lets me share data easier and takes less memory.
- Sure, what different types do you have in mind?
Yes, and this is what WebWork2 does when it creates the ActionContext. Of course by extension you mean a whole other class as we couldn't directly extend WebContext w/o extending all possible subclasses (servlet, faces, portlet, etc).
Comment by rich on Fri Jul 8 13:58:28 2005
That's excellent. The more of an integration project this is, the better, as far as I'm concerned.
- I see. Mainly to support both path-mapping and extension-mapping. I know that from a tooling point of view, it would be much easier if we defined one extension and one path prefix. Is there a compelling reason to offer more flexibility than that?
In Beehive there are two types of action mappings: simple actions and method-based actions. Simple actions either map directly to a path, or go through a script expression evaluator to go through a set of conditions/results. Basically, the shape of metadata is different for the two types of actions. Just making sure -- the ActionMapping is still the way you'd access an action's metadata at runtime?
Oh, right. I was talking about extending WebContext and wrapping the underlying one, but that's not pretty since ServletWebContext, etc. expose properties you'd be interested in. I assume we should extend ActionContext and expose WebContext as a property, along with our other context properties. Sound correct? An alternative would be to leave WebContext out of the ActionContext, and ensure that our single context had everything you need... but this would cause it to reimplement much of what Chain did.
Comment by mrdon on Sun Jul 10 19:14:47 2005
- I don't mind if we suggest one prefix/extension mapping, but I'd like the internal framework to be capable of more. The code I just committed allows multiple servlet mappings - source:src/java/org/apache/ti/config/mapper/ServletActionMapper.java
Well, ActionMapping in this context is different than Struts 1.x. In this case, all an ActionMapping does is capture and action name and namespace. XWork's ActionConfig is like the ActionConfig of Struts 1.x As for two types of action mappings, I was kinda hoping to just go to one type, i.e. Ruby on Rails. If we can keep annotation/tag overhead low, even simple actions could be a controller method.
Comment by plightbo on Sun Jul 10 20:15:43 2005
Hey guys -- Patrick Lightbody here. Just joining in on the conversation. One thing to keep in mind is weighing between tool support and supporting flexible URLs. At this point, our plans in WebWork are up in the air. Pasted below is a discussion I had with Don over email about this:
Speaking of the ActionMapper -- I'm not done with it by any means and very open to feedback. One of the challenges I have is not mapping from "request" -> action, but rather action -> "request" (url).
For example, suppose you have a form that lets you edit a person. In a RESTful design, that would be a PUT to /people/1. Or, with the "cool" mapper, it would be a POST to /person/1`, where 1 is the person ID. But suppose the form has a drop down form element that is a selection of "persons" you can edit (say, it is a combobox and the textfield becomes the name of the person). Now the <form> element needs to submit to a dynamic location (/person/1, /person/2, etc).
Even when the URL is not dynamic, mapping a form (in WW it is <ww:form>) is not so easy. Using a *.action extension mapping, this:
<ww:form action="updatePerson"> <ww:hidden name="id"/> <ww:textfield label="Email address" name="email"/> ... </ww:form>
produces this HTML (or close to it):
<form name="updatePerson" action="updatePerson.action"> <table> <input type="hidden" name="id" value="123"/> <tr> <td>Email address</td> <td><input name="email" value="email@example.com"/> </tr> ... </table> </form>
So in this situation, mapping the action name ("updatePerson") to the URL ("updatePerson.action") is very easy. But in the cool or restful way, the ActionMapper would have to know the parameters of the form ("id" -> "123") and construct a proper HTML output:
<form name="updatePerson" action="/person/123"> <table> <tr> <td>Email address</td> <td><input name="email" value="firstname.lastname@example.org"/> </tr> ... </table> </form>
Comment by rich on Mon Jul 11 09:41:59 2005
Response to Don:
- Sounds good -- it's easy for the runtime to be aware of multiple mappings.
- Having one config is OK, but I don't think we should sacrifice wholly-annotation-based actions. I'm all for low overhead, but we did go through a round of every-action-is-a-method in Beehive, and it's just a pain. Even if there were no annotations on an action method, it's still just cleaner to do this:
- Definitely -- sounds good.
Comment by rich on Mon Jul 11 09:49:46 2005
Patrick/Don, I've got a basic question: what's the main case for generating HTML that accesses actions RESTfully? I can imagine exposing actions/flow in this way for a back-channel XmlHttpRequest (which doesn't have some of the form issues Patrick is raising, and which is what I'd imagine as the main use initially), but I don't see how it would be helpful on the other side.