One of the questions that I hear most often is How can we
model exceptions? Prior to the 2.0 version of the Unified Modeling Language,
the answer was the implicit use of the class and interaction diagrams. These
diagrams could be used to explain structure and dispatch, but they were
incapable of describing the logic flow. With UML 2.0, the activity diagram has
a mechanism for describing how exceptions are handled.
In this installment, we will look at new developments in the
activity diagram that deal with exception handling. In the activity diagram, an
exception handler specifies something to execute when a given exception occurs
during processing. This is another case where the UML 2.0 has moved closer to
way that we solve problems with software.
A History of Exceptions
The idea of programmatically handling exceptions started in
C++. However, the idea really took off in the Java programming language where
exceptions are part of the language, libraries, and frameworks. Java made
exceptions part of the language syntax, method declarations, and even the way that
errors are reported by Java compilers.
Exceptions are often used to reflect abnormal conditions
that are part of common operations such as creating a new file, opening a socket, or dividing by zero. These exceptions
must be either caught as part of our program logic or passed on to the next
tier of application logic. All exceptions will be handled at some level, even if it
causes the program to be terminated. One of the more difficult tasks can
be tracking down where an exception originates and who is actually handling it.
Since exceptions are part of our technical view of the world
and arguably (in another column) our domain, they should be reflected in our
models. By placing exceptions in our models, we are acknowledging that these
elements are part of our overall design. We can also look at how they are
handled and where they originate. Modeling helps us communicate this information to
those who need it to utilize our components.
The Exception Handler
Exception processing
consists of two phases. In the first phase, we throw an exception at some point
in the code. An exception may be thrown in several places in a given section
of code. We often group the statements where exceptions can be thrown in a block.
In the Java programming language, this block is the
block of code grouped in brackets as part of a try statement.
In the second phase, we catch the exception and perform some
action. The action that is performed is part of a catch block. There may be
multiple or nested catch blocks as part of our program logic. The action is
supposed to handle the problem that the exception reported. Sometimes, this is
possible and processing can resume. There are also times when the problem
cannot be resolved and the user must intervene or the program must be aborted.
Figure 1: The UML 2.0 Exception Handling Notation
In the UML 2.0 specification, the try block is called a
protected node in an activity diagram. The catch block is called the handler
body. If an exception occurs, the set of handlers is examined for a possible
match [UML 2003]. If a match is found, the handler body is invoked and the
handler catches the exception. If the exception is not caught, the exception is
propagated to the enclosing protected node if one exists.
An Example
Consider a simple URL viewer that prompts the user for a URL
and then copies the contents to the display. The logic for this activity is to
open a new URL, open the display, copy the contents of the URL to the display,
and then close the streams for the URL and the Display. In the sunny day
case, we simply display the contents of a resource.
Figure 2: The URL viewer example
During the course of this logic, two possible exceptions may
result. The first is a MalformedURLException. This
exception could be detected when we open the URL. The second is an IOException that could happen in several places. The URL
might be valid but the object that it locates is unreadable. The display may
not be accessible.
In the model of this system, there are four activities.
Three of these activities are nested in a protected node. In UML 2.0, we are
allowed to nest activities. There are two handler bodies; one for the MalformedURLException and one for the IOException.
Successors to the handler bodies are the same as the successors to the
protected node. We could, therefore, look at the activity which closes the URL
and the Display as our "finally" clause.
Implications
Activity diagrams have been substantially augmented in the
UML 2.0 specification. In general, activity diagrams have been a staple of
business process modeling and not system modeling. However, as Service-Oriented
Architecture (SOA) continues to move business process modeling and system modeling
closer together, we can expect to see more widespread use of activity diagrams
in system modeling. This was a natural evolution from a closing gap between
business and software.
However, this natural evolution is being accelerated by
placing exceptions on the activity diagram. The impact of using activity
diagrams to communicate the proper use of exception handling in the design of a
system is huge. This aspect alone is enough to bring the activity diagram back
to system modeling on many projects (if it isnt being utilized already).
Activity diagrams lost favor in the software system community because
it was believed that they promoted functional programming. Having roots in flow
charting, activity diagrams are often associated with functional decomposition.
It is important to balance any modeling activity (like use case modeling and
activity diagrams) that promotes functional programming with activities that promote good object-oriented design.
References
[Palmer 2001] Palmer, Stephen.
Exceptional Strategies, The Coad Letter, Issue 90.
[Ashmore 2003] Ashmore,
Derek C. Streamline Your Exception Processing, JavaPro,
Volume 7, Number 5, May 2003.
[UML 2003] Unified Modeling Language: Superstructure version
2.0, 3rd revised submission to OMG RFP.
Server Response from: BDN9B