To configure and run a Spine driven process you should perform the
steps below:
-
Create a process flow for each request set you wish to service
by:
-
Defining the process flow in configuration.
-
Create the classes needed to service the process flow. You will
usually be creating a
BusinessDelegate and a
DataAccessObject, for more sophisticated
process flows, you may need to create a
ViewProcessor or
MultiViewProcessor and more than one
BusinessDelegate.
-
Ensure you application follows the spine paradigm
of keeping business logic and rules in the business
layer and data operations in the data layer.
-
To define a process flow in configuration, you will usually be
using one of the following:
-
Simple Process Flow
-
Multidelegate Process Flow
-
MultiView Processor Flow
A simple process flow will need to have a definition in
configuration. An example is given below:
<processor
name="simpleProcessor">
<processorClass>
com.zphinx.spine.core.viewprocessors.DefaultViewProcessor
</processorClass>
<delegate>
<subclass>
com.zphinx.spine.examples.simpledelegate.SimpleDelegate
</subclass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.ExampleFileDAO
</className>
<proxyIndex>1</proxyIndex>
</dataAccessObject>
</delegate>
</processor>
This example implies that the process flow will be from the
ViewProcessor known as
DefaultViewProcessor to
ExampleFileDAO. As
DefaultViewProcessor is provided by Spine
Framework, all the client developer will be creating are the two
classes known as
SimpleDelegate and
ExampleFileDAO.
In Spine paradigm, the class
SimpleDelegate will contain all the
business methods and rules while
ExampleFileDAO will provide the means to
access and retrieve data from the data store.
The client developer will of course need to access this
configuration in his application or MVC be invoking the call:
ViewProcessor
vp =
ViewProcessorFactory.getInstance().createProcessor("SimpleProcessor");
This call effectively creates the
ViewProcessor and initializes it for
running the process flow. To complete the process flow, the
developer will need to create a
DataTransferObject or alternatively wrap a
custom object in a
DTOWrapper to ensure the system is capable
of running the process. The example shown below uses a
DataTransportBean which is a
DataTransferObject available within the
API.
ViewProcessor
vp =
ViewProcessorFactory.getInstance().createProcessor("SimpleProcessor");
DataTransportBean dto = new
DataTransportBean("transporter",new Object());
dto.setId(Universal.getRandom(7));
String daoPath =
"/home/user/spineApp/somePropertiesFile.properties";
String[] proxyInit = new String[]{daoPath,true};
ResultObject result =
vp.processData(dto,proxyInit);
The
ResultObject obtained from the process can
then be queried for the results of the process invocation. The
ResultObject can contain any arbitary
object as a returned object or a collection. i.e
Identifier
id = (Identifier) resultObject.getObj();
String
firstName = id.getFirstName();
String
userName = id.getUserName();
String
password = id.getAccountSecrets().getPassword1();
It can also have localized messages or errors sent to the
invoking Object which can be obtained as a collection or as a
line delimited string. E.g
String s =
result.getDisplayMessages(locale).getAllErrorString();
System.err.println(s);
To get only specific types of error identified by a key, the
client programmer can invoke the following:
String key = "validationErrors";
DisplayError[] errors =
result.getDisplayMessages().getErrors(key);
if(errors.length > 0){
System.err.println("There has been
a validation error!!"); }
As long as business logic is kept in the
BusinessDelegate and data calls are in the
DAO, Spine will ensure your process flow is
fully transposable.
The multi delegate process flow is only slightly different from
the simple process flow. It allows the developer to use more than
one delegate in the configuration, these delegates are then
called by the framework in the order they are declared in
configuration. A multi delegate processor example configuration
is shown below:
<!--// The MultiDelegateProcessor:- An
example simple processor which uses multiple delegates and
multiple DAOs in the order in which they are declared
//-->
<processor name="MultiDelegateProcessor">
<processorClass>
com.zphinx.spine.core.viewprocessors.DefaultViewProcessor
</processorClass>
<delegate>
<subclass>
com.zphinx.spine.examples.multipledelegates.LogonDelegate
</subclass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.LogonDAO
</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
</delegate>
<delegate>
<subclass>
com.zphinx.spine.examples.multipledelegates.PendingJobsDelegate
</subclass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.PendingJobsDAO
</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
</delegate>
<delegate>
<subclass>
com.zphinx.spine.examples.multipledelegates.InboxDelegate
</subclass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.InboxDAO
</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
</delegate>
</processor>
This example implies that the stated process flow will require
the following objects:
-
DefaultViewProcessor
-
LogonDelegate
-
LogonDAO
-
PendingJobsDelegate
-
PendingJobsDAO
-
InboxDelegate
-
InboxDAO
In this example, we depict the process of an administrator
logging into an application, which on a successful logon will
display two tables, one a list of pending jobs and the other an
internal inbox of customer emails.
In reality what the framework will do is to call the process
flows in the order shown and on success make available all the
objects needed to populate the page where the admistrator is
logged into.
This can be shown by the example below:
DefaultViewProcessor
dvp = (DefaultViewProcessor)
ViewProcessorFactory.getInstance().createProcessor("MultiDelegateProcessor");
DataTransportBean dto = new
DataTransportBean("joebloggs","password");
dto.setId(Universal.getRandom(7)); DataSource
dataSource =
DataSourceServiceLocator.getInstance().getDataSource();
User user = null; List pendingJobsList = null;
List inboxList = null; ResultObject result =
dvp.processData(dto,dataSource);
if(!result.isErrorFlag){
// gets the logged on user's details ..
. .
user = (User) result.getObj();
String id = user.getId();
DataTransportBean pendingDto = new
DataTransportBean("pending",new Boolean(true));
pendingDto.setId(id);
result =
dvp.processData(dto,dataSource);
if(!result.isErrorFlag){
pendingJobsList =
(List) result.getObj();
DataTransportBean inboxDto = new
DataTransportBean("metadata",null);
inboxDto.setId(id);
result =
dvp.processData(dto,dataSource);
if(!result.isErrorFlag){
inboxList =
(List) result.getObj();
}
else{
System.out.println("Error :"+result.getDisplayMessages(locale).getAllErrorString());
}
}
else{
System.out.println("Error :"+result.getDisplayMessages(locale).getAllErrorString());
}
}
else{
System.out.println("Error
:"+result.getDisplayMessages(locale).getAllErrorString());
}
The Objects retrieved from the invocation will be packaged and
persisted in the users session or request as needed.
Should an error occur, it can be retrieved from the
ResultObject and sent to the user in the
presentation tier as demanded.
The client developer should note the calls made by the
ViewProcessor, the code calls
ViewProcessor.processData(DataTransferObject,Object):ResultObject multiple times but
does not specify which delegate or
DAO to use. This fact is automatically
derived from the order in which delegates are declared in the
spine.xml file.
Multi view process flow possesses the ability to run several
delegates and multiple
DAOs with the same configuration. It is the
most versatile
ViewProcessor available and the framework
provides an example
ViewProcessor called
MultiViewProcessor which is useful for
handling invocations derived from this type of configuration.
It also declares an attached object (a Builder) which is useful
for running or creating other objects whilst processing, an
example configuration is shown below:
<!--//
The MultiViewProcessor:- An example multiview processor
using different DataAccessObjects //-->
<processor name="MultiViewProcessor">
<processorClass>
com.zphinx.spine.examples.multiview.ExtendedMultiViewProcessor
</processorClass>
<multiDelegate>
<subclass>
com.zphinx.spine.examples.multiview.MultiViewExampleDelegate
</subclass>
<managedObject>
<objectClass>
com.zphinx.spine.examples.beans.SpineBean1
</objectClass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.SpineBean1DAO
</className>
<proxyIndex>1</proxyIndex>
</dataAccessObject>
<pageIndex>1</pageIndex>
</managedObject>
<managedObject>
<objectClass>
com.zphinx.spine.examples.beans.SpineBean2
</objectClass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.SpineBean2DAO
</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
<pageIndex>2</pageIndex>
</managedObject>
<managedObject>
<objectClass>
com.zphinx.spine.examples.beans.SpineBean3
</objectClass>
<dataAccessObject>
<className>
com.zphinx.spine.examples.dao.SpineBean3DAO
</className>
<proxyIndex>2</proxyIndex>
</dataAccessObject>
<pageIndex>3</pageIndex>
</managedObject>
<builder>
com.zphinx.spine.examples.multiview.ExampleBuilder
</builder>
</multiDelegate>
</processor>
The configuration above declares a single delegate and several
managedObjects which are expected to be made available by the
builder when needed.
To use a configuration like that shown above, the code will
instantiate the
ViewProcessor from the
ViewProcessorFactory, the developer can then
create a
SpineBean from a builder specified in
configuration and subsequently invoke the process flow. eg:
try{ DataSource
dataSource =
DataSourceServiceLocator.getInstance().getDataSource();
MultiViewProcessor mvp =
ViewProcessorFactory.getInstance().createProcessor(
"MultiViewProcessor"); SomeBuilder builder =
mvp.findBuilder("MultiViewProcessor","MultiViewTestDelegate");
//create a bean for your use SpineBean2 sp2 =
builder.createBean( 2); //popuate
the bean's methods sp2.setModifiedDate(new Date());
//to invoke a process and run methods in the business
delegate final ResultObject resultObject =
mvp.processData(sp2,dataSource,null,4,-1); //process the ResultObject as in the above
example } catch(Exception e){
e.printStackTrace(); }
It can be seen from the example above that passing a
pageNumber/pageIndex to the
MultiViewProcessor will indicate to
the
MultiViewProcessor which object is been
processed and which
DataAccessObject should be invoked for the
particular process flow.
Users should note that in certain instances (eg invoking the
builder) there is a need to pass the name of the
BusinessDelegate in use to the stated method.
This is because a
MultiViewProcessor is capable of using more
than one
BusinessDelegate to service it's request.
-
Ensure you write a suitable test for the
process flow, there are some examples provided in the
/test-src/ directory of the
distribution
|
|