Activity Graphs

These graphs allow you to express the way you want your application to behave, this is expressed by means of states and transitions. An activity graph therefore is, by definition, a state machine.

Your activity graph should be modeled as a child element of the use-case. In case your modeling tool does not support that you can add a tagged value to the use-case, making it point to the activity graph, like this: @andromda.presentation.usecase.activity=My Activity Graph

On this page you will see how to use the different states, and how to express the flow from one state into another.

Custom code (methods) can be executed from an action state, you will learn about that in one of the later sections .

Initial States

Each use-case needs an initial state, an initial state is displayed as a solid black disc. It denotes the starting point of the use-case, it can have no incoming transitions and only one outgoing transition. Only a single initial state is allowed per activity graph.

Since our example features only one use-case it will therefore contain exactly one initial state.

Action States

An action state represents a certain state in which the application can be recorded, an action state is displayed as a rectangle with rounded corners. In bpm4struts you will use action states for both server-side states (the controller: struts actions) as client-side states (the view: JSP, VTL, ...).

Make sure the actual name property of each action state is unique in the activity graph. Additionally, make sure the name is properly entered: sometimes people enter the action state's label in the activity diagram instead of the real name of the element.

Client-side action states are tagged with the <<FrontEndView>> stereotype, they represent a JSP and may have multiple outgoing transitions (one per call to the server).

Server-side action states do not need any stereotype but can only have a single outgoing transition.

Most of the time you'll want exactly a single outgoing transition for your server-side action states, but in a few cases it is required to take full control of the process flow, meaning you don't want to have the application forward to the next resource. In this case simply don't model an outgoing transition, the Struts action class will return null. Don't forget to write to the HTTP response yourself, you can do this is you defer to a controller operation in your action state.

You'll want to make use of this feature when you want an action returning a dynamically generated report such as a PDF.

Transitions

Transitions are used to interconnect the different states in the activity graph, they make up the actual process logic.

A few tagged values exist for transitions coming out of <<FrontEndView>> action states, please see this page to learn more about them: profile.html .

Using these tagged values a transition may be marked to carry a message to the (indirectly) targetted <<FrontEndView>> action state:

  • @andromda.struts.action.success.message: Write a message that will be displayed in a green box. This message will be stored into the default resource bundle.
  • @andromda.struts.action.warning.message: Write a message that will be displayed in a yellow box. This message will be stored into the default resource bundle.

It is possible to model exceptions to the process logic, in doing so you express how the system should behave in case something goes wrong. You just need to add the <<FrontEndException>> stereotype to the transition and you're good. Additionally you can add a tagged value to such a transition in order to refine the exception handling: @andromda.struts.exception.type needs the fully qualified classname of the exception to be handled by this transition, others will be ignored; the default value if not specified is java.lang.Exception meaning all exceptions will be handled.

The default exception handling strategy is to return to the source page on which the exception has been triggered.

Event Parameters

Event parameters are parameters modeled on transitions exiting client-side action states (the ones with the <<FrontEndView>> stereotype). Whenever you model such a transition it represents a call to the server from a webpage, usually by submitting a form. The parameters you model will represent the form fields.

Please note that you will need to add the parameters to the transition's trigger, this trigger should be of type 'signal', but don't worry about that if your UML tool does not support setting the type of the trigger.

Different tagged values exist to control the generation of the type of the event parameter.

Selectable parameters

Event parameters can be made selectable so that the user can select one or more values from a list and send them to the server. In order to achieve this we need to make the distinction between two types of data: the complete list and the selected value(s).

The event parameter you model should represent the one that is sent to the server, this typically is a String but could also be a Collection, List, int, etc... Add the following tagged value to this parameter: @andromda.presentation.web.view.field.type=select.

A collection-type parameter (Collection, List, Set, ...) will result in the rendering of a list where multiple selections are possible.

Adding this tagged value will allow us to populate this list prior to showing it to the user.

Any action that is entering the page on which this parameter is an event parameter will have the possiblity to populate the list. In order to do this you would simply defer to a controller operation which has as argument a parameter with the exact same name and type as the event parameter, defer to this operation somewhere before entering the <<FrontEndView>> action state. This will result in the controller having the possiblity to set the values and labels for the selectable field.

Notice how the form allows setting the values and labels to back up the selectable event parameter. In this case the event parameter had been named 'number'. Most of the time the data that will go into the list is coming from the back-end, in this example the list contents never change.

There is another method available for selectable event parameters that is equivalent to the above but is easier to use when the labels and values are encapsulated in value objects:

Setting the labels is optional, in case they are missing the application will assume the values instead.

Password fields

Simply add the @andromda.presentation.web.view.field.type=password tagged value to the event parameter. This will render a regular text input field in which the characters are masked behind asterisks.

Multi-line text

Simply add the @andromda.presentation.web.view.field.type=textarea tagged value to the event parameter. The generated input field will allow more than a single row.

Options

Simply add the @andromda.presentation.web.view.field.type=radio tagged value to the event parameter. This will render a set of radiobuttons from which the user may choose one. By default 3 radiobuttons are rendered, but this number can be changed by using the @andromda.struts.view.field.radio tagged value, which either takes a positive integer value or a comma-separated list of values from which to select.

@andromda.struts.view.field.radio=7
@andromda.struts.view.field.radio=cd,dvd,book,hardware

Getting the selected option's value from the form will return the selection index encapsulated by a class of this field's type. There is also a convenient method present on the form that is able to convert this index to the modeled selection value.

In the example above one would have:

  • 0: cd
  • 1: dvd
  • 2: book
  • 3: hardware

File upload

The parameter must be a File type.

Checkboxes

The parameter must be a boolean type.

List of checkboxes

Simply add the @andromda.presentation.web.view.field.type=multibox tagged value to the event parameter. An additional tagged value must be set: @andromda.struts.view.field.multibox, the value must match a variable which holds a collection or array.

Using this tagged value only makes sense when used in a table, go here to learn about tables. Each row in the table will be matched against to content of the multibox variable, if it is present the checkbox will be checked.

Page Variables

Page variables are modeled the same way event parameters are, the only difference is that you model them on transitions entering a <<FrontEndView>> action state. In doing so the modeled parameters will be available in the generated JSP page.

Page variables can be rendered in tabular format, this is an advanced feature which is explained in more depth on this page: Tables .

Decision Points

In some cases action states and transitions just aren't enough, a good example is when you want to fork the flow based on a specific decision. Suppose you want to follow the first transition if the user login credentials are valid, and follow the second transition if they are invalid.

In order to do this we must need to be able to call an operation with a return value, on which the decision is based. We will see how to do this later, click here to proceed there now: Custom Code .

Finally we must tag the transition indicating when it must be followed, in UML this is done by means of guards. Not to make things overly complex it is not necessary to model the OCL for the guard (very few tools properly support this), so instead it will be sufficient to model the name of the guard, it must match the return value of the method call (matching is done using String.valueOf(returnValue)).

Some modeling tools do not properly show the name of the guard in the activity diagram, in that case you might consider copying the name also in the guard's body, this will be ignored by the cartridge and might show it on screen for clarity.

Final States

You may have as many final states as you want in an activity graph. In bpm4struts a final state represents the end of the use-case and the flow into the next use-case. Final states are displayed as bulls-eyes in activity diagrams.

There are two ways of modeling a final state: either you give it the name of the next use-case (which can be the same as the current use-case), either you do not name it and you use a hyperlink to the next use-case (this is not supported in all UML tools).

Sending parameters across use-cases

Sometimes it can happen that you would like to send parameters from one use-case into another use-case. This is easy with the bpm4struts cartridge: just model the parameters on an action leading into a final state and the parameters will automagically be available in the target use-case.

This is the first use-case

This is the second use-case

Respect the fact that use-cases are supposed to be loosely coupled: do not assume incoming parameters to always be present and check for null, this will improve your application's robustness.

Nice to know

JSP pages

Each action state carrying the <<FrontEndView>> stereotype will result in the generation of a JSP page. If you have properly modeled your use-case then these pages will contain already everything to have a working application: forms, buttons, hyperlinks, a menu, breadcrumbs, an online help, client validation, server calls, security ...

The generated JSP pages comply to the JSP 2.0 specification, as found in J2EE 1.4.

Struts Actions/Forms

For each transition modeled exiting either an initial state or an action state with the <<FrontEndView>> stereotype the cartridge will generate a Struts Action class and a Struts Form class. The parameters modeled on the transition's signal event will make up the fields that go into the form.

The generated struts-config.xml descriptor will contain a form-bean entry per generated Form. Here's an example:

<
form-beans
> ... <
form-bean
name=
"purchaseItemsEnterUserDetailsPurchaseForm"
type=
"my.onlinestore.purchase.EnterUserDetailsPurchaseForm"
/
> ... <
/form-beans
>

Each action will have a corresponding action-mapping entry, like this:

<
action-mappings
> ... <
action
path=
"/PurchaseItems/EnterUserDetailsPurchase"
type=
"my.onlinestore.purchase.EnterUserDetailsPurchase"
name=
"purchaseItemsEnterUserDetailsPurchaseForm"
scope=
"request"
input=
"/my/onlinestore/purchase/enter-user-details.jsp"
unknown=
"false"
validate=
"true"
> <
exception
type=
"java.lang.Exception"
key=
"purchase.items.enter.user.details.exception"
path=
"/my/onlinestore/purchase/enter-user-details.jsp"
scope=
"request"
/
> <
forward
name=
"purchase.items"
path=
"/PurchaseItems/PurchaseItems.do"
redirect=
"false"
/
> <
/action
> ... <
/action-mappings
>

A Struts action class and associated form is generated per sequence of transitions between two <<FrontEndView>> action states. The form fields are determined by the parameters modeled on the transitions, for maximum usability some parameters from neighbouring actions might also be included, but we'll not get into this just yet.

The action class has a private method for each different state it encounters, those methods might delegate control to a controller operation, this is explained here . A code fragment taken from the online-store sample is shown below, it contains a single action state deferring control to the loadItems controller operation. Please notice exception handling is taken care of. Such methods start with an underscore not to cause naming conflicts with existing Struts Action methods.

private
ActionForward _loadItemsForSale( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws
Exception { ActionForward forward =
null
;
final
org.apache.struts.action.ActionMessages errors =
this
.getExceptionHandlerErrors(request);
try
{
if
(
this
.errorsNotPresent(request)) { PurchaseControllerFactory.getPurchaseControllerInstance().loadItems( mapping, (EnterNameAndPasswordProceedForm)form, request, response); }
if
(
this
.errorsNotPresent(request)) { forward = _promptUserWithItemList(mapping, form, request, response); } }
catch
(Exception ex) {
final
String messageKey = PatternMatchingExceptionHandler.instance().handleException(ex); errors.add(ActionMessages.GLOBAL_MESSAGE,
new
ActionMessage(messageKey)); }
finally
{ }
if
(!errors.isEmpty()) { forward = mapping.getInputForward(); }
return
forward; }

Action classes and action forms, and struts-config.xml too for that matter, are never manually edited when using AndroMDA.

Screenshots

The screenshots shown here are taken from the Online-Store sample, which is part of the AndroMDA distribution, for more information on the samples please go here .

(Larger View)

This screenshot shows a typical custom login screen, note how the passwords are masked using asterisks. The password confirmation is also automatically rendered into the page using JavaScript (server-side validation will also be performed). The tooltip is shown when hovering over an input field, in this case the password field. Also notice the online-help link at the bottom of the screen.

(Larger View)

Another screen showing some different types of input fields, depending on the type of the expected input (integer, date, email, creditcard, url, ...) a specific validation will be performed to make sure the user does not needlessly call the server. This validation makes use of the Struts validation framework.

(Larger View)

This screen is what you see when you click on the online-help link: a list of actions, input fields and corresponding documentation. What you see here is (like everything else in this how-to) 100% generated by the cartridge, information can be added on the corresponding element in the UML model.

(Larger View)

Did you notice the little calendar icon next to the date input field ? If you click it you will get a popup like this from which the date can be selected. Depending on the desired input format it will be formatted correctly.

Next

Use-cases usually execute custom code, later we will see how to do that, first you will need to understand how to assign a controller to a use-case, this is explained in the next section.