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:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to