Interesting.. You've take a similar approach to what I've done in the
past, with some caching of the Methodsthat I didn't do.. Here is what I
did in text form (no diags available right now):

Create a base action class that implements the perform() method and
offers an abstract method handleRequest( UserRequest ) that the subclass
must implement. UserRequest is created and populated in the perform()
and has things like the request, response, and other needed references.
It also offers methods to replace the request.getParameter() and
request.getAttribute(), like: userRequest.getParameter( key, default ),
userRequest.getAttribute( key, default ), and userRequest.getFormBean().
This allows me to later adapt the action subclass to work from within a
unit test or swing application (if the pages map to panels the same)
without binding the concrete action class to HTTP. I've always believed
that this abstraction would have been helpful in Struts, even though the
action is the HTTP glue - its easy and just makes sense, since we mostly
need access to a HashMap rather than anything HTTP specific anyway. I
know mock objects are out there for testing struts and I've used them -
very nice!

The next thing I did was to extend this base action class into a
WizardAction and implement the new handleRequest() method to look for a
predefined button name that is used to construct a dynamic method call..
So, if the button pressed was 'create', then it would call
processCreateEvent(UserRequest request). Same goes for things like Next,
Back, Cancel, and other types of multi-button forms. This allows me to
remove large if or switch statements to determine which button was
pressed and tackle that logic should I want 1 action for multiple
buttons on a page. 

I can't wait until JDK 1.5 where we can start attaching metadata to a
method and get to it via runtime calls (ala C#), which would allow me to
tag a method with its required roles and have the code find those roles
and do the checks - no more XML config -> whatever mapping files and no
more custom access control methods!

James



> -----Original Message-----
> From: Philipp K. Janert [mailto:[EMAIL PROTECTED]] 
> Sent: Tuesday, September 03, 2002 9:48 AM
> To: [EMAIL PROTECTED]
> Cc: [EMAIL PROTECTED]
> Subject: Call for comments: Method dispatching and access 
> control framework.
> 
> 
> 
> Dear All!
> 
> I would like to invite comments on some extensions I have 
> made to get around some limitations in the Struts framework.
> 
> When working with Struts, I quickly developed the following 
> wishlist of things that I wanted Struts to do:
> 
> 1) Be able to bind a user request to an arbitrary function
>    in an Action class, not just to perform().
> 
> 2) Be able to bind each button in a form with multiple submit
>    buttons to an arbitrary function (such that control is
>    transferred to a specific functions based on which button
>    was clicked).
> 
> 3) Provide the ability to restrict access to actions as part
>    of the configuration (ie in struts-config.xml).
> 
> 4) Reduce the number of runtime String lookups (such as when
>    writing: mapping.findForward( "success" ) ).
> 
> I have written a few classes that provide items 1) - 3), and 
> also suggest a step towards dealing with item 4).
> 
> The code is available on my website at:
>     http://www.beyondcode.org/projects
> There you can also find Javadoc, as well as a little example 
> application, meant to demonstrate all of the above features.
> 
> Feel free to take a look and let me know what you think!
> 
> In the following, I am going to provide a more detailed 
> description and rationale for my dispatcher framework.
> 
> interface DispatcherMapping
> ===========================
> 
> When attempting to dispatch requests to individual methods 
> within an action class, additional mapping information is 
> necessary. Fortunately, the struts-config DTD allows for the 
> <set-property> element, so that such information can be 
> included in struts-config.xml without having to change the 
> DTD. The interface DispatcherMapping provides two additional
> properties: "method" (ie the name of the method that this 
> action should be dispatched to) and "access" (which can be 
> used to implement access control to individual actions/methods).
> 
> Any ActionMapping implementation to be used with the present 
> dispatcher framework needs to implement this interface. 
> By making this functionality available as an *interface*, 
> rather than as a specific mapping *class*, applications are 
> still free to use other mapping implementations, as needed.
> 
> See the section on "Standard Forwards" below for the other 
> properties defined in this interface.
> 
> class MethodDispatcherAction
> ============================
> 
> This is the central class of the framework. On startup (ie in 
> its constructor) it reflects itself and builds up a HashMap
> of member functions having the same signature as the perform 
> method. It is to these functions that requests can be dispatched.
> 
> Of course, this class takes a major leaf from 
> org.apache.struts.actions.DispatchAction. However, several 
> things are different: introspection is "eager" rather than 
> "lazy". Since the HashMap is accessed read-only once the ctor 
> has completed, we can dispense w/ synchronization (??!?). 
> This also allows to check at boot-time, whether all required 
> methods are found (more on this below). Finally, this class 
> requires the mapping to be used to implement 
> DispatcherMapping, because it expects the additional properties.
> 
> (Note: org.apache.struts.actions.DispatchAction puts the 
> method name to dispatch to onto the request as request 
> parameter. I am unhappy with the actual names of my methods 
> being accessible to the client. I also wanted *actions* (or 
> rather action mappings) to be dispatchable to methods, not 
> *requests*.)
> 
> Furthermore, MethodDispatcherAction provides access control 
> on the granularity level of individual member functions (ie 
> individual actions). Before the request is dispatched, the 
> member function hasAccess( dispatcherMapping, request ) is 
> called. The default 
> implementation of this method always returns true. Application 
> developers can override this method to implement their own access 
> control. Note that this method has access to the "access" 
> property from struts-config.xml, as well as to the 
> HttpSession (through request). The access property can be 
> used to hold an access mask, which must match some 
> information contained either in the request or on the session.
> 
> class FormDispatcherAction
> ==========================
> 
> This class is meant to be used with forms with multiple
> submit buttons. It does no work itself, it just forwards 
> incoming requests to other actions. As opposed to the 
> MethodDispatcherAction above, it is not meant to be extended 
> for individual applications.
> 
> Each submit button generates a request parameter, the name
> of which is the value of the "property" attribute in the JSP. 
> The FormDispatcherAction class looks for a local 
> ActionForward with the same name, and dispatches the request 
> to this action, as a local forward (ie redirect=false).
> 
> There is no access control in this class - it is expected
> that all forwards from this class are dispatched to 
> subclasses of MethodDispatcherAction.
> 
> class DispatcherMappingImpl
> ===========================
> 
> This is a ready-to-use implementation of the 
> DispatcherMapping interface mentioned above. Otherwise it 
> just extends the original ActionMapping class.
> 
> See the section on "Standard Forwards" below for more info.
> 
> class DispatcherTestServlet
> ===========================
> 
> This is an alternate ActionServlet, which overrides the 
> initMapping() method and tries to perform boot-time 
> consistency checks on it (cf. below).
> 
> Appendix: Standard Forwards
> ===========================
> 
> It seems that there are quite a few places in Struts where 
> information is available (and could therefore be checked) at 
> compile time (or at least at boot time), but is not accessed 
> until actual run time! Examples are: findForward() (String 
> lookup), action mappings (consistency between JSP and 
> struts-config), bean-property/request parameter names 
> (consistency between JSP and code), etc.
> 
> Ever made an innocuos change to a JSP, exercised the 
> application (manually!) to the respective page, only to 
> have the page blow up on you because you made a typo 
> (so that no corresponding bean property could be found)?
> That's what I mean!
> 
> I sometimes dream of a lint-like tool that I could run
> over an entire Struts application and that would flag all 
> inconsistencies between classes, JSPs, struts-config, and the 
> file system (ie referring to a non-existent JSP in 
> struts-config) for me.
> 
> While a complete compile-time checking tool might be
> a challenge, some boot-time consistency checking seems 
> possible.
> 
> DispatcherMapping and DispatcherTestServlet attempt to
> show how this could be done for the case of findForward().
> It seems to me that there are 4 standard forwards which
> are appropriate for most actions: "success", "failure", 
> "error", and "access denied" (the latter makes sense only in 
> the context of access control to individual actions). 
> DispatcherMapping therefore provides eponymously named 
> methods. The DispatcherTestServlet examines all action 
> mappings at boot time, and reports those for which any of the 
> standard forwards return null. The DispatcherMappingImpl 
> finally tries to provide meaningful defaults, by looking for 
> appropriate global forwards, when no "error" or "denied" 
> forward is defined locally. All other forwards are of course 
> still accessible via findForward().
> 
> Rather than finding out during functional testing, it
> is now possible to find out whether you mistyped "succes" 
> simply by looking into the servlet log...
> 
> 
> That's it. I am looking forward to your comments and suggestions.
> 
> Best regards,
> 
>                  Ph.
> 
> 
> -----------------------------------------------------------------
> 
> Philipp K. Janert, Ph.D.                   janert at ieee dot org
> 
> --
> To unsubscribe, e-mail:   
> <mailto:struts-user-> [EMAIL PROTECTED]>
> For 
> additional commands, 
> e-mail: <mailto:[EMAIL PROTECTED]>
> 
> 

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to