Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Spring Integration

No description
by

Viktor Horvath

on 22 April 2014

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Spring Integration

Conclusion
Different approach how to build a middleware service
Handling message
Cleaner code
New technology -> not having experience in it => need time to learn it and not having experince in production
Integration with Spring
Spring Remoting
Supported Protocols:
RMI
HTTPInvoker (Java serialization via HTTP)
HEssian/Burlap
Spring Integration
An implementation of the Enterprise Integration Patterns
The most important principle! ->
LOOSE COUPLING
Spring Batch
Main properties:
A job has an identity
A job has steps
A job instance can be restarted after failure
Each execution has a start / stop time, status
The job instance has an overall status
Each execution can tell us how many items were processed , how many commits, rollbacks, skips
Fundamental Parts
Spring Core
Spring Webservices
- Remoting: RPC literal SOAP
- Messaging: Document literal SOAP, REST
Spring Security
Spring Integration
Spring Batch
Remoting (RPC literal SOAP, RMI, Hessian/Burlap)
Messaging (JMS API, AMQP protocol,
Contract first web services, Spring Integration
)
Transaction Management
Goals
: Making a platform and programming
language dependent quick connection
Spring can hide the "plumbing" code and can support multiple protocols in a consistent way.
Standard for data exchange:
XML
It is understood by almost all the major programming language or platform
some problem with XML: bigger than we need -> name of the elements, XML marshalling is costly
Other important data exchange syntax:
JSON
Worth to remember:

Web services are not only about SOAP (e.g. REST)
Web service != RPC
Generating contract from code may lead to tight coupling and weird contract (WSDL)
Postel's law: "Be conservative in what you do, be liberal in what you accept from others"
Consider skipping validation for incoming requests and ...
... using XPath to get the values from the request
Spring Web Service
Request processing
Endpoints should be implemented.

Similar to MVC controller -> the Message Dispatcher is the Front Controller which invokes the specific (our) Endpoint class
Configuration in web.xml
<web-app>

<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

</web-app>

We can map our endpoints in XML by
- Message Payload
- SOAP Action Header
- WS-Addressing
- XPath
Message Channel - How does one component communicate with another using messaging?
Message Translator - How can systems using different data formats communicate with each other using messaging?
Message Endpoint - How does an application connect to a messaging channel to send and receive messages?
Publish Subscribe Channel - How can the sender broadcast an event to all interested receivers?
Content Based Router - How do we handle a situation where the implementation of a single logical function (e.g., inventory check) is spread across multiple physical systems?
Message Filter - How can a component avoid receiving uninteresting messages?
Splitter - How can we process a message if it contains multiple elements, each of which may have to be processed in a different way?
Aggregator - How do we combine the results of individual, but related messages so that they can be processed as a whole?
Messages and workflows are handled inside our application -> no need to use a workflow execution engine (like an ESB or a BPEL engine)
For batch and offline processing
Many implementations of writers and readers:
Files
XML
JDBC
Hibernate
JMS
Sample for using RMI - Server
Configuration in Spring XML
<bean id="employeeService" class="rmi.server.CustomerImpl"></bean>

<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="customer-service"/>
<property name="service" ref="customerService"/>
<property name="serviceInterface" value="rmi.common.CustomerI"/>
<property name="registryPort" value="1234"/>
</bean>
Java Code
public interface CustomerI {
public void addCustomer(Customer customer);
}

public class CustomerImpl implements CustomerI {

public void addCustomer(Customer customer) {
...
}

}
Sample for using RMI - Client
Configuration in Spring XML
<beans>
<bean id="employeeService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost:1234/employee-service"/>
<property name="serviceInterface" value="rmi.common.EmployeeI"/>
</bean>
</beans>
public class EmpClientDemo {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("rmi/client/rmi-client-context.xml");
EmployeeI employee = (EmployeeI) ctx.getBean("employeeService");
employee.addEmployee(new Employee("dr Manhattan", "Universe"));
}
}
Java Code
Modifications in Spring config XML
<beans ...
xmlns:sws="http://www.springframework.org/schema/web-services">

...

<!-- registers all infrastructure beans needed for annotation-based
endpoints, incl. JAXB2 (un)marshalling
no need to define elements in the config XML for definining spring
beans -->
<sws:annotation-driven/>

<!-- the id attributes represents the name of the WSDL; for example:
http://[host]:[port]/[servicename]/temperatureService.wsdl -->
<sws:static-wsdl id="temperatureService" location="/WEB-INF/wsdl/temperature.wsdl"/>

</beans>
JAVA code
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;

@Endpoint
public class ReserveAppointmentEndpoint {

private final ReserveAppointmentService reserveAppointmentService;

@Autowired
public ReserveAppointmentEndpoint(ReserveAppointmentService reserveAppointmentService) {
this.reserveAppointmentService = reserveAppointmentService;
}

@PayloadRoot(localPart = "reserveAppointmentService", namespace = "http://samples")
public void reserve(@RequestPayload ReserveAppointmentRequest request) {
reserveAppointmentService.reserve(request);
}

}
!!! The request will get to the class ReserveAppointmentEndpoint by the payload meta information -> if the name of the payload element is reserveAppointmentService and its namespace is http://samples !!!
Some typical Enterprise Integration Pattern
What are the Integration Patterns for...?
Often very similar building blocks must be implemented in the middleware services:
creating a request XML to call a service from an existing one
calling different services based on a value in the request (routing)
calling a third-party service
validating (filtering) the request
generating the response XML from the response(s) of the child service(s)
and so on...
Repetitive tasks
Making design patterns
Processing messages inside the scope of our middleware component and not implementing code ! <-> at the moment we are implementing methods (method orientation) and the methods are called like a flow
Implementing the service ReserveBTAppointment in Spring Integration
Projects artifacts:
Spring Integration configuration XML
Java classes
XSLT transformation
main Spring configuration XML
WSDL, XSDs
Authenticator.java
import virginmedia.schema.faults._2._1.Fault;
import virginmedia.schema.faults._2._1.SOAPFaultMessage;
import virginmedia.wsdl.reservebtappointment._2._0.ReserveBTAppointmentFault;

public class Authenticator {

public void authenticate(String username, String password) throws ReserveBTAppointmentFault {
System.out.println("Trying to authenticate. username="+username+", password="+password);

if (username.equals("VMPORTAL") && password.endsWith("vmp0rt4l")) {
System.out.println("Authenticated!");
} else {
// at the moment SOAPFaultMessage is thrown (SOAP specific...) but if the authentication logic is in a third-party JAR and it throws
// a general exception then a java class can be used here to convert the common exception to SOAP fault
SOAPFaultMessage faultMessage = createSOAPFaultMessage("11111111", "AUTH-ERROR", "wrong username or pwd");
throw new ReserveBTAppointmentFault("AUTH-AUTH!", faultMessage);
}
}

private SOAPFaultMessage createSOAPFaultMessage(String id, String errorCode, String exceptionMessage) {
SOAPFaultMessage faultMessage = new SOAPFaultMessage();
faultMessage.setFault(new Fault());
faultMessage.setId(id);
faultMessage.getFault().setFaultcode(errorCode);
faultMessage.getFault().setDetail(exceptionMessage);
return faultMessage;
}
}
FromBTResptoRBTARespMapper.java
public class FromBTResptoRBTARespMapper {

public JAXBElement<ReserveBTAppointmentResponseCplxType> map(AppointingRequestResponse aResponse,
JAXBElement<ReserveBTAppointmentRequestCplxType> jaxb) throws ReserveBTAppointmentFault {
ReserveBTAppointmentRequestCplxType rbtaRequest = jaxb.getValue();
// if unsuccessful
if (aResponse.getCPWSPALServiceMessage().getAppointmentRejected() != null) {
String errorMessage = "DEFAULT";
try {
errorMessage = aResponse.getCPWSPALServiceMessage().getAppointmentRejected().getRequestResponse()
.getRespondedRequestLine().get(0).getRequestLineMessageInfo().get(0).getMessageInfo().get(0).getMessage();
} catch(NullPointerException npe) {}

SOAPFaultMessage faultMessage = createSOAPFaultMessage("rbtae.getId()", "rbtae.getCode()", errorMessage);
throw new ReserveBTAppointmentFault("errorMessage in the response of BT service!", faultMessage);
}
// if successful
else {
ReserveBTAppointmentResponseCplxType rbtaResponse = new ReserveBTAppointmentResponseCplxType();
rbtaResponse.setResponseHeader(new ResponseHeader());
rbtaResponse.getResponseHeader().setId(rbtaRequest.getRequestHeader().getId());
rbtaResponse.getAppointment().add(new virginmedia.schema.reservebtappointment._2._0.Appointment());
List<JAXBElement<?>> features = aResponse.getCPWSPALServiceMessage().getAppointmentAccepted().getRequestResponse()
.getRespondedRequestLine().get(0).getRequestLineItem().getValue().getContent();
boolean hasBeenFound = false;
for(JAXBElement<?> _feature : features) {
if (_feature.getValue() instanceof Features) {
hasBeenFound = true;
Features feature = (Features)_feature.getValue();
javax.xml.datatype.XMLGregorianCalendar appointmentDate = rbtaRequest.getRequiredAppointment().getAppointmentDate();
...

package uk.co.virginmedia.si.rbta;

import java.net.URI;
import java.net.URISyntaxException;

import org.springframework.ws.client.support.destination.DestinationProvider;

public class WebserviceDestinationProvider implements DestinationProvider {

public URI getDestination() {
try {
return new URI("http://jcaps-kn-d18:38080/WSDLSentry/BTWStubFacade");
} catch(URISyntaxException e) {
System.out.println(e);
return null;
}
}

}

WebserviceDestinationProvider.java
for creating the requests of the child services or the response of the ReserveBTAppointment service
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

<import resource="classpath:/META-INF/spring/integration/test-receiver.xml"/>
<!-- for exposing the XSDs of the ReserveBTAppointment service -->
<import resource="/spring-config-exporting-xsds.xml"/>

<sws:interceptors>
<bean id="validatingInterceptor" class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="/WEB-INF/wsdl/ReserveBTAppointment_V2.xsd"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
</sws:interceptors>

<sws:static-wsdl id="ReserveBTAppointment" location="/WEB-INF/wsdl/ReserveBTAppointment.wsdl"/>

<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="ws-inbound-gateway-for-rbta"/>
</bean>

</beans>
Processing a job step
Message flow
XML Source
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
xmlns:int-xml="http://www.springframework.org/schema/integration/xml"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/xml http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">


<!-- ***************************************************************************************************** -->
<!-- *************************************** INITIALIZATION ********************************************** -->
<!-- ***************************************************************************************************** -->
<bean id="authenticator" class="uk.co.virginmedia.si.rbta.Authenticator"/>
<bean id="webserviceDestinationProvider" class="uk.co.virginmedia.si.rbta.WebserviceDestinationProvider"/>

...

<!-- ***************************************************************************************************** -->
<!-- ************************************* WORKFLOW STARTING ********************************************* -->
<!-- ***************************************************************************************************** -->
<int-ws:inbound-gateway id="ws-inbound-gateway-for-rbta" request-channel="channel-incoming-req" reply-channel="channel-response"/>

<int:channel id="channel-incoming-req"/>

<int:chain id="chain-put-to-header" input-channel="channel-incoming-req" output-channel="publish-subscribe-channel-authentication">
<int-xml:xpath-header-enricher>
<int-xml:header name="username" xpath-expression-ref="username-xpath-expression" />
<int-xml:header name="password" xpath-expression-ref="password-xpath-expression" />
</int-xml:xpath-header-enricher>
<int-xml:unmarshalling-transformer unmarshaller="jaxb2MarshallerForRBTA"/>
<int:header-enricher>
<int:header name="original_payload" expression="getPayload()"/>
</int:header-enricher>
<int-xml:marshalling-transformer marshaller="jaxb2MarshallerForRBTA" result-type="StringResult"/>
<int:transformer expression="payload.toString()"/>
</int:chain>

<int:publish-subscribe-channel id="publish-subscribe-channel-authentication"/>

<int:service-activator id="service-activator-authentication" input-channel="publish-subscribe-channel-authentication" order="1"
expression="@authenticator.authenticate(headers.get('username'), headers.get('password'))"/>

<int-xml:xpath-router id="xpath-router-servicetype" input-channel="publish-subscribe-channel-authentication" order="2">
<int-xml:xpath-expression expression="//res:ReserveBTAppointmentRequest/res:serviceType/text()"
ns-prefix="res" ns-uri="http://virginmedia/schema/ReserveBTAppointment/2/0"/>
<int-xml:mapping value="Broadband" channel="channel-broadband"/>
<int-xml:mapping value="FTTC+WholesaleLineRental" channel="channel-fttc-wlr"/>
</int-xml:xpath-router>

<!-- **************************************** BROADBAND **************************************** -->
<int:channel id="channel-broadband"/>

...

<int:channel id="channel-response"/>

</beans>

3 Java classes are needed
Transparent for the client Java code where the service is
JSON is more compact than XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.mek.astron.com/" xmlns:con="http://www.mavir.hu/OSB/ENTSO-e/ConfirmationReport_v31" xmlns="http://www.mavir.hu/OSB/ENTSO-e/ConfirmationReport_v33" xmlns:con2="http://www.mavir.hu/OSB/ENTSO-e/ConfirmationReport_v23">
<soapenv:Header>
<ws:password>horvathv</ws:password>
<ws:username>horvathv</ws:username>
</soapenv:Header>
<soapenv:Body>
<ws:receiveCNF>
<ws:Container>
<ConfirmationReport DtdRelease="3" DtdVersion="3">
<MessageType v="A18"/>
<MessageDateTime v="2011-05-13T11:26:00.000Z"/>
<SenderIdentification codingScheme="A01" v="10XAT-APG------Z"/>

<MessageIdentification>CNF3</MessageIdentification>
<ReceiverIdentification codingScheme="A01" v="10X1001A1001A329"/>
<ScheduleTimeInterval v="2011-05-14T22:00Z/2011-05-15T22:00Z"/>
</ConfirmationReport>
</ws:Container>
</ws:receiveCNF>
</soapenv:Body>
</soapenv:Envelope>
/soapenv:Envelope/soapenv:Body/ws:receiveCNF/ws:Container/ConfirmationReport/MessageIdentification
//MessageIdentification
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.mek.astron.com/" xmlns:con="http://www.mavir.hu/OSB/ENTSO-e/ConfirmationReport_v31" xmlns="http://www.mavir.hu/OSB/ENTSO-e/ConfirmationReport_v33" xmlns:con2="http://www.mavir.hu/OSB/ENTSO-e/ConfirmationReport_v23">
<soapenv:Body>
<RequestReport DtdRelease="3" DtdVersion="3">

<MessageIdentification>CNF3</MessageIdentification>
</RequestReport>
</soapenv:Body>
</soapenv:Envelope>
Should we reject this request or use the next XPath for both request...?
Full transcript