Reference

This reference contains detailed information about the Orkwan framework and should be sufficient for most web application development. It does not however cover all aspects of Orkwan nor does it explain all details of the API:s. To get more in depth understanding of how Orkwan works the reader is referred to the javadocs (which can be generated using the build script in the complete distribution of Orkwan) and to the source code itself (which is also included in the complete distribution).

  1. Request Processing
  2. MyServlet (inherits from OrkwanServlet)
  3. MyController (inherits from OrkwanController)
  4. orkwan.xml
  5. Controller invocation by URL parameter (?action=helloworld)
  6. Controller invocation by URI (/demo/helloworld)
  7. Controller invocation by file name (helloworld.html)
  8. Controller properties
  9. Controller output (view)
  10. Accessing the controller in a JSP
  11. Controller data
  12. Output encoding
  13. Controller lookup
  14. Execution and flow control
  15. Inheritance hierarchy



Request Processing

The following figure describes the http request processing in a web application based on the Orkwan framework. The required application components, here named MyServlet, MyController, and the orkwan configuration file orkwan.xml, are explained in the following chapters.

Orkwan request processing

  1. An incoming http request is dispatched to the class MyServlet. The class MyServlet inherits from the abstract base class OrkwanServlet in the Orkwan framework. MyServlet is defined in the standard java web.xml file as the receiver of the incoming http request.
  2. Based on the URL of the http request MyServlet will create a new instance of a controller and execute the controller. The mapping between the URL and the controller class is defined in the orkwan configuration file orkwan.xml. The MyController class inherits from the abstract base class OrkwanController.
  3. The controller is responsible for executing the request. It validates the request, operates on the business model, and creates a view.
  4. After execution of the controller the framework calls a view target, either a JSP (Java Server Page) or a servlet, to create a view. In both cases a relative URL to the web application root is specified to identify the view target. If the url matches the servlet mapping för MyServlet a cascaded execution of controllers will occur. The definition of the view target for a controller is made in the file orkwan.xml.
  5. The controller can also directly generate the view output as html source or an xml document. The controller can even write directly on the fly to the http response if the view is defined as custom in orkwan.xml.
  6. At the end of the request processing a http response is sent back to the user.



MyServlet (inherits from OrkwanServlet)

MyServlet is the main control servlet in the web application. It inherits from the abstract base class OrkwanServlet in the Orkwan framework. MyServlet must implement all methods which are declared abstract in the base class OrkwanServlet. These methods are designed to be key placeholders which allow a web application to customize the default behavior in the Orkwan framework. The required methods in MyServlet are:

  1. handleError(): this method is invoked by the framework when an error (throwable) occurs during processing a request. The error (throwable) as well as the executing controller where the error occured is available for handling. A typical implementation of this method will call the log function in the application and redirect the user to an error page.
  2. handleNotFound(): this method is invoked by the framework when it can not find a controller matching the URL of the request (equivalent to a 404 response code in a web server). A typical implementation of this method will redirect the user to a page explaining that the resource can not be found.
  3. init(): this method is invoked by the framework to allow for different kinds of initialization when a new request is to be processed.
  4. validate(): this method is invoked by the framework to validate a new http request. Typical validation may involve verifying the http session, cookies, and other general request data.



MyController (inherits from OrkwanController)

MyController inherits from the abstract base class OrkwanController in the Orkwan framework. MyController must implement all methods which are declared abstract in the base class OrkwanController. These methods are designed to be key placeholders for defining the logic of a general web function. The required methods in MyController are:

  1. init(): this method is invoked by the framework to initialize the controller.
  2. validateInput(): this method is invoked by the framework to validate the request. A typical implementation may get and validate the input parameters of the request and save them as internal variables for later processing of the business model.
  3. updateModel(): this method is invoked by the framework to operate on the business model of the application. This method is where the business logic of the controller should be placed.



orkwan.xml

orkwan.xml is the root configuration file for the Orkwan framework. It defines the mapping between a request URL, the controller to execute, and the output view to create. It can also define a number of other properties for the orkwan framework which are described in more detail throughout this reference. An example of an orkwan.xml file is:

[orkwan.xml]

<orkwan>

   <include file="/demo/search/search.orkwan.xml"/>

    <controllers>
        <controller>
            <class>demo.MyController</class>
            <url-parameter name="action" value="helloworld"/>
            <view>/helloworld.jsp</view>
        </controller>
    </controllers>
</orkwan>

The configuration above means that the controller demo.MyController will be executed for an input url containing the url parameter action=helloworld (e.g. http://www.orkwan.com/demo?action=helloworld ), and the output view is /helloworld.jsp.

The <include> tag specifies the location of another orkwan configuration file. The location is specified relative to the web application root. The content of the file is also included in the configuration of the Orkwan framework.

To completely remove all execution of Orkwan controllers in the application, define the following configuration in orkwan.xml:

<orkwan>
    <controllers>
    </controllers>
</orkwan>

Simply removing the orkwan.xml file or deleting all content from the file will not work since the Orkwan framework will fail to initalize.




Controller invocation by URL parameter (?action=helloworld)

One way of invoking a controller is to invoke it by URL parameter. To invoke a controller by url parameter the tag <url-parameter> must be included in the controller definition as shown below:

[orkwan.xml]

<orkwan>

    <controllers>

        <controller>
            <class>demo.MyController</class>
            <url-parameter name="action" value="helloworld"/>
            <view>/helloworld.jsp</view>
        </controller>

    </controllers>
</orkwan>

The configuration above means that the controller demo.MyController will be executed for an input url containing the url parameter action=helloworld (e.g. http://www.orkwan.com/demo?action=helloworld ), and the output view is /helloworld.jsp. The value of the view tag is a relative url to the web application root, hence the root slash, "/", must be included in the path to the JSP file.




Controller invocation by URI (/demo/helloworld)

A controller can be invoked by URI. URI is an abbreviation for Uniform Resource Identifier and is defined as "the part of the url from the protocol name up to the query string". An example of the relationsship between URI and URL is given below.

URL = http://www.orkwan.com/demo/helloworld?name=jamesbond
URI = /demo/helloworld

To invoke a controller by URI the <uri> tag must be specified in the configuration of the controller as shown below:

[orkwan.xml]

<orkwan>

    <controllers>

        <controller>
            <class>demo.MyController</class>
            <uri>/demo/helloworld</uri>
            <view>/helloworld.jsp</view>
        </controller>

    </controllers>
</orkwan>

The configuration above means that the controller demo.MyController will be executed for an input url containing the uri /demo/helloworld (e.g. http://www.orkwan.com/demo/helloworld ), and the output view is /helloworld.jsp.

Regular expressions

The URI can also be specified using a regular expression. In some web applications the first part of the URI serves as a country or market identifier, and the second part specifies the actual web funtion, like in the following example:

URI 1 = /se/helloworld
URI 2 = /uk/helloworld
URI 3 = /de/helloworld
URI 4 = /fr/helloworld
...

In this case the controller is matched using the second part of the uri, not taking the first part containing the country identifier into account. To do this matching a regular expression must be used in orkwan.xml.

[orkwan.xml]

<orkwan>

    <controllers>

        <controller>
            <class>demo.MyController</class>
            <uri>/[\w_]+/helloworld</uri>
            <view>/helloworld.jsp</view>
        </controller>

    </controllers>
</orkwan>

An in depth tutorial on how to use regular expressions in Java is found here.

Attribute uri-root

If several controllers are matching the same basic URI pattern they can be grouped together in a controllers tag and the attribute uri-root can be specified. When a uri-root is specified the uri-root is prepended the uri in the controller tag (if a uri is defined in the controller).

[orkwan.xml]

<orkwan>

    <controllers uri-root="/[\w_]+/">

        <controller>
            <class>demo.MyController</class>
            <uri>helloworld</uri>
            <view>/helloworld.jsp</view>
        </controller>

    </controllers>

</orkwan>

Cascaded controllers and relative addressing

Sometimes it is of interest to execute one controller after the other. In case the uri contains a country identifier as described above it may be necessary to specify the cascaded view (controller) using a relative url. For example, if MyController is executed, the LoginController must also be executed as shown below:

URL 1: http://www.orkwan.com/se/helloworld   => execute MyController

then continue to execute LoginController:

URL 2: http://www.orkwan.com/se/login   => execute LoginController

In this case an uri matching /se/helloworld will lead to a cascaded execution of /se/login. The problem is that the value of the country identifier in the uri, /se, is not known since MyController was matched using a regular expression. The solution is to use a relative addressing in the output view of MyController:

[orkwan.xml]

<orkwan>

    <controllers uri-root="/[\w_]+/">

        <controller>
            <class>demo.MyController</class>
            <uri>helloworld</uri>
            <view>./login</view>
        </controller>

        <controller>
            <class>demo.LoginController</class>
            <uri>login</uri>
            <view>/login.jsp</view>
        </controller>
		
    </controllers>

</orkwan>

The ./ value tells the servlet container that the address is relative and that addressing shall begin at the current directory which is /se  (the /helloworld at the end of the path is perceived by a servlet container as the name of a file, not a directory).




Controller invocation by file name (helloworld.html)

A controller can be invoked by file name, e.g. helloworld.html. To invoke a controller by file name use the URI invocation method. For example, to invoke the controller for the url http://www.orkwan.com/demo/helloworld.html use the following URI matching:

[orkwan.xml]

<orkwan>

    <controllers>

        <controller>
            <class>demo.MyController</class>
            <uri>/demo/helloworld.html</uri>
            <view>/helloworld.jsp</view>
        </controller>

    </controllers>
</orkwan>



Controller properties

A controller is configured by a set or properties. A property can be set by either an attribute or a tag in the orkwan.xml configuration file. The core properties which are reserved for use by the Orkwan framework are:

Property (tag)Required Description
classyesSpecifies which java controller class to invoke
url-parameter*yesSpecifies which url parameter to match controller to
uri*yesSpecifies which uri to match controller to
viewyesSpecifies view target

(* either url-parameter or uri must be specified).

In addition to the generic Orkwan properties described above user defined properties can be added to the xml configuration of a controller and retrieved during runtime using the method getControllerProperty(String property). There are two ways of adding a property to a controller:

  1. XML attribute in the controller tag, or
  2. XML sub tag to the controller tag

In the first example it is shown how to add property, recaptcha, with value demo, as an XML attribute to a controller.

[orkwan.xml]

<orkwan>

    <controllers>

        <controller recaptcha="demo" >
            <class>demo.MyController</class>
            <uri>/demo/helloworld</uri>
            <view>/helloworld.jsp</view>
        </controller>

    </controllers>
</orkwan>

The next example shows how to add a property, recaptcha, with value demo, as an XML sub tag to a controller.

[orkwan.xml]

<orkwan>

    <controllers>

        <controller>
            <class>demo.MyController</class>
            <uri>/demo/helloworld</uri>
            <view>/helloworld.jsp</view>
            <recaptcha after="20210327:13.00.00">demo</recaptcha>
        </controller>

    </controllers>
</orkwan>

The xml sub tag method enables the use of grouping properties by declaring XML attributes on the sub tag. An attribute, after, has been added to the recaptcha tag. The property recaptcha, and the attribute after are available as controller properties in the MyController class. To get the values of the properties the following code can be used in MyController:

    String g = getControllerProperty("recaptcha");
    String a = getControllerPropertyAttribute("recaptcha", "after");



Controller output (view)

The output of a controller is defined by the content of the <view> tag. A controller can generate different kinds of output as described in the table below.

Output type<view> tagDescription
PAGE<view>/index.jsp</view> Path to JSP page or servlet from web application root (/).
DOCUMENT<view type="xml"/>XML document output. To create the XML document override method createDocument() in the controller, or use setDocument() in e.g. updateModel().
SOURCE<view type="html"/> HTML source output. To create the html source override method createSource in your controller, or use setSource() in e.g. updateModel().
CUSTOM<view type="custom"/> No output is generated by the framework. The output must be created by the controller itself (by accessing the Writer in the response).

If several controllers define a view which is located in a specific directory of the web application a view root may be defined in the controllers tag. For example, if all jsp:s are located directly under the web application root the root slash may be defined as view-root. In this case, the individual view tags do not have to be prepended with the root slash.

[orkwan.xml]

<orkwan>

    <controllers view-root="/">

        <controller>
            <class>demo.MyController</class>
            <uri>/demo/helloworld.html</uri>
            <view>helloworld.jsp</view>
        </controller>

    </controllers>
</orkwan>

Changing the view

There are several ways to change the configured view or output type during execution of a controller:




Accessing the controller in a JSP

The controller carries data from the domain model to the creation of the view in the JSP. The controller responsible for executing a request is saved as an attribute in the request under the key "controller". To get the controller in a JSP call: pageContext.getAttribute("controller", PageContext.REQUEST_SCOPE)

The following code shows how to get the controller in a JSP:

[helloworld.jsp]

<%@ page import="demo.MyController" %>
<%
    MyController controller =
      (MyController) pageContext.getAttribute("controller", PageContext.REQUEST_SCOPE);
%>
<html>
<head>
    <title>Hello World</title>
</head>
<body>
    <p>Hello World from <%=controller.getModelData("name")%>!</p>
</body>
</html>



Controller data

To carry data from the request to the business model to the view the controller contains an internal HashMap. In the hashmap any type of data can be stored. The data is stored using a key. The standard getters and setters are:

type set methodget method
StringsetModelData(String key, String value)getModelData(String key)
IntegersetModelInt(String key, int value)getModelInt(String key)
BooleansetModelBoolean(String key, boolean value)getModelBoolean(String key)
ObjectsetModelObject(String key, Object value)getModelObject(String key)

In addition to the generic hashmap common in all controllers it is of course possible to define new member variables of any type to carry data from model to view. It is also possible to define "wrapper" getters/setters for custom objects which internally operate on the internal hashmap but externally look like getters/setters for custom member variables.

Note also that data stored in the generic hashmap is automatically copied to the next controller in case of cascaded controller execution.




Output encoding

The default character encoding in Orkwan is UTF-8. To set a different character encoding in the output response use the method setEncoding(String encoding). For example, to create a response using the character set iso-8859-1 use the following code in your controller:

    setEncoding("iso-8859-1");

The encoding can be set any time during the controller life cycle. After the controller has finished executing the framework will use the encoding value to set the content type on the response and to create an output stream using the specifed character set. The servlet specification guarantees that as long as the content type is set before the output is written the response will be encoded using the content type.

The encoding will apply to all kinds of output types and views. However, in the case of a JSP the following should be noted:




Controller lookup

Setting controller lookup properties may significantly improve controller lookup performance especially for large web applications. Controller lookup properties can only be set in the Orkwan root file configuration file orkwan.xml. The lookup element consists of three properties:

The following table shows all possible combinations of the primary and secondary lookup properties and how they control the lookup of controllers in Orkwan:

lookup primarylookup secondaryDescription
uri - Only the uri part of the http request will be matched to controllers
uriurl-parameterThe uri of the request will first be matched to controllers. If there is no match the url parameters in the request will be matched.
url-parameter - Only the url parameters of the http request will be matched to controllers
url-parameteruriThe url parameters of the request will first be matched to controllers. If there is no match the uri in the request will be matched.

An example of a lookup tag element is given below. The values shown are the default lookup assignments in Orkwan.

[orkwan.xml]

<orkwan>

    <lookup>
        <primary>url-parameter</primary>
        <secondary>uri</secondary>
        <parameter>action</parameter>
    </lookup>

</orkwan>



Execution and flow control

The execute() method in class OrkwanController lies at the heart of the Orkwan framework. This is the only method that is called by the framework after the controller has been created and it encapsulates the entire work flow in Orkwan. The content of the method is shown below:

[OrkwanController.java]

    /**
     * Execute controller
     */
    public void execute() throws Exception
    {
        // boot controller
        boot();

        // init controller
        init();

        // validate input
        validateInput();

        // update model
        updateModel();

        // create output
        createOutput();

        // exit handling
        exit();

        // successful execution
        setSuccessful();
    }

The chain of methods in the execute() method makes up the execution flow in a controller. Some of these methods must be implemented when creating a controller, others can be overridden to customize the execution flow in a controller.

MethodAbstractDescription
bootnoThe boot() method is implemented in OrkwanController and the framework implementation takes care of various things such as verifying the request, copying model data from previous controllers in cascaded execution and setting http response headers
inityesinit() must be implemented in a subclass to OrkwanController. Use the method to initialize a controller.
validateInputyesvalidateInput() must be implemented in a subclass to OrkwanController. Use this method to validate input parameters and data in the http request. Do not put validation of database data in the model here.
updateModelyesupdateModel() must be implemented in a subclass to OrkwanController. Use this method to operate on and update the business model. This method usually contains the actual work done by the controller.
createOutputnoThe createOutput() method creates the output based on the configuration of the controller. Note that this method does not actually write any data to the http response, it only creates and sets the output data
exitnoThis method is a hook to allow for exit handling in a controller. The framework implementation is empty.
setSuccessfulnoIf the controller executes without an exception the setSuccessful method will set the successful execution flag of the controller to true.

Methods declared as Abstract must be implemented when creating a controller. If they are not abstract and already implemented in the base class OrkwanController they can still be overridden to customize the execution flow in a controller. Note however that overriding a method defined in OrkwanController is potentially dangerous and any override should begin with invoking the super.method() implementation to preserve the integrity of the Orkwan framework.

Controlling the flow of execution

Sometimes it is of interest to change the flow of execution as defined in the execute() method. For example, if validation fails in the validateInput() method it may not of interest to continue the normal execution but instead to abort the execution and show the user an error page. For this purpose there are methods that change the flow of control available. They all throw different types of ControlFlowException to change the execution flow.

To change the control flow it is also possible to throw a ControlFlowException directly. There are three different kinds of control flow exceptions available: RedirectException, IncludeException, and ForwardException.




Inheritance hierarchy

A good way of leveraging the Orkwan framework is to use inheritance as a mechanism for grouping common behavior in an application. By defining a local base class controller and inheriting from this controller rather than directly from OrkwanController, a natural placeholder for common functionality is obtained in the application. If the application contains several distinctive areas of functionality, e.g. a public web site, and an internal administrative console, a local base class controller should be defined for each specific area of functionality. The following figure depicts an application inheritance hierarchy for a web site with a public interface (base class MyController) and an admin console (base class MyAdminController).

Inheritance hierarchy based on Orkwan MVC framework

The local base classes, MyController and MyAdminController, are both declared abstract and only function as placeholders for common validation, business logic, logging etc. They are not real classes which can be used for executing a web function. The real web functions are performed by subclasses to the local abstract base controllers. By not implementing the framework methods init(), validateInput(), updateModel(), in the local abstract base class controllers the subclasses are still forced to implement these methods and thus uphold consistency with the main execution flow in the Orkwan framework. In addition, new abstract methods may be defined to further impose a uniform implementation in the application controllers.