Introduction
This is
Part 2 of a series of articles about modeling Web Presentation Layer implementation
using Statecharts and then implementing that design using a generic server-side
engine for processing incoming events and determining resultant states
and HTML pages. If you haven't read Part
1, the justification and explanation of the logical architecture then
you might like to do so first.
Handling
Statecharts Generically
Assuming
that you have modeled the implementation of your Presentation Layer Navigation
using a Statechart, you could simply go on to develop a hard coded solution
where one HTML page invokes another. You would simply hard code your events
into your links and form submissions, your next states into the requested
URLs. I have seen very adequate implementations of this particularly using
Servlets. However, this is an inflexible approach which doesn't easily
support condition evaluation and is likely to involve considerably more
maintenance. It does not provide for a central facility to protect against
unexpected use of bookmarking, back button or refresh and can lead to
extensive code to protect the back end application from unexpected browser
events.
Far better,
if you have time and are willing to make the long term commitment, to
invest in a genericised architecture which allows you to "soft"
code the design of the system as a description in a database. This series
of articles is about doing just that and now we are going to look at modeling
an engine for the generic treatment and processing of events and state
transitions.
Figure 1
presents an elementary Statechart containing all the notation elements
with which we must cope in order to deliver the full functionality. We
must model states which can have substates. There is an initial Start
State and there is an End State. Sometimes a State can have a Start State
as a child which must have an transition to an actual substate. Transitions
from one state to another are made by Events. Sometimes an Event will
contain arguments and those arguments may be evaluated with conditions.
The resultant evaluation can determine the next state. Finally, events
can carry Actions. The actions are conducted after the conditions are
evaluated.

Figure 1 Basic Statechart Notation Elements which we need
to model
In addition
to the Start State there are also two other initial states shown inside
State2. These are the History State and the Deep History State or History*.
The History State means: enter State 2 and immediately enter the substate
which was most recently occupied. Deep History State means: enter State
2 and immediately enter the most recently visited substate and immediately
enter the most recently visited substate of it and keep going recursively
until we have reached the deepest available level. In the example diagram,
if we are in State 5 and EventX happens we will go to State 6. Some time
later from State 8, we receive Event D which enters State 2 with History*.
The actual resultant state will be State 5 which was the most recently
visited child of State 2.
For User
Interface applications, this return to the History of a previous state
is incredibly powerful. If we open a Dialog Box, the Cancel action is
almost certainly going to return us to the history state of the previous
state which requested that Dialog, as shown in figure 2.

Figure 2 Opening a Dialog and returning to History* if
Cancel is selected
It
ought to be immediately apparent that this will also work for websites
which are running a server side Statechart engine. You can, for example,
navigate to a "Exit! Are you sure?" page which has a Yes or
No option. If No is selected, simply return to the previous area of the
application entering it with History*.
The use
of this mechanism decouples the design. For example, State1 above could
have new additional substates added such as State7 and State8. The Dialog
would never need to know this. All it needs to know is that Cancel will
return it to State1-History*.
The ability
to model History and History* is a powerful addition and can be used to
make websites behave more like GUI applications. Something which is in
increasing demand as website users get more and more sophisticated.
Concurrency
is missing
There is
one aspect of the Statechart notation which is not modeled - Concurrency.
Concurrency is the notion that the system can be in several independent
states simultaneously. It was a simple design decision to avoid complexity.
So far, for web site applications, the constraint that only single threaded
Statecharts can be modeled has proven satisfactory.
Why should
this be so?
Well we
are only modeling the Presentation Layer state, not the underlying business
system (Model Layer) state. In most business systems, there is an extreme
amount of concurrency, however, in a web implementation of a User Interface,
we are really delivering only a single html page. That single page does
not need concurrency.
Naturally,
there is the possibility to introduce concurrency as soon as you start
to use frames. Whether or not there is concurrency in the UI is dependant
on whether the frames can change independently or not. In most cases they
do not change independently but in a synchronous fashion. Concurrency
is an unnecessary addition and complexity which can safely be avoided
for the time being.
Initial
Model for Statecharts
In order
to implement a generic engine for a State modeled, Event driven system,
we need to be able to represent those States and Events as data at the
server.
Figure 3
introduces an initial model shape for Statecharts. This model has a State
class which knows its parent and any children. It also knows which of
the children is the default Start State child. It was decided not to model
the Start State or the End State explicitly. The action on the default
Start State has been modeled with the method onEntryExecute() - [ see
the Reflections section below] . The behaviour on
the default Start State action will be executed by calling this method
when a state is entered.
A State
has a collection of Events which are permitted from that particular state.
The Event in turn has a number of StateTransitions. The actual Transition
taken will depend on the Condition Evaluations. This part of the model
deals with the problems associated with EventD in Figure 1.

Figure 3. Class diagram to model an elementary
Statechart.
Figure 3
does not model History or History* though some provision is made for it
in the StateTransition which has an attribute entryCondition, this
would have the enumerated values of [default; History; HistoryStar] but
is shown as an int for brevity. [ The term HistoryStar is used
from now on because Java syntax doesn't allow History* and UML tools can
get confused. ]
A StateTransition
showing HistoryStar would indicate that the resultant (or "to")
State should be entered with HistoryStar. The current model however has
no way of knowing what that might be. We are not storing any history of
where the client has previously visited. This will require a more complex
model.
On Entry
Behaviour
It was found
from the navigation designs that default start state actions are unusual.
The most common usage is Start Transaction. For this reason, it was decided
to break OO design purity and implement the onEntryExecute() method as
a class method on the State class. The method contains a switch() statement
which is switched on the stateID passed as a parameter. This decision
was made in order to keep the Object Model clean and the persistence simple.
This is broadly in keeping with the Coad approach to OO modeling. [ see
the Reflections section later ]
For those
who prefer OO purity, you would simply make the onEntryExecute() a stub
method and over-ride it in a sub-class of State. You would provide one
of these for each State which required default entry behaviour.
Modeling
History
There are
several possible ways to model the history of visited states. We could
simply keep a Vector (or ordered collection) of States and iterate through
it backwards looking for the most recently visited child of the new "to"
state. This was, in fact, our initial approach. However, this is problematic
as data is needed in order to rebuild that previously visited state. That
data can change and is dependent on the User, the Login Session, perhaps
other system activity. For example, say we are populating a table of bank
account transactions using Account Number and Date. In order to accurately
rebuild that screen at a later date, we need to know which Account Number
and Date, the User had selected. At some point those values were entered
as HTTP Parameters, so we had them. It is important to be able to retrieve
them to rebuild the screen accurately.
The answer
was the model shape in Figure 4. This model introduces the User's LoginSession
and shows it holding a collection of visited states. This additional class
can hold that specific data required to rebuild the view. In this case
the HTTP Parameters which were current at the time the state was last
visited.

Figure 4. Statechart model extended to support a history
of state visits
In Figure
4, a LoginSession which is opened for each new client hitting the site
for the first time, holds a collection (Hashtable) of most recent StateVisit
objects. These represent the most recent time a State was visited by that
LoginSession. This collection is sufficient to allow us to model History
and HistoryStar which are only interested in the most recent visit to
the state. A second ordered collection (Vector) is also being held. This
is to allow future functionality such as "undo" to be introduced.
An <<interface>>
is introduced which is used to hide a generic collection of Parameters.
These are normally only the HTTP Parameters which accompanied the original
request to goto the state. In the event, that some more complex
attributes were needed such as specific business objects at the time the
state was visited, the StateVisit class would need to be extended with
a subclass to hold the reference to those additional and specific objects.
Figures
5, 6 and 7 show the Sequence Diagram for making a State Transition. This
assumes that the engine has already determined which StateTransition object
is appropriate and has determined the [default; History; HistoryStar]
entry condition for the new State. The LoginSession class is responsible
for making the transition. It will be called with the desired resultant
state passed as a parameter. The sequence will require to make a StateVisit
object and resolve issues such as default child or deep history before
finally determining the ultimate resultant state.
For example,
from Figure 1, a call to gotoState( State2 ) would normally result in
State 3 becoming the resultant state visited. The gotoState() method must
ensure that this happens by ensuring that th default child state is automatically
entered on entry into State2.
Resolving
the gotoState(), returnHistory() and returnHistoryStar() methods represents
the resolution of the significant problems in modeling the Statechart.
After this we can go on to look at the engine which processes HTTP Requests
and drives the Event handling Controller code and the resultant View Classes.

Figure 5. Goto Next State, Sequence Diagram
[Click to see full size]

Figure 6. Return to History of a State, Sequence Diagram

Figure 7. Return to Deep History of a State, Sequence
Diagram
Implementing
the MVC Engine
So far we
have seen how to model the Statechart. So now we can represent our Presentation
Layer design as real Objects which we can store on the server side of
the system. Now we will look at how to implement this with HTML clients
and make the whole thing work together.
There are
several problems. Firstly, our HTTP Request can only give us two Events
- Get and Post. It is necessary for us to translate the Get or Post into
the actual logical event from our diagram. In addition, we need to extract
any incoming arguments (or parameters) from the HTTP request. Finally,
we need to deal with the unexpected. We know that the client browser can
change its State using the Back Button. We want to allow this - most of
the time. We also know that we can receive unexpected Events because the
client has jumped using a Bookmarked URL. We also want to allow this -
at least sometimes.
Whether
or not Back and Bookmark are allowed has a lot to do with Conversational
State and Transactions. For the time being, we will continue to ignore
this complexity so Back and Bookmark is allowed. This complex area is
expanded in Part 3 of this
article.
Connector
All web
server environments have the concept of a connector. It's the code which
is run when a request arrives, for example a Servlet or a JWeb Cartridge
(with OAS v4.x). In this engine, the connector is purposefully lightweight.
It is one of the few implementation dependant parts of the system. It
would have to be re-written if you decided to move Web Server platform.
Other platform specific parts of the engine are hidden behind Java interfaces.
Making the engine and the Statechart design reasonably portable. The Connector
is responsible for wrapping the platform specific HTTP Request behind
the IHTTPRequest interface.
Request
Manager
The Connector
delegates to a RequestManager class which processes the incoming request.
It must detect which Client is calling and get the associated LoginSession.
It does this by extracting the SessionID parameter from the request. If
there is no SessionID then the client is new so they begin at the StartState.
Assuming
that we have a legal session, it must interpret the current client state,
the incoming logical event, and use the State, Event and StateTransition
descriptions to figure out what to do next. The client State and logical
Event name should be encoded as parameters. It must invoke the appropriate
event handling Controller class passing the HTTP Parameters which the
controller may need to evaluate any Conditions. The Controller will also
be responsible for executing any Actions which take place on the Event
arrow. Eventually, the RequestManager must ensure that the appropriate
View class is built and dispatched. This was delegated to the Controller
classes in this design. The Request Manager also takes responsibility
for error handling, acting as the ultimate bucket for catching exceptions.
The reasoning for this is simple. RequestManager is well placed to invoke
the appropriate recovery State after catching an exception or error.

Figure 8. The Engine to drive the Statechart
Interfaces
for flexibility
You will
see that a complex strategy of interfaces is employed for HTTP Parameters.
The IHTTPParameters interface abstracts away the reality of the source
of the parameters. For normal requests, we will pull the parameters from
the incoming HTTP Request but when we need to enter History or HistoryStar
then we have to recall parameters from persistent storage. Allowing the
other parts of the engine to hold references to IHTTPParameters frees
them from needing to worry where the parameters are coming from. They
no longer need to care whether they came from an incoming request or from
storage, the RequestManager can decide for them.
Delegation
rather than Inheritance
Some OO
purists may be uncomfortable with some of the design elements here. They
may argue that there is little point separating out Connector and RequestManager.
True! If you don't intend to move platform or you don't mind re-writing
a slightly larger class if you do move, then by all means merge these
classes on the design.
RequestManager
also doesn't appear to do much but as you will see it becomes the ENFORCER
for the transaction isolation and the judge with respect to the legal
or illegal use of Back Button or Bookmarking from the client. RequestManager
is the key class discussed in Part
3.
The second
aspect which is not immediately obvious from figure 8 but will become
apparent is that the Controller Class hiding behind the IController is
actually containing behaviour which might otherwise be placed in the Event
class - after all a Controller is an Event Handler. In fact, the Controller
class also has behaviour which ought to be in the StateTransition class.
The Controller has the condition evaluation logic - Event Class - and
the action on transition logic - StateTransition Class. Implementing this
delegated design with Event and IController separated is a key part of
this implementation and its worth just spending a few moments to consider
why it was appropriate.
The Event
class represents all generic events on any Statechart. The Event class
simply models the data needed for an Event such as the eventName, and
any behaviour which relates that Event to States and StateTransitions.
The Event class is generic in this respect and doesn't need to be subclassed
or extended. The same is true for the StateTransition Class. In fact,
what is being modeled here is data. The behaviour is separated out into
the IController implementor. This lack of data and behaviour encapsulation
is not pure object oriented design. OO is all about encapsulating data
and behaviour. Why separate it out?
The implementors
of IController represent application specific behaviour related to specific
Event objects for a given application. It would be possible to extend
the Event class and compose in the the Event Handling behaviour but this
would be messy. It would give us the problem of maintaining lots of little
sub-classes for Event. This makes our persistence messy and the whole
engine becomes less portable. Its nicer to allow the Event class to hold
the name of the IController implementing class and then allow the class
loader to invoke the class on demand. After all, a Controller is not a
special kind of Event.
A similar
strategy was used for View classes. Views implement the IView interface.
A View is responsible for building an HTML page. A specific view is tied
to a specific State, so why not subclass (or extend) the State class,
one for each View? Well again this would be messy and again it introduces
inheritance simply for the sake of it. It messes up the persistence and
overly complicates the State class which is purely data related. A View
is not a special kind of State.
Separating
out the application specific View and Controller behaviour away from the
generic Statechart engine keeps the design flexible, scalable and portable.
Its easy to develop a tool which will automatically populate the State
and Event Objects for a given Application Presentation Layer design. This
can be done is isolation away from the code development for the Views
and Controllers. Figure 9 shows this in more detail.
[ Brian
O'Bryne of ebeon.com has demonstrated
that Together/J can be used
to output data into an XML format which can be used to automatically populate
a persistent datastore for States, Events and StateTransistions]

Figure 9. State and Event delegate to IController and
IView to get application specific work done.
Controllers
Its worth
taking a little time to consider what is going on behind the IController
interface. You ought to find that a great deal of any website design contains
simple Navigation. Take the client from one location to another. It was
found that this can be true for around 75% of all Event arrows in a typical
eCommerce application. It makes sense therefore to write a single generic
class which can handle these Events. This is the OneToOneController. It
is there to be used most of the time to simply select the Next State based
on the single StateTransition held by the Event. Not shown on the diagram,
it is necessary to extend OneToOneController, if there is an Action to
be performed such as commit() on a transaction.
The OneToManyController
is an abstract class which is designed to be extended for all the other
Events which require conditions to be evaluated. The OneToManyController
class contains code to execute the transition which is re-used by the
sub-classes. Not shown, is the protected abstract method evaluateConditions()
which must be over-ridden by the sub-classes. This method should return
the selected StateTransition to be used. Its important to realise that
this is again a deviation from "pure" OO principles. The evaluateConditions()
method really belongs across the StateTransition objects as an evaluateCondition()
method, however, it is being separated into the Controller class to keep
the main engine separate from specific application behaviour. There are
definite performance advantages in a design which evaluates all the conditions
together rather than as a set of rules separate out into a collection
of StateTransition objects. Consequently, StateTransition really ought
to have an doAction() method which is by default a stub method which does
nothing. Again, this behaviour is in the Controller class and is the code
which is executed on successful evaluation of a single condition.
Views
Views are
considerably simpler. They implement the contract in the IView interface
that is all. There is no concept of super or abstract classes. In the
current implementation a View class builds an HTML page from scratch using
basic HTML Tag classes provided by the platform being used.
An area
for future research is the creation of a richer set of re-usable UI classes
which could be composed into the View classes in the style of a toolkit
such as JFC. Such a scheme is now easily possible with the use of JSPs
which can call other JSPs thus constructing a single HTML page from a
collection of classes. Other possibilities include the use of HTMLKona
from Weblogic.
Puting
it all together
That just
about covers all the basic functionality required for a generic engine.
To make it a little more flexible, the final model adds the notion of
an Application. An Application contains a number of States. This allows
the one server to run several different applications simultaneously. This
can be advantageous if they need to share the same business logic, or
you can only run one version of your server environment but need to serve
up multiple applications / web sites. A typical use for this might be
Client User Application and a separate Technical Support Application used
for maintenance and telephone support. The Technical Supprt application
typically supporting features such as replacing a lost User ID and password.
The Application
is also the Class which knows the Start State. It holds it as a special
reference. You will recall that we didn't explicitly model the Start State.
The End States are naturally those with no Event transitions and no children
- in effect Dead Ends. Detecting an End State is not difficult. The result
of arriving at an end state is to terminate the LoginSession by setting
the end time.
The Final
addition to the completed model in Figure 10, is the UnitOfWork Class
which is there to support the concept of a Logical Transaction Unit of
Work. Supporting transactions adds more complexity to the Statechart engine
but it is the highly controlled and elegant solution that Statechart modeling
offers for Transaction Scoping and Isolation which makes the implementation
of a Statechart engine so attractive.

Figure 10. The complete Statechart based MVC Engine model
[Click to see full size]
Reflections
During development
of this paper, it has become apparent that several further improvements
could be made. The onEntryExecute() method is an ugly kludge. Better might
be to place it into the View class. Afterall the View class represents
the State. View classes also have methods for validating inputs. However,
not all States have View classes. So implementing the onEntryExecute()
in the View class was rejected.
Brían O'Bryne
has suggested changing
the model to allow the notion of a default Event for a State. The default
Event could in turn have a Controller which implements any "onEntry"
action required and does a gotoState() for the appropriate default child
State. This is a considerable improvement on the current design. The default
Event would be optional i.e. 0..1, and would only exist when a transition
to a default child state was required.
Finally,
in the original design, LoginSession did not directly couple to the Statechart
Engine, instead it delegated through a class called Context. Context was
the non-persistent delegate for LoginSession. LoginSession interacted
with all the Business Layer classes which were application specific. The
Context class was a generic delegate which was part of the Statechart
engine. As has been argued elsewhere, there is considerable merit in this
approach. The Statechart engine becomes truly generic and portable. Portability
promotes re-use. With infrastructure code such as this, re-use is vital.
Its just too risky to build this kind of thing for every application.
Its like an operating system - dangerous to play around with.
Part 3
- Transaction and Exception Support
Part 3. Transaction
Support for Conversational transactions is such an important topic which
requires in-depth analysis that I have decided to give it a separate article
. Part 3 will also look at Exception Handling
and why a Statechart Engine implementation makes exception recovery conceptually
simple and deterministic.
Reference
Material
Constructing
the User Interface with Statecharts, Ian Horrocks, Addison Wesley,
1998
Java
Design: Building better apps and applets, 2nd ed., Peter Coad and
Mark Mayfield, with Jon Kern, Prentice Hall, 1999
Java
Modeling in Color with UML, Peter Coad, Jeff De Luca and Eric Lefebvre,
Prentice Hall, 1999
A similar
architecture was discussed in brief at Servlet Central in late 1998, www.servletcentral.com
Acknowledgments
This paper
was written following earlier work in the area conducted atTrinity
Commerce , Dublin,
Ireland. The design presented here represents version 2 of such an architecture
and incorporates several changes and enhancements which we noticed along
the way. This version is a pure Java solution. Version 3 of this framework is now commercially available as ViewControl from Statesoft. The original design
was an Object-Relational solution and was built on Oracle Application
Server v.4.x . I owe thanks to Marcus O'Connell and Brían (pronounced
breen) O'Byrne who helped with the early models for this system. Marcus
went on to built the first prototype and later Martin Byrne, Mark McSherry
and I developed it into a full production system. Brian Murray, with Jenny
Hay and Philip Miles (both Oracle Consultants) all contributed to the
implementation of the persistent storage and the data entry forms for
States, Events, Applications and Units Of Work.
Thanks to
Brían O'Byrne, Will Estes,
Jim Avery and Ian Horrocks for review comments and assistance with the
diagrams.
Notes
This article
contains extensive UML diagrams for the problem solution including Sequence
Diagrams. The nature of these is that they are large when displayed in
GIF format for publishing. As such you may experience difficulties trying
to print them. It is really impossible to adequately publish these diagrams
in a standard html page. To fit the page they must be small but to be
readable they must be large. It was decided to stick with large, readable
diagrams rather than printable diagrams.