"Craig R. McClanahan" wrote:

> * As fleshed out, the only events reported with this model so far
>   are before and after an Action's perform() method is called.
>   The abstract talks about building listeners for all "interesting"
>   events.  If we're going to do a listeners model, I think we should
>   extend it to basically all of the processXxx methods, not just
>   processPerform().

Yes.

> * If we go with generalized events, putting the firing logic inside
>   Action seems wrong -- general purpose support classes, or
>   public methods inside ActionServlet, seem more appropriate.

Agreed. I vote for a support class.

> * Given that there will be many more events, we've got some
>   representation choices:
>
>     * Single ActionEvent class, or subclasses for various types
>       of events that have different properties (some events care
>       about the current ActionMapping and some don't).

I envision an event hierarchy.

>     * SIngle registrations of ActionListeners that receive all types of
>       events, or separate registrations for separate event families?

The latter would be more type-safe, and is probably preferred.

> * I also have a couple of nit-picky type thoughts:
>
>     * Event type codes inside the ActionEvent seem redundant,
>       given that the type is implicitly defined by which listener
>       method you call.

True, but that assumes that the handler will never pass the event
to other methods that need to distinguish the event type -- the
information's not available to those methods.

>     * An ActionEvent, or the ActionListener that receives it,
>       should have knowledge of the ActionServlet
>       it is associated with, to provide access to underlying resources
>       provided by the servlet.  (The whole event listener model is
>       intimately tied to Struts anyway, so this does not seem onerous).

Agreed.

>     * We need to use collection classes (with an implementation I'm
>       currently working on) that do not require lots of synchronization locks
>       or new object creations when processing event notifications, since
>       they happen on every request.

Ok.


david

>
>
> Thoughts?
>
> Craig
>
> David Geary wrote:
>
> > ABSTRACT
> >
> > It's often convenient, and sometimes necessary, to handle Struts events,
> > such as when an action has its locale set, or when the action servlet
> > processes an action's form. This document proposes retrofitting Struts
> > with the delegation event model. That model, which is used by the AWT
> > and
> > Swing, makes event handling simple, flexible, and scalable.
> >
> > CREDITS
> >
> > Delegation and Event Model for Struts? -- posted to struts-dev by
> >                                           Robert Leland
> >
> > INTRODUCTION
> >
> > Currently, you can use inheritance to handle Struts events like those
> > described above. Typically, that means extending ActionServlet and
> > overriding a protected method, such as
> > ActionServlet.processActionPerform.
> >
> > Inheritance-based event handling is inflexible and does not scale well
> > because event sources and listeners are tightly coupled at compile time.
> > This was evident to AWT engineers, who replaced the AWT's original
> > inheritance-based event model with the delegation event model.
> >
> > The delegation event model, which has its roots in java.util, implements
> > the Observer design pattern to loosely couple event sources and event
> > listeners at runtime. That loose coupling makes it easy to associate
> > disparate types of objects, so that event listeners can easily react to
> > changes in event sources.
> >
> > STRUTS AND THE DELEGATION EVENT MODEL
> >
> > So what does it mean to retrofit Struts with the delegation event model?
> > It means that Struts will fire events when it performs certain
> > functions. You can register with Struts as an event listener, and
> > handle events as you see fit.
> >
> > This proposal advocates firing events for all interesting Struts
> > functions; for example, the action servlet should fire a robust set of
> > events for processing actions and forms, performing mappings, etc.
> > Implementing support for those events follows the same
> > design pattern discussed in this proposal for implementing action
> > events.
> >
> > This proposal illustrates how to modify Struts to fire events just
> > before, and immediately after, a Struts action has its perform method
> > invoked. Those events are hereafter known as action events.
> >
> > IMPLEMENTING ACTION EVENTS AND ACTION LISTENERS
> >
> > Getting Struts to fire action events is easy. First, we define a
> > listener interface and an event class:
> >
> > org/struts/apache/event/action/ActionListener.java
> > org/struts/apache/event/action/ActionEvent.java
> >
> > Here's the listing for ActionListener:
> >
> >    public interface ActionListener {
> >       public void beforeActionPerform(ActionEvent event)
> >                                 throws ServletException;
> >       public void afterActionPerform(ActionEvent event)
> >                                 throws ServletException;
> >    }
> >
> > ActionListener methods are passed instances of ActionEvent. Here's the
> > listing for that class:
> >
> >    public class ActionEvent extends java.util.EventObject {
> >       public static final int BEFORE_ACTION_PERFORM=0,
> >                               AFTER_ACTION_PERFORM=1;
> >       private int eventType;
> >       private HttpServletRequest request;
> >       private HttpServletResponse response;
> >       public ActionEvent(Action action, int eventType,
> >                          HttpServletRequest request,
> >                          HttpServletResponse response) {
> >          super(action);  // specifies action as the event source
> >          this.eventType = eventType;
> >          this.request   = request;
> >          this.response  = response;
> >       }
> >       public int getEventType() { return eventType; }
> >       public HttpServletRequest  getRequest()   { return request; }
> >       public HttpServletResponse getResponse()  { return response; }
> >    }
> >
> > Through action events, action listeners have access to:
> >
> > event type (BEFORE_ACTION_PERFORM, AFTER_ACTION_PERFORM)
> > action
> > request
> > response
> >
> > HANDLING ACTION EVENTS
> >
> > Here's how you use action events and listeners:
> >
> >    // first, implement a listener that handles action events
> >
> >    public class MyListener implements
> >                    org.apache.struts.event.ActionListener {
> >       public void beforeActionPerform(ActionEvent event) {
> >          // handle event
> >       }
> >       public void afterActionPerform(ActionEvent event) {
> >          // handle event
> >       }
> >    }
> >
> >    // Then register your listener with an action:
> >
> >    someAction.addActionListener(new MyListener());
> >
> > Thereafter, MyListener.beforeActionPerform and
> > MyListener.afterActionPerform will be called before and after
> > someAction's perform method, respectively.
> >
> > Let's see what changes need to be made to Struts to make this work.
> >
> > STRUTS MODIFICATIONS FOR SUPPORTING ACTION EVENTS
> >
> > Only two Struts classes need to be modified to support firing action
> > events: Action and ActionServlet. Methods are added to the Action class
> > for registering action listeners and firing events:
> >
> >    // the following is added to org.apache.struts.action.Action:
> >
> >    import java.util.Enumeration;
> >    import java.util.Vector;
> >    import org.apache.struts.event.action.ActionEvent;
> >    import org.apache.struts.event.action.ActionListener;
> >
> >    public class Action {
> >       ...
> >
> >       protected static Vector listeners = new Vector();
> >
> >       public void addActionListener(ActionListener listener) {
> >          listeners.addElement(listener);
> >       }
> >       public void removeActionListener(ActionListener listener) {
> >          listeners.remove(listener);
> >       }
> >       public void beforeAction(ActionEvent event)
> >                                         throws ServletException {
> >          fireEvent(event);
> >       }
> >       public void afterAction(ActionEvent event)
> >                                         throws ServletException {
> >          fireEvent(event);
> >       }
> >       protected void fireEvent(ActionEvent event)
> >                                        throws ServletException {
> >          Enumeration it = listeners.elements();
> >
> >          while(it.hasMoreElements()) {
> >             ActionListener listener =
> >                         (ActionListener)it.nextElement();
> >
> >             switch(event.getEventType()) {
> >                case ActionEvent.BEFORE_ACTION_PERFORM:
> >                             listener.beforeActionPerform(event);
> >                             break;
> >                case ActionEvent.AFTER_ACTION_PERFORM:
> >                             listener.afterActionPerform(event);
> >                             break;
> >             }
> >          }
> >       }
> >       ...
> >    }
> >
> > Now Struts actions can fire action events to registered action
> > listeners. ActionServlet.processActionCreate is modified to call
> > Action.fireEvent, like this:
> >
> >    protected void processActionPerform(Action action,
> >                                         ActionMapping mapping,
> >                                         ActionForm formInstance,
> >                                         HttpServletRequest request,
> >                                         HttpServletResponse response)
> >                                         throws IOException,
> >                                                ServletException {
> >       action.fireEvent(new ActionEvent(action,
> >                        ActionEvent.BEFORE_ACTION_PERFORM,
> >                        (HttpServletRequest)request,
> >                        (HttpServletResponse)response));
> >
> >        // Perform the requested action
> >       ActionForward forward =
> >             action.perform(mapping, formInstance, request, response);
> >
> >       action.fireEvent(new ActionEvent(action,
> >                                 ActionEvent.AFTER_ACTION_PERFORM,
> >                                 (HttpServletRequest)request,
> >                                 (HttpServletResponse)response));
> >       ...
> >    }
> >
> > CONCLUSION
> >
> > Struts will be a more powerful and extensible framework if developers
> > can handle Struts events, which can be accomplished as outlined in this
> > proposal with the delegation event model.
> >
> > This proposal has illustrated modifying Struts to fire action events. If
> > this proposal is accepted, Struts should be modified to fire many
> > meaningful events. The ActionServlet class alone is rife with methods
> > that should fire events; for example, initApplication,
> > processActionForm, processLocale, etc.
> >
> > A practical use of the action events discussed in this proposal can be
> > found in the proposal 'Tokens and Events: Handling Illicit Access to
> > Sensitive Pages'. That proposal implements an action listener
> > that restricts access to actions that are sensitive to the back button,
> > reload button, or bookmarks.

Reply via email to