Responding to only Selected Events
If I am implementing the IHttpEvents directly, I am
forced to implement all of the events (or methods), whether I am
interested in them or not. This can be unnecessarily tedious.
Instead, I usually extend the LogHttpEvents, which does
nothing but log each event, and then implement the only one or two
methods that concern the event at hand.
To draw a parallel, while editing this article, the editor
pointed out that in the AWT/Swing/JavaBeans world, there's a
concept of an "adapter" implementation, which no-ops all interface
methods, so you subclass and override only those methods that
interest you. That is what is exactly happening here, as well in the
following example:
public class HttpRequestCharacterEncodingHandler
extends LogHttpEvents
{
public boolean beginRequest(
HttpServletRequest request,
HttpServletResponse response)
throws AspireServletException
{
try
{
String enc = request.getCharacterEncoding();
if (enc == null)
{
String encoding =
AppObjects.getValue(
m_requestName
+ ".encoding",
"UTF-8");
request.setCharacterEncoding(encoding);
AppObjects.log(
"Info:setting encoding to " + encoding);
}
return true;
}
catch(UnsupportedEncodingException x)
{
throw new AspireServletException(
"report error",x);
}
}//eof-function
}//eof-class
How to Raise an Event?
So far I have documented primarily how to respond to events.
Here is an example of how to raise an event using the
SWIHttpEvents wrapper.
private boolean login(
String username,
String password,
HttpServletRequest request,
HttpServletResponse response,
HttpSession session)
throws RequestExecutionException,
AuthorizationException,
AspireServletException
{
boolean validPassword =
yourLogin(username,password);
if (validPassword == false)
{
//Invalid password
throw new AuthorizationException(..);
}
//Good password
ServletCompatibility.
putSessionValue(session
,AspireConstants.ASPIRE_USER_NAME_KEY
,username);
SWIHttpEvents.userLogin(username
,session
,request
,response);
ServletCompatibility
.putSessionValue(session,
AspireConstants.ASPIRE_LOGGEDIN_STATUS_KEY
, "true");
return true;
}
In this example, as part of the login process, a successful
login event is raised using the highlighted code segment.
Event Distributor Class Diagram
The general pattern of the event distributor can be summarized
pictorially using the class diagram in Figure 1.
|

Figure 1. Event Distributor class diagram (click for full-size version)
|
In the diagram, client sections of the code (such as "client1"
and "client2") raise events by obtaining a reference to an
IHttpEvents and calling methods on that interface.
Each method corresponds to an equivalent event. Instead of
repeating this process, every time a client needs the event
interface, this is handled by an intermediate static
class called SWIHttpEvents.
The event interface could have been implemented by any number of
implementations, one of which is a concrete event distributor
called HttpEventDistributor and the other a
default implementation for the event interface.
The default implementation acts as an abstract implementation
for the derived event-specific implementations, whereby the derived
implementation can pick and choose the events to implement. In the
diagram, two such event handlers are being shown. It is also
possible that a given event may be implemented by more than one
implementation.
This class diagram can serve as a guide for implementing new
event interfaces. In particular, the naming conventions and the
various classes listed here could serve as a copy book.
JavaBeans and Property Change Events
Earlier in this article, I compared the events discussed so
far with the macro-level messaging systems such as JMS. On the
other side of the spectrum, at the micro level, many Java
programmers are quite familiar with the property change events in
the JavaBeans architecture. In this architecture, one can register
property change listeners. In this scenario, when the value of an
attribute of a bean changes, a whole number of listeners can be
invoked. This model is often used in UI toolkits and frameworks.
The events I have noted in this article are not granular enough to
be tied to a set of properties but exist independently, and also
don't adhere to the concept of a "value change," where one could
track the value before and after an event. I believe these are
different semantics and require separate treatment.
Parallels to Remoting Proxies
The approach suggested here has parallels to other component
architectures such as dynamic proxies in Java, remoting in C#,
delegates in C#, and even EJBs. Although the examples show a
straightforward, non-reflection-based approach, it is possible to
redesign the principles using reflection, whereby a number of
intermediate classes can be eliminated.
It is even conceivable to design language constructs for
interfaces where a natural delegation such as this is inherent in
the language. For example, I can envision the following:
public static class SWIHttpEvents
defined_as_a_multiple_delegate_for IHttpEvents
{
//No other code necessary
}
All the code above will be automatically enabled. To support
this, perhaps configuration should become a natural part of the
language as well. Also, bringing this higher level of abstraction to
a language allows programmers to think of their interfaces as
delegated events where appropriate.
Resources
Satya Komatineni is the author of AspireJ2EE (http://www.activeintellect.com), an open source web development RAD tool for J2EE/XML.