Announcement Announcement Module
Collapse
No announcement yet.
Split-ServiceActivator-Aggregation-Transformation for a XML (List Request/Response) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Split-ServiceActivator-Aggregation-Transformation for a XML (List Request/Response)

    Hello,

    I have an exchange process that I've modeled using Spring Integration.

    The process accepts a request (with a list of 'presentments'), then process it by calling a service for each single presentment, and create a response with a global result, some original data, and a list of the individual result of processing each single presentment.

    The messages exchanged are XML files. I manage them using JAXB2.

    It's easy to see that I need a Splitter-Aggregator, a Service Activator for each individual object of the list, and a Transformation (from the Request to the Response, besides the Marshalling/Unmarshalling of the XML files)

    My question is, is it better to Split, to call the Service Activator, then to aggregate and finally to make a transformation or to use the Service Activator for performing both the business logic and the transformation?

    I'd rather the former, because otherwise, I'd need to keep the individual result in MesssageHeaders to be managed in the aggregator. Furthermore, I avoid a double loop in the list.

    However, in spite that seems clear enough that a ServiceActivator accepts a request and returns a Response, to aggregate responses from a list of request could create some confussion. Since the response list must have the same size of the request list, it's not actually an issue.

    Any advice regarding this issue?

    NOTE: spring integration XML file:

    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
    
    
    	<!-- Ficticious -->
    	<int:inbound-channel-adapter id="request" ref="" />
    	<oxm:jaxb2-marshaller id="requestJaxb2Marshaller">
    		<oxm:class-to-be-bound name="com.malsolo.integration.schema.REQUESTSCHEMA"/>
    	</oxm:jaxb2-marshaller>
    	<int-xml:unmarshalling-transformer id="unmarshaller" unmarshaller="requestJaxb2Marshaller" input-channel="request" output-channel="processRequest"/>
    	<int:channel id="processRequest" />
    	<!-- For the aggregator -->
    	<int:header-enricher id="enrichHeaderWithRequester" input-channel="processRequest" output-channel="splitPresentments">
    		<int:header name="REQUESTER" value="payload.getREQUESTER()"/>
    		<int:header name="REQUESTER_IDENTIFIER" value="payload.getIDENTIFIER()"/>
    	</int:header-enricher>
    	<int:channel id="splitPresentments" />
    	<!-- Split the REQUESTSCHEMA into a List<REQUESTSCHEMA.PRESENTMENTS> -->
    	<int:splitter id="presentmentsSplitter" input-channel="splitPresentments" output-channel="processPresentments" ref="presentmentSplitter" method="splitRequestIntoPresentments"/>
    	<int:channel id="processPresentments" />
    	<!-- @ServiceActivator public RESPONSESCHEMA.PRESENTMENTS doStuff(REQUESTSCHEMA.PRESENTMENTS presentmentRequested) {} -->
    	<int:service-activator id="presentmentProcessor" input-channel="processPresentments" output-channel="aggregatePresentments" ref="presentmentServiceActivator" method="doStuff" />
    	<int:channel id="aggregatePresentments" />
    	<!-- Aggregate the List<RESPONSESCHEMA.PRESENTMENTS> into a RESPONSESCHEMA using the headers managed by enrichHeaderWithRequester -->
    	<int:aggregator id="presentmentsAggregator" input-channel="aggregatePresentments" output-channel="response"
    		correlation-strategy="presentmentsAggregator" correlation-strategy-method="correlateBy"
    		ref="presentmentsAggregator" method="aggregateCasosConfirmacionIntoConfirmacion"
    		release-strategy="presentmentsAggregator" release-strategy-method="releaseCasosConfirmacion"
    	/><!-- Yes, the same @Component for the @Aggregator, the @ReleaseStrategy and the @CorrelationStrategy -->
    	<!-- Ficticious -->
    	<int:outbound-channel-adapter id="response" ref="" />
    </beans>
    NOTE: a summary of the classes created by JAXB2

    REQUEST
    Code:
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
    ...})
    @XmlRootElement(name = "REQUEST_SCHEMA")
    public class REQUESTSCHEMA {
    
        @XmlElement(name = "REQUESTER", required = true)
        protected String requester;
        @XmlElement(name = "IDENTIFIER", required = true)
        protected ID identifier;
        @XmlElement(name = "NUMBER_OF_PRESENTMENTS")
        protected short numberOfPresentments;
        @XmlElement(name = "PRESENTMENTS", required = true)
        protected List<REQUESTSCHEMA.PRESENTMENTS> presentments;
    
            
        //~ setters/getters...
    
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
    ...    })
        public static class PRESENTMENTS {
    
            @XmlElement(name = "SEQUENCE")
            protected short sequence;
            @XmlElement(name = "CYCLE", required = true)
            protected String cycle;
            @XmlElement(name = "TYPE", required = true)
            protected String type;
            @XmlElement(name = "DATA", required = true)
            protected REQUESTSCHEMA.PRESENTMENTS.DATA data;
            
            //~ setters/getters...
    
            @XmlAccessorType(XmlAccessType.FIELD)
            @XmlType(name = "", propOrder = {
    ...        })
            public static class DATA {
    
                @XmlElement(name = "IDENTIFIER", required = true)
                protected ID identifier;
                @XmlElement(name = "PRESENTMENT_DATA", required = true)
                protected REQUESTSCHEMA.PRESENTMENTS.DATA.PRESENTMENTDATA presentmentData;
                @XmlElement(name = "ISSUER_NUMBER", required = true)
                protected String issuerNumber;
                @XmlElement(name = "REQUIERED", defaultValue = "true")
                protected boolean requiered;
                @XmlElement(name = "PRIORITY")
                protected String priority;
    
            //~ setters/getters... and so on
    
            }
    
        }
    
    }
    RESPONSE
    Code:
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
    ...})
    @XmlRootElement(name = "RESPONSE_SCHEMA")
    public class RESPONSESCHEMA {
    
        @XmlElement(name = "RESPONSER", required = true)
        protected String responser;
        @XmlElement(name = "IDENTIFIER", required = true)
        protected ID identifier;
        @XmlElement(name = "IDENTIFIER_ORIGINAL", required = true)
        protected ID identifierOriginal;
        @XmlElement(name = "RESULT", required = true)
        protected String result;
        @XmlElement(name = "RESULT_DESCRIPTION", required = true)
        protected String resultDescription;
        @XmlElement(name = "NUMBER_OF_PRESENTMENTS")
        protected short numberOfPresentments;
        @XmlElement(name = "PRESENTMENTS", required = true)
        protected List<RESPONSESCHEMA.PRESENTMENTS> presentments;
    
            
        //~ setters/getters...
    
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
    ...    })
        public static class PRESENTMENTS {
    
            @XmlElement(name = "SEQUENCE")
            protected short sequence;
            @XmlElement(name = "CYCLE", required = true)
            protected String cycle;
            @XmlElement(name = "TYPE", required = true)
            protected String type;
            @XmlElement(name = "DATA", required = true)
            protected RESPONSESCHEMA.PRESENTMENTS.DATA data;
            @XmlElement(name = "PROCESS_RESULT", required = true)
            protected RESPONSESCHEMA.PRESENTMENTS.PROCESSRESULT processResult;
            
            //~ setters/getters...
    
            @XmlAccessorType(XmlAccessType.FIELD)
            @XmlType(name = "", propOrder = {
                "identifier",
                "presentmentData",
                "issuerNumber",
                "requiereimagen",
                "priority"
            })
            public static class DATA {
    
                @XmlElement(name = "IDENTIFIER", required = true)
                protected ID identifier;
                @XmlElement(name = "PRESENTMENT_DATA", required = true)
                protected RESPONSESCHEMA.PRESENTMENTS.DATA.PRESENTMENTDATA presentmentData;
                @XmlElement(name = "ISSUER_NUMBER", required = true)
                protected String issuerNumber;
                @XmlElement(name = "REQUIERED", defaultValue = "true")
                protected boolean requiered;
                @XmlElement(name = "PRIORITY")
                protected String priority;
    
            //~ setters/getters... and so on
    
            }
    
            @XmlAccessorType(XmlAccessType.FIELD)
            @XmlType(name = "", propOrder = {
    ...        })
            public static class PROCESSRESULT {
    
                @XmlElement(name = "NAME", required = true)
                protected String name;
                @XmlElement(name = "ORDER")
                protected short order;
                @XmlElement(name = "CALCULUS", required = true)
                protected String calculus;
                @XmlElement(name = "RESULT", required = true)
                protected String result;
                @XmlElement(name = "RESULT_DESCRIPTION", required = true)
                protected String resultDescription;
                @XmlElement(name = "ATTEMPTS")
                protected short attempts;
    
            //~ setters/getters... and so on
    
            }
        }
    
    }

  • #2
    Here is how I understand your issue
    You are saying that after the business logic is applied you have enough information to perform transformation of the message but since the transformed message still needs to be aggregated with other messages you are asking if such transformation should be done before or after the aggregation, right?

    If so, don't forget about the meaning of aggregation - "transform several messages into one aggregated message" - this means that you can perform individual message transformation at the same time you are aggregating individual messages into one. All you need is a custom aggregation strategy

    Comment


    • #3
      Thanks for the quick response

      Originally posted by oleg.zhurakousky View Post
      Here is how I understand your issue
      You are saying that after the business logic is applied you have enough information to perform transformation of the message but since the transformed message still needs to be aggregated with other messages you are asking if such transformation should be done before or after the aggregation, right?
      Yes, the transformation can be done in the Service activator method (it accepts a request and it return a response, basically a request with the result of the processing)

      Originally posted by oleg.zhurakousky View Post
      If so, don't forget about the meaning of aggregation - "transform several messages into one aggregated message" - this means that you can perform individual message transformation at the same time you are aggregating individual messages into one. All you need is a custom aggregation strategy
      Thank you very much, that's what I've done:

      The individual elements of the request (each presentment) is transformed in the Service Activator after splitting the Request. The final transformation is performed in a custom aggregator that uses each transformed presentment to create a Response (with the help of some headers created before splitting)

      I'm glad to see that I wasn't wrong.

      Comment

      Working...
      X