/src_docs/architecture/event/sample_event_flows.html, v125
Sample Event Flows
This document just describes the basic program flow for various
presentation frameworks.
-
Barracuda
-
Turbine
-
Struts
It might be helpful to provide a basic summary of how events are
delivered.
- Everything starts in the ApplicationGateway. When the servlet is
initialized, we can add any known EventGateways, and these in turn will
be used to register EventHandlers with the EventBroker.
- When the application gateway receives an HTTP request, it must first
figure out what event the URL maps to. The URL must specify an event
name, and optionally may specify specific listener IDs that should
receive the event. If the URL does NOT correspond to a valid event, OR
if the event is not an instance of HttpRequestEvent, it will not be
dispatched. Instead, a generic HttpRequestEvent will be created and
delivered.
- Once the application gateway knows the name of the event, it either
instantiates the event itself (slightly slower, because this requires
reflection), OR, it asks the EventPool for an instance of the event.
- The EventPool keeps a reference to all known events based on the
event class signature. When an event is requested, the pool looks up the
list of events for the given event class, and either return a previously
instantiated event or if necessary, create a new one. This is somewhat
faster because, even though we are still using reflection for
instantiation, the instantiation only occurs a handful of times, after
which the events are simply reused. The downside of event pooling is
that it does require more resources to keep event instances around.
Generally, however, such overhead is minimal.
- Once the application gateway has an instance of the event, it
instantiates a DispatchQueue, indicates that it requires a response,
adds the initial event to the queue, and then passes it all to the
EventBroker for dispatching.
- The EventBroker uses the DispatcherFactory provided by the
application gateway to get an actual instance of an EventDispatcher
- The DispatcherFactory is responsible for instantiating the actual
instance of the EventDispatcher. Generally, it will return a new
instance each time, although optionally it may reuse the same instance
of the dispatcher. In this latter case, however, the dispatcher factory
should synchronize access to the dispatcher to ensure thread safety.
- When a DispatchQueue is passed in to be dispatched, the
EventDispatcher will iterate through the queue and dispatch all events.
As described above, in the case of the DefaultEventDispatcher, this is a
2 Phase Model 2 style dispatch in which non-Response events are
dispatched first, followed by all Response events (see above for
detailed description).
- Note that prior to actually dispatching an event in the queue, the
dispatcher will examine the event to see if it implements Polymorphic,
and if it does, it will dispatch it's parent events first (starting with
the highest event in the chain that implements Polymorphic all the way
down to the actual event itself).
- For every event in the queue, the dispatcher must determine which
listeners should be notified. This is determined by first looking to see
if the event is addressed to specific listener IDs. If not, the
dispatcher queries the event broker for a list of listener factories
that have expressed interest in the particular class.
- Once the dispatcher has a list of listener factories, it uses them
to obtain a reference to the actual listener (same rules apply as in the
dispatcher factory--return a new instance or synchronize).
- Once the dispatcher has a reference to the actual listeners, it
notifies them of the event.
- Event listeners generally do something in response to events. In
many cases Request events typically process business logic and then
redirect flow to the approriate view by adding a Response event to the
queue. They may however, simply log the event or update an underlying
data structure, or possibly even just ignore the event. If a listener
does something in response to an event, however, it should be marked as
handled.
- If no one handles the event and it implements Exceptional, then the
dispatcher appends the parent event to the queue. This will occur
recursively until someone handles the event or we reach the root, in
which case an UnhandledEventException will be thrown by the dispatch.
The ApplicationGateway generally catches this event and provides a
default response.
Suppose we have a form which whose action is mapped to a URL that looks
something like this http://<server>/servlet/Turbine/template/AddUser.wm/action/NewUser
and whose form buttons might be named doSubmit, doCancel, etc. When the user
presses a button, the following sequence would occur.
- the /servlet portion of the path will cause the Turbine Servlet to
handle the request
- Turbine evaluates whether the user has a session - if not it either
redirects them to a default page, or sends them to the requested page
with a default session
- If the user has a session, Turbine makes sure the user has logged
in, validates the session, and gets / builds an ACL list. This
information will be stored in the RunData structure.
- Turbine then evaluates the /action portion of the path, causing it
to instantiate and execute the NewUser implementation of the Action
interface
- Turbine then evaluates the button name (i.e. doSubmit) to determine
which method to invoke in the NewUser class.
- If there is no method matching the button name, the doPerform method
specified in the Action interface will be invoked
- The method which gets invoked is passed a copy of RunData
(encapsulates HTTP information, as well as other data)
- This method would typically load info from the underlying data model
and store it as named messages (based on form name, field name) in a
FormMessages storage structure provided by RunData
- Turbine then evaluates the /template portion of the path, and
invokes the AddUser.wm template.
- The (in this case) WebMacro template receives a copy of the RunData
structure, and the WebMacro scripting language can pull values out of
the FormMessages structure to populate specific data items in the page.
- The completed page is then returned to the client browser
Struts initially loads an ActionServlet which (as described in the
javadoc) has the following responsibilities:
- Identify, from the incoming request URI, the substring that will be
used to select an action procedure.
- Use this substring to map to the Java class name of the
corresponding action class (an implementation of the Action interface).
- If this is the first request for a particular action class,
instantiate an instance of that class and cache it for future use.
- Optionally populate the properties of an ActionForm bean associated
with this mapping.
- Call the perform() method of this action class, passing on a
reference to the mapping that was used (thereby providing access to the
underlying ActionServlet and ServletContext, as well as any specialized
properties of the mapping itself), and the request and response that
were passed to the controller by the servlet container.
For the example application all urls ending with a ".do" extension are
mapped to this Action Servlet. At initialization time, the action servlet
reads in a action.xml file which provides additional routing information
that is used during request processing. The basic application flow runs
something like this:
- All GET and POST requests are routed to the
protected void process(HttpServletRequest request, HttpServletResponse
response) method of the
ActionServlet.
- This method first retrieves the process path of the incoming
request. This is either the "request.getPathInfo()" if available or a
substring of the full "request.getServletPath()" as returned from the
servlet request API. This is determined based on the deployment
specifications in the web.xml file. Path Info would be used if the
application routes URLs based on a application prefix. The sub string of
Servlet Path would be used if the application routes URLs based on
application extensions. This is how the example app is configured and a
request URL such as 'http://localhost:8080/struts-example/editRegistration.do'
would be mapped to a path of '/editRegistration'.
- The next thing that happens is an
ActionMapping class is found for the request. Based on the path
retrieved from the previous step, the action mapping class is
instantiated and passed onto the following stages. This class
encapsulated the routing information obtained from the action.xml file.
For example, a path of '/editRegistration' can be associated with its
own ActionMapping class or the default
ActionMappingBase class (which can be specified in the web.xml
file). A line read from the action.xml file such as <forward
name="success" path="registration.jsp"> tell the action mapping class
where to go when a
findForward() call is made on it. An additional line may be
specified such as <action path="/editRegistration" className="org.apache.struts.example.ApplicationMapping">
to designate a custom action mapping class for this path.
- The next step to occur is to find a
ActionForm class, if it exists, for the request. This action form
attribute is retrieved from the action mapping class associated with
this request and is specified in the action.xml file. If the action form
exists, it is automagically populated with any cgi data submitted with
the request. This is done using the JavaBean method signature patters
such that a form field with the name 'passwd' would be associated with
the bean property 'passwd' and can be accessed by getter and setter
methods of 'getPasswd()' and 'setPasswd(String passwd)'.
- The next step that occurs is to validate the action form if
required. The validation criteria is left up to the action from class
and the validate method will only be called if:
- A action form instance was found.
- The action form is a sub class of
ValidatingActionForm
- The input form attribute exists, this attribute is also
specified in the action.xml file.
- The cancel action button was not selected.
- otherwise, the process() method of the Action Servlet continues on
as normal.
- If the validation method is invoked, the action form class validates
the submitted form parameters and reports any errors into an instance of
the ErrorMessages class. This class returns all the collected errors at
the end of the validation process as an array of Strings. If there are
no errors to report, the process() method of the Action Servlet
continues on as normal. If there are errors to report, the input form
attribute is retrieved from the action mapping class and control is
forwarded to this location.
- If validation was successful or it was not required by not meeting
the stated criteria, the
Action instance class associated with this request is called. The
action instance class is also retrieved from the action mapping class
associated with this request and is specified in the action.xml file.
The
perform() method is called on the action instance class and any
additional work that is required to complete the request processing
before generating a response is performed here. The return value for the
perform() method tell the Action Servlet where to forward control on to.
- The final stage after the perform() method is called on the Action
instance is to forward control onto a servlet that will generate the
view. This servlet will be determined by the return value of the
perform() method and is typically a Java Server Page.
If you'd like to document a framework not listed here, we'd love to hear
about it.
Last Modified: 2006-01-02 15:59:13 -0500 (Mon, 02 Jan 2006)
Put all your content above this line