SINS (SINS Is Not Struts) web controller framework is a simple controller framework for web applications written in Java programming language and published under a GNU Lesser General Public License. Implementation is based on standard Java Servlet, Java Server Pages tag library and XML technologies and runs in standard Servlet containers.

Table of contents

Overview

Java web applications are implemented using Servlets and Java Server Pages (JSP pages). Common approach for implementation of Model-View-Controller architecture in web applications is to use servlets as application controllers and JSP pages as views. Request from client is posted to a servlet which after calling (or performing) the appropriate business logic forwards the client request to a proper JSP view. This basic controller model is presented in the following picture.

Usually transitions from servlets to JSP views and vice versa are hard coded to servlets which has clear disadvantages.

Well, SINS web controller framework saves the day. Goal for the framework is to separate the presentation layer from the controller logic by using XML document to describe the transitions between the views. Additionally framework supports pluggable modules (written in Java) for controlling the web application flow. The improved web controller model is presented in the following picture.

As the name of the project implies SINS has many similiarities to widely used web application framework called Struts. SINS differs from struts by being light-weight controller framework without any additional features such as automated HTTP form parsing or utilitary tag libraries. For these web user interface enhancements please refer to the WUIT (Web User Interface Toolkit) project (work in progress) that supports integration with SINS by extending the pluggable SINS modules.

Requirements and compatibility

Requirements for using the SINS web controller framework are:

SINS library has been tested to work on many free and commercial application servers / web containers such as BEA Weblogic 7.x - 8.x, Orion Application Server 1.x - 2.x and Tomcat v4.x.

Features

The following list describes some main features of the SINS web controller framework:

Usage and Examples

Installation

The installation of SINS library is simple. Copy the library jar (sins-1.0.1.jar) to web applications classpath e.g. /WEB-INF/lib. Edit the web.xml file to map the SINS controller servlet to all URLs ending with .sins as follows:

    ...
    <servlet>
        <servlet-name>SINSController</servlet-name>
        <description>SINS controller servlet</description>
        <servlet-class>sins.servlet.Controller</servlet-class>
        <!--
            SINS init parameters. All SINS specific XML files
            should be placed to web apps WEB-INF/ directory.
        -->
        <init-param>
            <!-- Our sites and states are configured in this file -->
            <param-name>siteconfiguration</param-name>
            <param-value>sinswebsite.xml</param-value>
        </init-param>
        <init-param>
            <!-- Our SINS components are defined in this file -->
            <param-name>componentconfiguration</param-name>
            <param-value>sinscomponents.xml</param-value>
        </init-param>
        <init-param>
            <!-- Our logging configuration (apache log4j is used) -->
            <param-name>log4jconfiguration</param-name>
            <param-value>log4jconfiguration.xml</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>SINSController</servlet-name>
        <url-pattern>*.sins</url-pattern>
    </servlet-mapping>
    ...

Configuration and usage

There are three different XML configuration files for SINS.

All three configuration files are discussed below.

To understand the format of configuration files some basic concepts of SINS must be explained. SINS controller servlet is called with URL in following format:

        /<site>.<state>[.<action>].sins

From the URL above the controller servlet parses the following information:

The URL ending .sins is just a suffix used in servlet mapping and has no actual function.

For example if the URL the controller is called with is

        /adminweb.useradmin.add.sins

.. the controller calls the action "add" from the action module associated with the state "useradmin" in the site "adminweb". If the module is an action module (instance of sins.actions.ActionBase) the method actionAdd(...) is invoked from the module.

Site configuration file declares the sites, states and transitions (targets) from application state to another. The format for site configuration file is as follows:

    <?xml version="1.0" encoding="iso-8859-1"?>
    <!DOCTYPE sites SYSTEM "sinswebsite.dtd">
    <sites>
        <!-- new site definition, name is mandatory -->
        <site name="site name"
              [defaulterrorstate="state name"]
              [noaccessstate="state name"]
              [rolevalidator="role validator name in component configuration file"]
              [urlfilter="URL filter name in component configuration file"] >
            <!-- new state definition, name is mandatory -->
            <state name="state name"
                   [module="module name"]
                   [userinrole="security roles separated by ,"]
                   [usernotinrole="security roles separated by ,"]
                   [urlfilter="URL filter name in component configuration file"] >
                <!-- new target definition, type is mandatory, target state OR target url is mandatory -->
                <!-- if name is undefined target is treated as default target -->
                <target [name="target name"]
                        type="redirect | forward | include"
                        [state="state name" | url="url"]
                        [userinrole="security roles separated by ,"]
                        [usernotinrole="security roles separated by ,"]/>
            </state>
        </site>
    </sites>

Site elements represent individual web sites run with SINS framework. For example if a web application has public internet pages and secured administration pages these can be defined as separate SINS sites. All sites must have an unique name. Additionally a site may have an attribute named defaulterrorstate which is the name of the state the servlet should redirect the request to if an unexpected exception is caught from some SINS module. The attribute named noaccessstate works in similar fashion: If a user's request tries to access a state or a target the user has no access to the controller redirects the request to the state defined as the noaccessstate attribute. The last to attributes are names of the components declared in component configuration file. rolevalidator attribute defines the name of role validator component used to authenticate the current user against the user roles declared in states and targets (see below). Similarly the urlfilter attribute defines the name of URL filter component used globally in this site to filter all URLs when executing the transitions from a state to an URL. It should be noted that this URL filter declaration can be overridden in state element as explained below.

State elements represent the different application states the web site can have. All states have an unique name and they may have SINS modules associated with them (module attribute). Everytime a client request ends up in a state with a module associated the request is passed to the associated module. Additionally a state can be authorized only for a set of user roles. These roles are defined with element attributes userinrole and usernotinrole. Both role-attributes can contain multiple user roles separated with a comma. Lastly the attribute urlfilter describes the name of the URL filter component used to filter all URLs when executing transitions from this state to an URL. This attribute overrides the site-wide urlfilter attribute defined in site element.

Target elements define the transitions from a state to another. These targets are triggered by modules associated with the state. Only mandatory attribute for a target is the type of the target. The type describes the method of the transition:

If the attribute name is not defined for a target the target is considered to be the default transition that should take place in this state. If defined, the name should be unique. The named target is triggered for a transition if the module associated with the state returns the name of the target as a response. The destination the triggered transition should be made to is defined with the state or url attribute. Additionally a target transition can be authorized only for a set of user roles. These roles are defined with element attributes userinrole and usernotinrole. Both role-attributes can contain multiple user roles separated with a comma.

For example site configuration file please see Examples subsection.

Component configuration file declares the SINS components and component initialization properties. There are three different kinds of SINS components:

The format for component configuration file is as follows:
    <?xml version="1.0" encoding="iso-8859-1"?>
    <!DOCTYPE components SYSTEM "sinscomponents.dtd">

    <components>

        <!-- new module definition, name is mandatory -->
        <module name="module name">
            <!-- module class, mandatory -->
            <class>full class name</class>
            <!-- properties for module, optional -->
            <properties>
                <property name="name of the property">
                    <value>value of the property</value>
                </property>
            </properties>
        </module>

        <!-- new role validator definition, name is mandatory -->
        <rolevalidator name="role validator name">
            <!-- role validator class, mandatory -->
            <class>full class name</class>
            <!-- properties for role validator, optional -->
            <properties>
                <property name="name of the property">
                    <value>value of the property</value>
                </property>
            </properties>
        </rolevalidator>

        <!-- new URL filter definition, name is mandatory -->
        <urlfilter name="URL filter name">
            <!-- URL filter class, mandatory -->
            <class>full class name</class>
            <!-- properties for URL filter, optional -->
            <properties>
                <property name="name of the property">
                    <value>value of the property</value>
                </property>
            </properties>
        </urlfilter>

    </components>
All components share a similar XML element format. The type of the element describes the component type - module, rolevalidator or urlfilter. Components implementation class is defined with an attribute named class. Components may have initialization properties that are passed to the component at the initialization stage. These properties are defined with property elements as seen above.

It should be noted that the default implementation class for role validation is sins.security.impl.GenericRoleValidator.

For example component configuration file please see Examples subsection.

Examples

All the following examples are from "the volatile diary" example application demonstrating the usage of the SINS framework. The example application can be downloaded from the official project page and browsed directly from SourceForge CVS.

The following describes the component configuration file of the example application.


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE components SYSTEM "sinscomponents.dtd">

<components>
    <!--
        Our generic role validator. This declaration is for example
        purposes only - the default role validator is the class below
        if no role validator is declared in sinswebsite.xml.
        Bundled with the SINS 1.0.1 library.
    -->
    <rolevalidator name="GenericRoleValidator">
        <class>sins.security.impl.GenericRoleValidator</class>
    </rolevalidator>

    <!--
        Localization URL filter.
        Bundled with the SINS 1.0.1 library.
    -->
    <urlfilter name="LocalizationURLFilter">
        <class>sins.urlfilters.impl.LocalizationURLFilter</class>
        <properties>
            <property name="availablelanguages">
                <value>en,fi</value>
            </property>
            <property name="defaultlanguage">
                <value>en</value>
            </property>
        </properties>
    </urlfilter>

    <!--
        Logs unauthorized user access.
    -->
    <module name="LogUnauthorizedAccessModule">
        <class>sins.example.modules.LogUnauthorizedAccessModule</class>
        <properties>
            <property name="loglineprefix">
                <value>Unauthorized access - information on request follows: </value>
            </property>
        </properties>
    </module>

    <!--
        Diary actions.
        Supports add, list, get and delete.
    -->
    <module name="DiaryActions">
        <class>sins.example.actions.DiaryActions</class>
    </module>
</components>

The role validator component described is actually the default role validator component bundled with the SINS library 1.0.1. The declaration above is for example purposes only.

The declared URL filter component is also bundled with SINS 1.0.1 and provides functionality to manipulate the transition URLs depending on user's browser locale. Please see the documentation of the implementation class (sins.urlfilters.impl.LocalizationURLFilter) for more information.

The last two components are custom modules for the diary application. The first demonstrates a basic module which just logs the information from the user's request. This module is used to log the unauthorized access and is attached to the defaultnoaccessstate state in the application. The last component demonstrates action module functionality. The module DiaryActions encapsulates all actual diary specific actions such as the adding of new diary entries, the viewing and the deletion of the entries.

The following describes the site configuration file of the example diary application.

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE sites SYSTEM "sinswebsite.dtd">

<sites>
    <!--
        SINS example web site.
        * State where to go if errors (exceptions from
        modules / actions) are encountered is "error".
        * State where to redirect if user has no access
        to a state or target is "noaccess".
        * Role validator component to authorize the user
        to states and targets with role definitions is
        GenericRoleValidator. See sinscomponents.xml.
        * URL Filter component to filter the target
        URLs is LocalizationURLFilter. See sinscomponents.xml.
    -->
    <site name="diary"
          defaulterrorstate="error"
          noaccessstate="noaccess"
          rolevalidator="GenericRoleValidator"
          urlfilter="LocalizationURLFilter">

        <!--
            our default error state.
        -->
        <state name="error">
            <!--
                note: when name-attribute is left undefined for
                      target-element the element is treated as
                      default target.
            -->
            <target type="forward" url="error.jsp" />
        </state>

        <!--
            Log unauthorized access and redirect to noaccess.jsp.
        -->
        <state name="noaccess" module="LogUnauthorizedAccessModule">
            <target type="forward" url="noaccess.jsp" />
        </state>

        <!--
            Welcome screen.
        -->
        <state name="welcome">
            <target type="forward" url="welcome.jsp" />
        </state>

        <!--
            Diary main menu.
        -->
        <state name="main">
            <target type="forward" url="diarymain.jsp" />
        </state>

        <!--
            State to add new entries to diary.
            Form is posted here (diary.new.add.sins).
        -->
        <state name="new" module="DiaryActions">
            <!--
                if add is successful, show diary listing
            -->
            <target name="addok" type="forward" state="show" action="list" />

            <!--
                by default show the add page
            -->
            <target type="forward" url="diarynew.jsp" />
        </state>

        <!--
            State to delete diary entries with diary.delete.delete.sins?id=id of the entry
        -->
        <state name="delete" module="DiaryActions">
            <target name="deleteok" type="redirect" state="show" action="list" />
        </state>

        <!--
            State to show diary entries.

            action 'get' shows an entry with parameter id,
            action 'list' lists the entries of the diary.
            (list is attached as attribute 'entries' to request)
        -->
        <state name="show" module="DiaryActions">
            <target name="getok" type="forward" url="diaryentry.jsp" />
            <target name="listok" type="forward" url="diarylist.jsp" />
        </state>

        <!--
            State to demonstrate the security declarations.
        -->
        <state name="securitytest" userinroles="nosuchrole">
            <target type="forward" url="foobar" />
        </state>
    </site>

</sites>
The file above describes the structure of the diary application web site. States describe the possible different application states the presentation layer of the diary application can have. The states are attached with the modules declared in the component configuration file described earlier. The modules implement the actual business logic and data processing of the application.

Version:
1.0.1
Author:
Marko Kanala

Version 1.0.1 changes:
 - Fixed the entity resolver to load the dtds correctly with different parsers
 - Fixed the library manifest
 - cleaned up the example app