Getting started with Lexaden Web Flow


Lexaden Web Flow (LWF) is the next generation framework with the asynchronous language allowing to program an algorithm of systems behavior on a higher level. Similar to how browser interprets HTML code - LWF engine interprets business model written on Lexaden Web Flow to the complete applications. Asynchronous or dynamic business model managed by external events brings a new way of building enterprise applications.

A Flow-Based Architecture

Lexaden Web Flow is based on a finite state machine implementation but provides extra functionality to support inheritance, polymorphism and flow execution within the same configuration.

A flow encapsulates a sequence of steps that guide a user through the execution of some business task. Applications developed with LFW are treated as one big wizard. Users can start communicating with the systems from any entry point and systems will lead them opening up the predefined steps of the particular business model.

Lexaden Web Flow includes:

  • Event Processor - used to trigger and transport flow events within the application.
  • Controller -  is responsible for creation and initialization of a View. It receives events from the View and from the LWF engine and prepares corresponding views to display.
  • Layout Controller - responsible for construction of layout view with appropriate placeholders within it. Later State Controller prepares and injects child views into that layout view. This allows building views dynamically depending on external events.
  • State Controller - a facade class controlling application state. It invokes annotated methods and injects Views into placeholders of appropriate layout views.
  • View is based on Vaadin component model. It can be also any other component framework as well.

Having a flow-based architecture, LWF is extremely configurable and extensible.

Lexaden Web Flow and MVC

Lexaden Web Flow is the result of lessons learned over several years of experience in Java Web-development.

Controller is responsible for creation and initialization of a View. It gets data from the Model and updates the View. Controller receives events from a View and fires application events using an event processor.

View is a composite Vaadin component. A View can be built with ease using Vaadin component model..

Model could be any data received from any service of the application. The Model is used by the Controller to populate the View. And the Model can be updated by the Controller.

Event Model. The main disadvantage of the many MVC frameworks they do not have well-designed event model. Usually they use the Publish/Subscribe pattern. It's very difficult to follow the pattern because you have to create EventListeners and Custom Events for every reusable module in the application. This increases the number of classes in the application. Also it's hard to maintain state of publishers and subscribers while changing the state of the application.

LWF uses the well designed event model based on statechart to avoid issues described above . Controllers are connected to states. State transitions are driven by events. Depending on the current state the application can receive only subset of events from the user. Changing the application state the allowed events are also changing.

This section focuses on the step-by-step creation an application with Vaadin + LWF. The example application is a simple Patient Registration application that demonstrate the following aspects of using LWF technology:

  • How to lay out a LWF application for deployment
  • How to configure a web.xml
  • How to configure demo.flows.xml file for an application
  • Writing Controllers
  • Constructing the view using Vaadin technology

In subsequent sections, you'll improve the application over several iterations and make it more LWF savvy. Figure 2 shows an annotated view of what the final iteration of the example Patient Demo application will look like. See Download to get the application source.

The goal of the initial application is to help the user in filling the large form by splitting it into several small forms.

The application has:

  • Main Application Class - this is an entry point of application
  • Layout Controller - uses to define a placeholders in which to place current views
  • Welcome Screen - initial Screen
  • Welcome Controller - controls user events such as Register a New Patient event.
  • Patient Registration Screen - capture data from the user
  • Patient Controller - handles event from the user

To build the initial application you need to:

  • Declare Vaadin Application Servlet and Servlet Mapping in the Web application deployment descriptor (web.xml) file
  • Create demo.flows.xml file in WEB-INF/webflow folder
  • Create WebFlowPanelDemo application class and declare as a initial parameter in Vaadin Application Servlet in web.xml
  • Create MainLayoutController
  • Create WelcomeController

The application uses the following directory layout:

+---src

+---main

+---java

+---webapp

+---pages

+---WEB-INF

+---lib

+---webflow

The Java code is under src/main/java/. The web.xml file is under the src/main/webapp/WEB-INF directory. The flow configuration file is under src/main/webapp/WEB-INF /webflow.

To use the Vaadin Application Servlet, you first need to install it in your web.xml file, as shown in Listing 1:

Listing 1. Vaadin Application Servlet declaration in web.xml:

    <servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
        <init-param>
            <description>Vaadin application class to start</description>
            <param-name>application</param-name>
            <param-value>com.lexaden.webflowpaneldemo.WebFlowPanelDemo</param-value>
        </init-param>
    </servlet>

The init parameter 'application' defines which application class will be started by Vaadin Application Servlet. This is similar to most web.xml descriptions, except that your're giving control to the Vaadin Application Servlet to handle requests instead of specifying your own servlet.

Listing 2. Vaading Application Servlet path mapping in web.xml

    <servlet-mapping>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
 

Listing 2 tells the Vaadin Application Servlet container to send all requests to the Vaadin Application Servlet for processing.

Specify the demo.flows.xml file

The demo.flows.xml file has the root state 'application'. Usually this state is used to associate a layout controller for the application. The layout controller should contain one or several placeholders. In our case we create the "content" placeholder. The placeholder will be used later by Web Flow Engine to inject views based on the current application state.

    <application id="application" extends="controller">
        ...
    </application>

The WebFlowPanel has a bindContoller method. It's used to bind a controller with the specific state of the application and to bind with the certain placeholder.

flowPanel.bindController("application", "content", new MainLayoutController());


The listing 3 shows how the MainLayoutController is bound to 'application' state.

The 'application' state contains initial state "initView". This is an action state which is used to initialize the main layout of the application. Annotation @OnEnter("initView") is used to bind the action state with the corresponding method in the bound controller.

    <application id="application" extends="controller">
        <action id="initView" extends="action">
            <on to="displayView" type="flow"/>
        </action>
        ...
    </application>

public class MainLayoutController  {
    @OnEnterState("initView")
    public void initView(StateEvent event) {…}
} 


The MainLayoutController defines a main layout of the application and creates the 'content' placehodler.

The transition "displayView" in the "initView" action state will be invoked automatically by the Web Flow Engine. The transition has the "flow" type which indicates a new flow within the Web Flow Engine. The flow is responsible to keep the execution flow of the current user session. The flows are used to handle different entry points within the application and keep them separately from each other.

Further the application goes to the "application/displayView" state. At this stage the layout is initialized and it's ready to be displayed to the user.

The "application/displayView" state contains two controller states "welcome" and "register". The "welcome" controller state is used to create the "welcome" screen and to handle user inputs from it. The "register" controller state is used to process a new patient registration.

The WelcomeController is bound with the "welcome" state using the following code:

flowPanel.bindController("welcome", "content", new WelcomeController());

Such as the "welcome" controller extends the "controller" state it inherits initial attribute, action and view states. The Web Flow Executor goes to the "initView" action then to the "displayView" view state of the WelcomeController.

The "view" type of a state indicates that the controller has prepared view to be injected into the bound placeholder of the parent layout controller.

At the "welcome/displayView" state the application waits for input from the user.

When the user clicks the "Register a New Patient" button the controller fires a "register" event.

public void register(Button.ClickEvent clickEvent) {
    getEventProcessor().fireEvent("register");
} 


According to the current state and the flow mapping the state of the application goes to "register" state.

    <controller id="welcome" extends="controller">
        <on event="register" to="register"/>
    </controller>
    <controller id="register" extends="controller">
        ...
    </controller> 


Such as the "register" controller state also extends "controller" state it inherits the "initial" attribute and the state goes to the "initView" action state.

The "register" controller state overrides "initView" from the parent state. It defines custom transition to the "personalInfo" view state.

In order to handle the state of the buttons the RegisterController class defines a method with the following annotation:

@OnEnterState(VIEW)
public void onView(StateEvent event) {...} 


This method will be invoked each time when the application enters a state that is inherited from the "view" state.

The method gets the list of available events for the current application state and enables or disables corresponding buttons.

    <view id="personalInfo" extends="view">
        <on event="next" to="address"/>
    </view> 


As we see the "personalInfo" view state has only one transition with the "next" event. Only the "Next" button will be enabled then.

At the final screen of the flow there are two final actions:

    <final id="finish" extends="action"/>
    <final id="cancel" extends="action"/> 


The final action is used to finish a part of the execution flow. The context of this flow is defined by the controller bounders.

The flow controller pushes in a stack all controller visited by the flow. When the controller visits the final state. A final event occurred with the name of current controller and the name of the final state.

For instance:

register.finish

Which means the "register" controller just reached the final state "finish". This event is transferred to previous controller by default. Where you can map it to a transition.

In our sample we just declare that the event is available for handling by the controller using the "OnEvent" annotation.

    <controller id="welcome" extends="controller">
        ...
        <on event="register.finish"/>
    </controller> 


@OnEvent("register.finish")
public void registrationFinished(StateEvent stateEvent) {…} 


Think about a flow inside a controller like a function in a programming language where you call the function by sending an event and the function returns the result using the final event. As a result the previous controller will receive the control and can handle the final event.

The "cancel" event is accessible from any view of the "register" controller state such as it's declared at the controller level.

    <controller id="register" extends="controller">
        ...
        <view.../>
        <view.../>
        <view.../>
        ...
        <on event="cancel" to="cancel"/>
        ...
    </controller> 


The "cancel" event leads to the final "cancel" state.

    <controller id="register" extends="controller">
        ...
        <on event="cancel" to="cancel"/>
        <final id="cancel" extends="action"/>
        ...
    </controller> 


Which triggers the "register.cancel" event and transfers control to the previous controller in the flow e.g. the "welcome" controller.

    <controller id="welcome" extends="controller">
        ...
    </controller>
    <controller id="register" extends="controller">
        ...
        <final id="cancel" extends="action"/>
    </controller> 


Such as we don't need any action upon cancelation of register flow we do not declare corresponding transition in the "welcome" controller. Otherwise we could specify the following transition:

    <on event="register.cancel"/>
 

And create an annotation over a method in the WelcomeController.java in order to handle it:

@OnEvent("register.cancel")
public void someMethod(StateEvent stateEvent) {…} 
 

Writing Controllers

When the application enters into the "personalInfo" state it invokes the "initPersonalInfo" method. The code changes the caption and sets visible items on the form.

    @OnEnterState(PERSONAL_INFO)
    public void initPersonalInfo(StateEvent event) {
        panel.setCaption("Enter Personal Information");
        patientForm.setVisibleItemProperties(new String[]{
                "patientNo",
                "title",
                "firstName",
                "lastName",
                "middleName",
                "dateOfBirth",
                "gender"
        });

    }

The same works for other view states - "address", "contacts", "medicalInfo", "medicalNotes".

Buttons fire corresponding events to the event processor. The processor changes the state of the application and invokes the view related methods.

    public void next(Button.ClickEvent event) {
        ...
        getEventProcessor().fireEvent(NEXT);
    }

    public void previous(Button.ClickEvent event) {
        getEventProcessor().fireEvent(PREVIOUS);
    }

    public void finish(Button.ClickEvent event) {
        ...
        getEventProcessor().fireEvent(FINISH, patient);
    }

    public void cancel(Button.ClickEvent event) {
        getEventProcessor().fireEvent(CANCEL);
    }

Constructing the view using Vaadin technology

It is fairly simple to build user interfaces using Vaadin component framework. Very complex forms and layouts can be build in minutes.

    @OnEnterState(INIT_VIEW)
    public void initView(StateEvent event) {
        panel = new Panel("");
        panel.setSizeUndefined();

        final HorizontalLayout splitter = new HorizontalLayout();
        splitter.setSpacing(true);

        final VerticalLayout formLayout = new VerticalLayout();

        final HorizontalLayout hl = new HorizontalLayout();
        hl.setSpacing(true);

        previous = new Button(Constants.PREVIOUS_TITLE, this, PREVIOUS);
        next = new Button(Constants.NEXT_TITLE, this, NEXT);
        finish = new Button(Constants.FINISH_TITLE, this, FINISH);
        cancel = new Button(Constants.CANCEL_TITLE, this, CANCEL);
        hl.addComponent(previous);
        hl.addComponent(next);
        hl.addComponent(finish);
        hl.addComponent(cancel);

        patient = new Patient();
        patientForm = new PatientForm(patient);
        patientForm.setHeight(250f, Sizeable.UNITS_PIXELS);

        formLayout.addComponent(patientForm);
        formLayout.addComponent(hl);

        splitter.addComponent(formLayout);

        panel.addComponent(splitter);
        setView(panel);
    }

But using Java to construct the UI brings the following pros and cons:

Pros: You get all the benefits of using IDE such as syntax highlighting, refactoring, easy access to any utilities. It's very easy to change the behavior of components by extending them. Custom and composite components can be created without any additional mappings and configurations.

Cons: You don't see the overall structure of the user interface. Using Java it is easy to mix the UI structure logic with the UI behavior rather than using declarative XML approach. XML gives much more sophisticated picture of the UI structure. And XML encourages separation of UI structure from the UI behavior. Partially this problem can be solved using Vaadin Add-ons. 

Run the application

To run the application, go to the page where the WAR file is mapped (http://localhost:8080/webflow/)

Once you click on the Register a New Patient button the first registration screen appears:

Please notice only the Next and Cancel buttons are enabled at this stage.

The next "Enter Address" screen appears when you click the "Next" button.

By filling the forms and clicking the "Next" button the last "Enter Medical Notes" screen appears:

At this screen the "Finish" button is enabled along with "Previous" and "Cancel" buttons.

By clicking on the "Finish" button the application finishes the registration flow and returns to the "Welcome" screen .The last screen will show us the First and Last names of the registered patient as a result.

Conclusion

Looking at the application and flow configuration a question arises: what benefits could this approach give us?

If you have well defined fine-grained loosely coupled forms/panels/pages/whatever then this approach allows you to reuse them in different flows without involving a programmer.

Or imagine a situation when you don't need anymore the last step of the flow. In our case you just remove the last step from the xml configuration and instead of next event of the "medicalInfo" add the transition to the "finish" action. That will be enough for changing the business process.

In the case when the flow logic is coded inside java class it usually looks like a bunch of enclosed if/else statements. The programmer can change the business logic only.

Also using the flow xml you can see the whole business process at a glance in the format that could be easily understand by non-programmers such as functional and business analysts, managers, product owners.
The loosely coupled approach introduced in the tutorial and comprehensive event model based on the extended statechart notation will allow you to build agile, scalable and robust applications.

Downloads

Download Lexaden Web Flow Sample - Vaadin 7.0.0 - 3.5 MB - available under  Apache Licence 2.0


Lexaden
Easy to keep focus on business needs