How to integrate Spine into your application (installation and initialization)

Spine can be integrated into a java application either as a servlet or as a library. As the framework is predominantly a backend delivery mechanism, you will be usually be using an MVC framework of some sort with Spine.(An example of how to integrate spine into a web application is available here).  Please ensure you have the following pre-requisites installed on your system

  • J2SE 5 or higher
  • All the jar files in the Spine /lib/ directory
  • Log4J libraries
  • Junit libraries
  • J2EE 1.4 libraries if running servlets and JSP's
  • Hibernate 3 libraries if planning to use Hibernate

Servlet Mode

For servlet mode operation follow the instructions below:

  1. In servlet mode, you will need to add the spine servlet to your web.xml file.This can be done using the example below:

                A simple servlet to demonstrate Spine usage and examples
            <display-name> Application Core and Framework</display-name>


  2. You should copy all the files in spine-distro/lib directory to your /WEB-INF/lib/ directory.You may not need to copy all the libraries if they are already packaged in your application classpath.

  3. In your spine-init.xml file, ensure you define the full path to your log4J properties or xml file.  You may also change the watchTime property which tells log4J how many milliseconds it should perform a refresh. i.e

    <!--// Path to log4j properties file //-->

    <!--// Refresh time for log4J instance //-->

  4. Create resource properties files in suitable java packages and add the full class names to these files in the servlet initialization parameters.You can define as many properties files as you like but at least one properties file must be defined.

  5. Edit the spine-init.xml file to reflect your file paths and any resource properties files you may be using as shown below:

            <plugin key="messagePlugin">
                <property name="siteMessages" value="com.zphinx.spine.resources.ConfigurationResources,com.zphinx.spine.resources.UtilMessages"/>
                <property name="defaultMessageClass" value="com.zphinx.spine.resources.ConfigurationResources"/>
                <property name="exceptionMessageClass" value="com.zphinx.spine.resources.ExceptionMessages"/>

  6. If you are using a database and you know the properties required by the DataSource which will be used by the application, specify the properties of the DataSource in the dataSources tag as below:

            <dataSource key="Mysql" default="true">
                <property name="user" value="testuser"/>
    property name="password" value="minerva"/>
    property name="url" value="jdbc:mysql://"/>
                <property name="port" value="3306</port>
    property name="databaseName" value="securesite"/>
  7. You may add as many dataSources  as you like but each must have a unique key to identify the dataSource when it is requested in the working application.

    You may also need to create a specific builder for your database if the DefaultDataSourceBuilder is not compartible with your database.Please read the instructions on how to create a DataSourceBuilder for further information.

  8. Create additional references to files and objects which you wish spine to initialize within a specified plugin tag as shown below:

            <plugin key="myPlugin">
                <property name="someProperty" value="somePropertyValue"/>

                <property name="anotherProperty" value="anotherPropertyValue"/>       

    Ensure you have a plugin implemented and defined to use the values you have specified.You may specify as many plugins as you like otherwise skip this step if you are not defining a new plugin.

    When sending additional initialization properties to ApplicationConfigurator, you must implement an instance of SpinePlugin and ensure that you handle the initialization of your objects from this implementation. Spine will then use the SpinePlugin instance to perform initialization.An example is provided here

  9. In the servlet tag, add the following values needed to initialize the spine servlet.


    You may amend the path to the spine-init.xml file, but for security reasons it is best placed in your WEB-INF/ directory of your application context.

    To test if you have a successful initialization, you can point your browser to the mapping specified for the SpineServlet i.e

Library Mode

For library mode operation follow the instructions below:

  1. You must place the most current copy of the spine.jar file and all the files spine-distro/lib/ directory in your libaries directory or /WEB-INF/lib/ directory if working with a web application and/or ensure that your application is aware of the location of your spine libraries.

  2. Follow the instructions in steps 3-6 above.

  3. In your application, use an instance of the ConfigReader to obtain a map which can be used to initalize the framework. Eg. you can use the lines below to initialize the framework:

    ConfigReader confReader = new ConfigReader();
    Map map = confReader.createConfig();

  4. This concludes the initialization of the framework. An example of the spine-init.xml file can be viewed here, and a dtd and a schema are available with the distribution.
How to amend and use the configuration file in Spine

The dtd for the spine.xml is self explanatory. Objects used within the spine framework use inversion of control to determine the process flow for any request.

The spine.xml file contains all the references to the objects which will be used in every process flow and follows a simple pattern which can be divided into 2 major types:

  • The DataProxies node and subnodes
  • The Processors nodes and subnodes

DataProxies node and subnodes

This node defines the data proxies in use by spine and associates the names of these proxy classes with a unique index value. This index value is used internally by spine and later in the spine.xml to describe the type of proxy used to access a DataAccessObject. A typical entry for the DataProxies node is shown below:

<dataProxy name="com.zphinx.spine.data.FileProxy" index="1"/>

<dataProxy name="com.zphinx.spine.data.DatabaseProxy" index="2"/>

 You may add a new DataProxy to spine by creating an extension of AbstractDataProxy and adding a new entry to the spine.xml file as a dataProxy
node.(a unique index must also be assigned) e.g

<dataProxy name="com.foo.bar.NewProxy" index="3"/>

ViewProcessors nodes and subnodes

The processors node  contains the elements which are used to service process flows within the framework. ViewProcessors can invoke a process flow in 3 different ways, allowing the configuration to have  different  types of subnodes. Examples  of each type of configuration is shown below.
  1. Simple Processor
  2. Simple Processor with multiple delegates and DAOs
  3. Multi Processor with multiple delegates and DAOs;

Simple Processor

The dtd of the spine.xml file contains nodes which have the name "Processor". This processor tag can be a simple type which contains details of the objects which need to be instantiated and called for the process flow known by the processor tags name.

An example of the simple processor node and it's subnodes is shown below:

<processor name="TestProcessor">

The nodes which define  the various objects in the process flow can be classified as below:

processor Name The name by which this processors configuration is known to the system
processorClass The full class name of the object which represents the processor to use
delegate The delegate used by the business tier and its associated objects(this tag has no attributes)
subclass The full class name of the AbstractBusinessDelegate sub class in use by the process flow
dataAccessObject The tag showing the DataAccessObjects and dependencies
className The full class name of the DataAccessObject in use.
proxyIndex The index of the proxy subclass we are using for this process.

Simple Processor with multiple delegates and DAOs

ViewProcessor  can accommodate calls to more than one delegate in a single invocation.Each delegate to be invoked may have its own DataProxy and associated DataAccessObject. To use the ViewProcessor in this mode,  the user must be aware that the delegate calls are sequential  i.e the call to a delegate within the ViewProcessor  is based on  the position of  a delegate's node within the configuration file

An example is given below:
<processor name="MultiDelegateProcessor">


For each invocation of the ViewProcessor, a call is made to the next delegate defined in the configuration.It is also possible for users to use more than one ViewProcessor and delegates from an application context.

The nodes which define  the various objects in the process flow can be classified as below:

processor Name The name by which this processors configuration is known to the system
processorClass The full class name of the object which represents the processor to use
delegate The delegate used by the business tier and its associated objects(this tag has no attributes)
subclass The full class name of the AbstractBusinessDelegate sub class in use by the process flow
dataAccessObject The tag showing the DataAccessObjects and dependencies
className The full class name of the DataAccessObject in use.
proxyIndex The index of the proxy subclass we are using for this process.

Please note that the only difference between a simple processor node and the processor node defined above is that more than one delegate node is added.

Multi Processor with multiple delegates and DAOs

The Multi Processor is more flexible than a normal ViewProcessor, allowing client developers the oppurtunity to determine how the delegate handles the process flow. There is also the flexibility of adding a builder to the view processor which can be harnessed by the business layer to build objects on the fly.

E.g. A builder may be used as an abstract factory to build different types of the same object which may then be passed on other objects within the process flow.

 An example of such a node is given below:

    <processor name="newsletterConfig">
                    <objectClass> com.zphinx.spine.newsletter.NewsLetter </objectClass>
                    <className> com.zphinx.spine.newsletter.dao.NewsLetterDAO </className>


The nodes which define  the various objects in the process flow can be classified as below:

processor Name The name by which this processors configuration is known to the system
processorClass The full class name of the object which represents the processor to use
multiDelegate The delegate used by the business tier and its associated objects(this tag has no attributes)
subclass The full class name of the AbstractBusinessDelegate sub class in use by the process flow
managedObject The tag indicating which object is used by this process flow, we advise using a SpineBean
objectClass The full class name of the managed object in use by this process flow.
dataAccessObject The tag showing the DataAccessObjects and dependencies
className The full class name of the DataAccessObject in use.
proxyIndex The index of the proxy subclass we are using for this process.
pageIndex An index used to specify this particular managed object configuration
builder The full class name of a builder which can be used to invoke additional properties for the various managed objects

From above, it can be deduced that a single delegate can handle the data store access of more than one process flow which relates to more than one object e.g a delegate can create or delete several subclasses of a SpineBean and return results from each data storage/retrieval activity. The page value can be used to specify which set of data access objects to use.

To create a configuration in spine.xml, follow the instructions below:

  1. Create the necessary BusinessDelegates, DataTransferObjects and Data Access Objects for each functional implementation.

  2. Where an unimplemented or new DataProxy is required, this should be created and referenced in the spine.xml file.

  3. Amend the spine.xml file in the style shown(a schema and dtd is provided), to reference your newly created objects.

  4. You may then access ViewProcessors from your JSP pages or any suitable mvc in use by your application.

Spine will automatically detect your process flow and call the requisite objects as they are needed. If at a later date you need to use a different view, simply ensure that your new view can package the same DataTransferObject into your new view and your application should be working without needing to make changes. Spine also allows you to change data stores without needing to amend the functionality in your business layer and vice versa.

How to amend and create properties files in Spine

Most property files distributed with spine are referenced from configuration, while some are internally linked to the spine classes. Spine allows the user to define additional property files and reference them from configuration. It should be noted that the MessagePlugin allows the user to define 2 sets of properties files, they are:

  • SiteMessages
  • A comma seperated list of property files used within the application framework. Users are advised to add additional property files to the default list
  • MessagePropertyClass
  • The default message properties file used by the application framework

The property files are plain java property files and can be used by your applications in a multilingual format as normal. spine however uses these predefined files to produce multi lingual outputs in the following objects:

  • DisplayMessages
  • The collection of messages and errors generated within the framework by the process flow, you would normally query this object for message or error outputs.
  • DisplayMessage
  • A message object with additional properties used to indicate that a message has been generated in the application
  • DisplayError
  • A message object with additional properties used to indicate that an error has been generated in the application
  • SpineMessageException
  • An exception object capable of generating localized messages backed by the properties files


You may define a properties file within your application (ensure used locale variants are also available),you must then add your properties files to spine by providing the properties file as part of the comma seperated list of referenced by "siteMessages" in the spine-init.xml file.

How to create a SpineBean extension

Creating a SpineBean implies extending the base SpineBean class. To properly harness this object you will need to pass it a permission object after creation. The  permission you are expected to attach to the SpineBean is the permission object obtained from the creators profile, i.e if a user who is known to the framework were to create an entity object which is a SpineBean, then this users permission object must be passed to the SpineBean via its setPermission method.

The effect of this, is to ensure that the new SpineBean will inherit the creator's default security settings (These may be amended directly). This security settings will then determine which other users of the spine framework may access such entity objects at runtime. It will also determine which kind of access control rights are given to users of the created entity objects.

To amend permission levels or create access control rules for the spine bean, the PermissionLevel of the SpineBean's permission must be amended. The PermissionLevel allows client developers to specify unix type ACL rules by dictating that each SpineBean has a owner and belongs to various groups.

The permission level is then assigned an octal number exactly the same as is available in the unix operating system, Spine will then determine if it is accessible and which operations are allowed for users of the entity bean based on if they are it's owner, a member of a group which the entity objects owner belongs, or the general public.

How to use a Member object securely

When creating a Member object i.e Group Application, User, Administrator, an id is automatically generated which is associated with the object in question. A call made to the Member.getPermission() method will generate a permission object based on the present state of the Member object in question.

To expose the full security attributes of any Member, the following properties must be available at security check time:

  • id
  • This is always available at creation.
  • groupNames
  • The list of the groups which this Member belongs, a Group or Application will not need to provide this list, but it must have:
  • groupName
  • The name of the Group or Application
  • administratorNames
  • The list of administrators of the Member.
  • userList
  • The list of users of this Group, only available for Group and Application (optional as a user can be queried to see if he belongs to a group).

At runtime, the permission object returned from Member.getPermission() possesses 2 methods which can be used to check if any other Member has access to the Member whose permission object we are querying. The example below explains this technique.

//create the Member objects
User user = new User();
Administrator someAdmin = new Administrator();
Administrator admin = new Administrator();

//create some lists
ArrayList groupList = new ArrayList();
ArrayList adminList = new ArrayList();

//populate the lists
groupList.add(new StringAttributeBean("A_groupName","G_144245452"));

//add the list to the User

SpinePermission userPermission = user.getPermission();

* To check if Administrator someAdmin has access to User
boolean b = userPermission.getPermit(someAdmin.getId());
//b should be true

* To check if Administrator admin has access to User
boolean b = userPermission.getPermit(admin.getId());
//b should be false

Alternatively if we prefer to throw and handle an exception or we need to ascertain if a another Member object can access the specified Member, we may invoke Permission.checkGaurd(obj:Object), which will throw a SecurityException if access is not allowed.

MemberPermission which is obtained from the Member.getPermission() method  allows us to accurately determine the type of the object i.e Group,User,or Administrator. Specific calls to methods isUser(), isAdmin() or isSuperUser() (i.e Group or Application) return booleans which indicate the type of the object.

Although not broadly implemented for Member objects, it should be noted that MemberPermission objects inherit the SpinePermissions access control rules which is based on unix native ACL rules. It is possible for a MemberPermission to preset a PermissionLevel which will attach unix native ACL rules to the said Member although this is not required for Member to Member permission checks. 

When a PermissionLevel is attached or required for Members of the Spine framework, please note that additional calls are required to determine what access rights are available to the Member which needs to access the another Member.

The SpinePermission allows us to query access levels by invoking calls to getReadFlag(),getWriteFlag() and getExecuteFlag(). By default all Member objects are created with null PermissionLevel but work based on the following rules:

  • Users have no access to other User's data
  • Administrators can only read and write data relating to Users who belong to the group which they are allowed to administer
  • Groups or SuperUsers can only administer(Read,Write,Execute) Users and Administrators who belong to their Groups.
  • Applications have the same access rights as Groups
  • Groups can have multiple Administrators and Users
  • Administrators can control several Group's Users
  • Administrators have no control over other SuperUsers or Groups but may amend data relating Users of these Groups

It should be noted that most of this rules are implied and may not have been directly implemented in the framework. By default Permission.getPermit() will not allow a User to access another Users data nor will it grant access to a Group if the administrator is not registered as an administrator of that Group.

It will however grant access to another administrator who happens to belong to the same group as an administrator been queried. It is left to the client developer to decide if he wishes to allow administrators manage each others data.

How to create a BusinessDelegate

A BusinessDelegate is an extension of the AbstractBusinessDelegate provided by Spine. All business delegates which are created and registered with the framework via the spine.xml file automatically inherit properties and functions which enable them to invoke other
objects within the framework and return the necessary DataTransferAssemblers to the ViewProcessors. The steps for creating and using a BusinessDelegate are outlined below:

  1. Create a class which extends the AbstractBusinessDelegate.

  2. Implement the run method of the BusinessDelegate and ensure it returns a DataTransferAssembler usually a ResultObject.

  3. Override the preProcessBusinessRules(DataTransferAssembler) method of the BusinessDelegate and ensure it returns a boolean true indicating that business rules governing the process flow before the run method is called have been fulfilled, otherwise return false. If no business rules are applicable, do not override this method.

  4. Override the postProcessBusinessRules(ResultObject,DataTransferAssembler) method of the BusinessDelegate and ensure it returns a ResultObject after business rules governing the process flow after the run method have been fulfilled. If no business rules are applicable, do not override this method.

  5. Ensure all the business methods of your process is fulfilled in the business delegate, this is to ensure that the view is completely seperated from the business layer.

  6. Create the other objects used by the said process i.e DataAccessObject, ViewProcessor (the DefaultViewProcessor may be adequate ) and DataProxy (Where necessary).

  7. You may create helpers and other classes which are used by this delegate.

  8. Add an entry to the spine.xml denoting the process flow ( see example).

At runtime Spine will detect the process flow, instantiate the business delegate when needed and ensure that all other objects which are involved in the process flow are available.

How to create a DataAccessObject implementation

Some default DataAccessObject implementations are available within spine.  If having created a new DataProxy, it makes more sense to create a default DataAccessObject to go with it, please create one!

At present default DAOs are available for DataProxies which are available with spine. In creating a DAO (DataAccessObject), follow the steps below:

  1. Extend one of the DataAbstract classes e.g DataBaseAbstract.

  2. When  using  a DataAbstract class or otherwise, implement it's fetchData(obj:DataTransferObject):Object  method.

  3. Make all your datastore calls accessible from this fetchData method if possible.Otherwise you may retr ieve outputs from individual methods but you must create a ResultObject to be outputed from the run method of the business delegate.

  4. Create all the helper classes and objects needed by this DAO.

  5. Return a suitable object, please note that this object will be available to the BusinessDelegate registered with this DataAccessObject

  6. You may call the DAO directly from within your  BusinessDelegate by invoking DAO.fetchData(obj:DataTransferObject):Object although this is done for you in the BusinessDelegate method processDAO():Object

  7. Ensure that you implement the close method to close all open resources in the DAO.

  8. Ensure that the process flow objects i.e ViewProcessor, BusinessDelegate and DataAccessObject are registered in spine.xml.

Using a DataAccessObject involves getting the interface from the DataProxy directly available in the BusinessDelegate and invoking its DAO.fetchData(obj:DataTransferObject):Object method. Other methods may be added to the DAO and subsequently invoked from the BusinessDelegate.

Spine automatically invokes the appropriate DataAccessObject and DataProxy based on the configuration in the spine.xml file. Client developers can  cast the created DAO back to  the  registered object should they wish to invoke other methods.

How to create a DataTransferObject

The present definition of a DataTransferObject in Spine is simplistic. We assume you will be needing to process composite entity data mostly but allow for all contigencies by stating that any object can be a DataTransferObject so long as it implements DataTransferObject (Java Interface).

Users are advised that they may use any proprietry object as a DTO but they must ensure it possesses all the necessary properties defined by Interface DataTransferObject and any other properties needed to fulfill processing in both the business tier and the data/ enterprise tier.

Spine also presents the client developer with some  DTO's which the developer may reuse as needed, they are:

  • DataTransportBean
  • A value object which adds an id property to the Attribute Object distributed with JDK1.5 upwards.
  • SpineBean
  • An object recognised by spine as been an entity object with defined base properties and integrated security.
  • StringAttributeBean
  • An object which can be used to package a name value pair of strings.
  • UserListBean
  • A bean used by the Spine Group object to monitor users associated with a Group
  • DTOWrapper
  • A wrapper for any object which needs to pretend it is a DTO

Any of the above objects can be used as a DTO so long as they fulfill your requirements. In most instances you will need to create composite entity objects for your DTO, which are acceptable to spine as long as the fulfill the DTO signature.

How to handle a request within an application using spine

To handle an application request using spine requires that the framework is properly integrated,tested and shown to be working. Follow the steps below to use spine to handle your process flow:

  1. Decide if you will be using a new ViewProcessor or one of the default ViewProcessors.

  2. For each request,create a BusinessDelegate to service the business rules of the request.

  3. Create a DataTransferObject to package your data to the business layer which will usually be a composite entity object.

  4. You may simply declare your main object as implementing the DataTransferObject or use a SpineBean extension.

  5. Create a DataAccessObject which will interface with your data store.

  6. If using a data store whose DataProxy is not yet implemented in Spine, you will need to create a DataProxy to interface with your DataAccesssObject.

  7. If creating a new DataProxy, create a new DataAbstract implementation or extend the DataAbstract provided with spine.

  8. Ensure you have the newly created objects registered with spine.xml, you must assign a name for the view processor invocation.

  9. From your MVC or Application context, grab a reference to your ViewProcessor using the ViewProcessorFactory then call one of the service methods of the ViewProcessor and obtain the ResultObject which contains the results of the process flow.

The steps described above are sufficient for using spine to handle your process flow.Because of the use of configuration, it is possible to replace any Object in the invocation with another suitable object. This is most obvious with DataProxies and DataAccessObjects but is applicable to all of the objects within the process flow.

It should be noted that the order of invocation in spine is as shown in the diagram below:

It will also be seen that the input to the system is a DataTransferObject which returns a DataTransferAssembler.

<< Back    |     Home    |     Index    |     Forward >>

Copyright © 2008 Zphinx Software Solutions , all rights reserved