Sunday, November 28, 2010

The need for process layer.

This article is built with the help of the Enterprise Solution Asset template described in IBM SOA Compass book, this template is recommended to describe the reusable common assets across the organization; the solution at hand is for a business layer framework to help and guide building organized and reusable business services.

1.1      Problem Synopsis

Business services are tightly coupled with transactions services which make it less reusable, this asset helps in decouple of the two types of services allowing the organization to build a catalog of reusable business services.

1.1        Context

As in most of the web centric applications the framework promote the channel to call only one service at a time, this behavior encourages the creation of a coarse grained services, services which compose both business logic and transactional steps, though the resulted services are not fully reusable by other systems; example of that is the Calculate Charges service where the service performs the calculation and then attempt to save the resulted charges to the parent entity, this is fine for the web channel, but the other external systems will require only the calculation part to be performed; another example is the business validation of the risk profile and the saving or updating of the profile are taking place by the same service.


                   Figure1: Current layer structure

Another side effect of that model of calling one service is that the resulted application becomes monolithic application; in case we need to modularize our application we face a problem that we need to call at least two services for one request; we felt that problem in the design of VCC project where we needed to split the VCC core in a separate package.

1.2      Forces

These are the main forces in designing this asset:

  1. The SOA guidelines emphasize on having a process layer above the service layer to control and orchestrate the calls of services.

  1. For the business service to be reusable it should be stateless and idempotent.

  1. To allow having the maximum number of reusable business services out of the applications.

  1. To decrease the coupling between the business and technical services.

  1. To allow parameterized flow of services.

  1. To centralize and organize the transaction management, server side validation, transformation, and the call interception.

  1. To enhance the applications modularity, to add flexibility in separating different modules in different packages.

1.3      Solution


The proposed solution to this is to add an orchestration or process layer above the current service layer, this layer should be responsible for controlling the flow of services calls, transaction management, transformation of process input, and the input validation.

Figure 2: New Layer Architecture

As showing in the previous diagram, a process layer is added above the service layer; also the service layer has a proposed specification to guide the separation of business from the technical services, this model is following the Application Service JEE design pattern; the Rule validation and CRUD service are a sample services inspired from the design of the service layer of the NRE project.


A good design of the Service Orchestration Layer is by utilizing one of the EI patterns; the most suitable one in my opinion for controlling the flow of services requested by a channel is the Routing Slip pattern.

The Routing Slip from the EIP patterns allows you route a message consecutively through a series of processing steps when the sequence of steps may vary for each request.

Spring Integration doesn’t provide implementation for this pattern though Apache Camel framework will be used instead as a basis for this solution.





The sequence from the request till calling the services is like the following,


Sequence of processing

1.3.1      Usage Guide

The process layer is hiding its implementation behind a Process Gateway interface; the clients of this layer can access the process gateway with a set of parameters to control the behavior.

The default behaviors like the one is expected from the web channel can use the below technique,

/**
* Test method for {@link *ae.gov.dubaicustoms.commons.service.orchestrate.ProcessGateway#doProcess(ja*va.io.Serializable, *ae.gov.dubaicustoms.commons.service.orchestrate.ProcessContext)}.
             * Test with sequential processing and stop on exception set to true.
             * This emulates the default way of processing from web channel.
             * Flow filed can be filled by 1) Service1ID, Service2ID... in this case one              * public method can be defined,
             * 2) bean:Service1ID?method=methodName... in that case the mentioned method name will be used.
             * 3) Or a combination of the first and second option.
             */
@Test
            public void testDoProcessDefault() {
                        //filling sample process dto.
                        SampleProcessDTO sampleProcessDTO = new SampleProcessDTO();
                        sampleProcessDTO.setClaimId(1243L);
                        sampleProcessDTO.setClaimNumber("43435");
                        sampleProcessDTO.setClaimType("outbound");
                       
                        //preparing process context to configure the flow.
                        ProcessContext processContext = new ProcessContext();
                        String flow = "sampleBusinessService,bean:sampleTechnicalService?method=doTransaction";
                         processContext.setFlow(flow);
                         processContext.setParallel(false);
                         processContext.setStopOnException(true);
                       
                         //call the actual process with the sample dto as input.
                         try {
                                    processGateway.doProcess(sampleProcessDTO, processContext);
                                    assertTrue(true);
                        } catch (Exception e) {
                                    fail(e.getMessage());
                                    e.printStackTrace();
                        }
            }
In the previous test case, the process context class is the class which holds the process parameters, flow parameter can take a list of services names like sampleBusinessService, sampleTechnicalService,… in that case it will pick the public method from that service, if there are more than one public method then you can write a complete URI for the service like bean:sampleTechnicalService? method=MethodName.
The setParallel method can be used to enforce parallel processing of the service in case they are not related services

In case a transformation is required like from webservice type to process dto an easy way to use dozer mapper can be plugged into the framework, the usage is as follows,

/**
             * Test method for {@link *ae.gov.dubaicustoms.commons.service.orchestrate.ProcessGateway#doProcess(ja*va.io.Serializable, *ae.gov.dubaicustoms.commons.service.orchestrate.ProcessContext)}.
             * Test with dozer mapper, just add a bean with id dozzerMapper *any ware in any spring context in calss path,
             * The framework will auto wire the bean with that id and automatically try to *use it in case there is a conflict
             * In the types between input and the method parameters.
             * This is a sample of how to call the process from webserivce channel.
             */
@Test
            public void testDoProcessDozerMapping() {
                       
                        SampleWSType sampleWSType = new SampleWSType();
                        sampleWSType.setTd("1243");
                        sampleWSType.setClaimNumber("43435");
                        sampleWSType.setType("Import for Reexport");
                       
                        ProcessContext processContext = new ProcessContext();
                        String flow = "bean:sampleBusinessService,bean:sampleTechnicalService";
                         processContext.setFlow(flow);
                         processContext.setParallel(false);
                         processContext.setStopOnException(true);
                       
                         
                         try {
                                    processGateway.doProcess(sampleWSType, processContext);
                                    assertTrue(true);
                        } catch (Exception e) {
                                    fail(e.getMessage());
                                    e.printStackTrace();
                        }
            }
Just add the dozer bean with id dozzerMapper in any spring context and it will be used automatically like the following,

<beans:bean id="dozzerMapper" class="org.dozer.DozerBeanMapper" >
  <beans:property name="mappingFiles">
    <beans:list>          
      <beans:value>dozer-bean-mappings.xml</beans:value>
    </beans:list>
  </beans:property>
</beans:bean>

Then add the mapping file to the class path, a sample mapping file is as follows,

<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://dozer.sourceforge.net  http://dozer.sourceforge.net/schema/beanmapping.xsd">
  <mapping>
    <class-a>ae.gov.dubaicustoms.commons.service.orchestrate.test.SampleWSType</class-a>
    <class-b>ae.gov.dubaicustoms.commons.service.orchestrate.test.SampleProcessDTO</class-b>
    <field>
      <a>td</a>
      <b>claimId</b>
    </field>
    <field>
      <a>type</a>
      <b>claimType</b>
    </field>
  </mapping>
</mappings>

To use the validation capability of this framework, add the validation annotation to your dto and the framework will recognize the annotation and will perform the necessary validation, example for the annotation is like,

@Min(value=1000)
@NotNull
private Long claimId;
@NotNull
private String claimType;

The previous annotation is from javax.validation.constraints following JSR 303 using hibernate validator for the implementation.


1.4      Consequences

The following are some of the consequences of using this ESA:

  • Level of granularity for services: the business layer framework will increase the level of services granularity making it more reusable especially for the business services.

  • Parameterized navigation path: the channel can configure the list of services to be called, sequential or parallel processing, and the use of transformation and validation by using a set of parameters.

  • Easier maintenance and compatibility: separating the services in simpler building blocks makes it more testable by unit test as separate units; this layer can be easily plugged on top of the current application services.

  • Enhanced Modularity: the orchestration layer can call services from different packages and modules.

  • Extra overhead, adding more layers to the application architecture is adding extra overhead of calling and maintaining this layer.
Note: to get the JAR file with the source please email me.

No comments:

Post a Comment