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:
-
In servlet mode, you will need to add the spine
servlet to your
web.xml file.This can be done using the example
below:
<servlet>
<description>
A simple servlet to
demonstrate Spine usage and examples
</description>
<display-name> Application Core
and Framework</display-name>
<servlet-name>SpineServlet</servlet-name>
<servlet-class>
com.zphinx.spine.start.SpineServlet
</servlet-class>
<init-param>
<param-name>startConfigFile</param-name>
<param-value>spine-init.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpineServlet</servlet-name>
<url-pattern>/servlet/SpineServlet</url-pattern>
</servlet-mapping>
-
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.
-
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 //--> <logFile>log4j.props</logFile>
<!--// Refresh time for log4J instance //--> <watchTime>6000</watchTime>
-
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.
-
Edit the spine-init.xml file to reflect your
file paths and any resource properties files you may be using as
shown below:
<logFile>log4j.props</logFile> <watchTime>6000</watchTime> <configFile>spine.xml</configFile> <roleConfigFile>groups.xml</roleConfigFile> <plugins>
<plugin
key="messagePlugin">
<pluginName>
com.zphinx.spine.plugin.MessagePlugin
</pluginName>
<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"/>
</plugin>
</plugins>
-
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:
<dataSources>
<dataSource key="Mysql"
default="true">
<dataSourceBuilder>
com.zphinx.spine.start.helpers.impl.MysqlDataSourceBuilder
</dataSourceBuilder>
<sourceClass>
com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
</sourceClass>
<property
name="user" value="testuser"/>
<property
name="password"
value="minerva"/>
<property
name="url"
value="jdbc:mysql://192.168.1.5:3306/securesite"/>
<property
name="port"
value="3306</port>
<property
name="databaseName"
value="securesite"/>
</dataSource>
</dataSources>
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.
-
Create additional references to files and
objects which you wish spine to initialize within a specified
plugin tag as shown below:
<plugins>
<plugin key="myPlugin">
<pluginName>
foo.bar.MyPlugin
</pluginName>
<property
name="someProperty"
value="somePropertyValue"/>
<property name="anotherProperty"
value="anotherPropertyValue"/>
</plugin> </plugins>
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
-
In the servlet tag, add the following values
needed to initialize the spine servlet.
<init-param>
<param-name>startConfigFile</param-name>
<param-value>/WEB-INF/spine-init.xml</param-value>
</init-param>
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
http://localhost:8080/applicationContext/SpineServlet
Library Mode
For library mode operation follow the instructions below:
-
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.
-
Follow the instructions in steps 3-6 above.
-
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();
ApplicationConfigurator.getInstance().configure(map);
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.
|
|
|
|
|
|
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:
<DataProxies> <dataProxy
name="com.zphinx.spine.data.FileProxy"
index="1"/> <dataProxy
name="com.zphinx.spine.data.DatabaseProxy"
index="2"/> </DataProxies>
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.
-
Simple Processor
-
Simple Processor with
multiple delegates and DAOs
-
Multi Processor with multiple
delegates and DAOs;
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">
<processorClass>com.zphinx.spine.core.viewprocessors.DefaultProcessor</processorClass>
<delegate>
<subclass>com.zphinx.spine.unittests.impl.DelegateTestObject</subclass>
<dataAccessObject>
<className>com.zphinx.spine.unittests.impl.DaoTestObject</className>
<proxyIndex>1</proxyIndex>
</dataAccessObject>
</delegate>
</processor> 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.
|
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">
<processorClass>com.zphinx.spine.core.viewprocessors.DefaultProcessor</processorClass>
<delegate>
<subclass>com.zphinx.spine.unittests.impl.DelegateTestObject</subclass>
<dataAccessObject>
<className>com.zphinx.spine.unittests.impl.DaoTestObject</className>
<proxyIndex>1</proxyIndex>
</dataAccessObject>
</delegate>
<delegate>
<subclass>com.zphinx.spine.unittests.impl.DelegateTestObject</subclass>
<dataAccessObject>
<className>com.zphinx.spine.unittests.impl.DaoTestObject</className>
<proxyIndex>1</proxyIndex>
</dataAccessObject>
</delegate>
<delegate>
<subclass>com.zphinx.spine.unittests.impl.DelegateTestObject</subclass>
<dataAccessObject>
<className>com.zphinx.spine.unittests.impl.DaoTestObject</className>
<proxyIndex>1</proxyIndex>
</dataAccessObject>
</delegate>
</processor>
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.
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">
<processorClass>com.zphinx.spine.viewprocessors.impl.ConfigurationPageProcessor</processorClass>
<multiDelegate>
<subclass>com.zphinx.spine.admin.delegate.PageDelegate</subclass>
<managedObject>
<objectClass> com.zphinx.spine.newsletter.NewsLetter
</objectClass>
<dataAccessObject>
<className>
com.zphinx.spine.newsletter.dao.NewsLetterDAO
</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
<pageIndex>1</pageIndex>
</managedObject>
<managedObject>
<objectClass>com.zphinx.spine.newsletter.Letter</objectClass>
<dataAccessObject>
<className>com.zphinx.spine.newsletter.dao.LetterDAO</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
<pageIndex>2</pageIndex>
</managedObject>
<managedObject>
<objectClass>com.zphinx.spine.newsletter.NewsScheduler</objectClass>
<dataAccessObject>
<className>com.zphinx.spine.newsletter.dao.NewsSchedulerDAO</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
<page>4</page>
</managedObject>
<builder>com.zphinx.spine.shared.manager.ManagerBuilder</builder>
</multiDelegate>
</processor> 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:
-
Create the necessary
BusinessDelegates,
DataTransferObjects and
Data Access Objects for each functional
implementation.
-
Where an unimplemented or new
DataProxy is required, this should be
created and referenced in the spine.xml file.
-
Amend the spine.xml file in the style shown(a
schema and
dtd is provided),
to reference your newly created objects.
-
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.
|
|
|
|
|
|
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
|
Usage
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.
|
|
|
|
|
|
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.
|
|
|
|
|
|
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"));
adminList.add(someAdmin);
//add the
list to the User user.setGroupNames(groupList);
user.setAdministrators(adminList);
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.
|
|
|
|
|
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:
-
Create a class which extends the
AbstractBusinessDelegate.
-
Implement the
run method of the BusinessDelegate and
ensure it returns a
DataTransferAssembler usually a
ResultObject.
-
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.
-
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.
-
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.
-
Create the other objects used by the said
process i.e
DataAccessObject,
ViewProcessor (the
DefaultViewProcessor may be adequate )
and
DataProxy (Where necessary).
-
You may create helpers and other classes
which are used by this delegate.
-
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.
|
|
|
|
|
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:
-
Extend one of the
DataAbstract classes e.g
DataBaseAbstract.
-
When using a
DataAbstract class or
otherwise, implement it's
fetchData(obj:DataTransferObject):Object
method.
-
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.
-
Create all the helper classes and objects
needed by this DAO.
-
Return a suitable object, please note that
this object will be available to the
BusinessDelegate registered
with this
DataAccessObject
-
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
-
Ensure that you implement the close method to
close all open resources in the DAO.
-
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.
|
|
|
|
|
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.
|
|
|
|
|
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:
-
Decide if you will be using a new
ViewProcessor or one of the
default
ViewProcessors.
-
For each request,create a
BusinessDelegate to service the
business rules of the request.
-
Create a
DataTransferObject to package
your data to the business layer which will usually be a
composite entity object.
-
You may simply declare your main object as
implementing the
DataTransferObject or use a
SpineBean extension.
-
Create a
DataAccessObject which will
interface with your data store.
-
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.
-
If creating a new
DataProxy, create a new
DataAbstract implementation or
extend the
DataAbstract provided with
spine.
-
Ensure you have the newly created objects
registered with
spine.xml, you must assign a
name for the view processor invocation.
-
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 >>
|
|
|