Integracja usług sieciowych z użyciem Apache Camel – praktyczny przykład – część 1
Integracja usług sieciowych z użyciem Apache Camel – praktyczny przykład – część 1
Z tego wpisu dowiesz się na czym w praktyce polega integracja usług sieciowych z użyciem Apache Camel. Jest to wpis oparty na artykule – https://www.javaworld.com/article/2078883/java-tip-write-an-soa-integration-layer-with-apache-camel.html. Ukłony dla autorów! 😉 Integracja polegać będzie na spięciu ze sobą 3 serwisów. Pierwszy serwis na podstawie danych z dwóch pozostałych agreguje wyniki dotyczące cen biletów linii lotniczych. Drugi i trzeci serwis odpowiada za dostarczanie informacji na temat biletów należących do konkretnej linii lotniczej. Tego typu agregatory danych pozwalają na wyszukanie i zaproponowanie klientowi najlepszej oferty cenowej! Usługi sieciowe będą oparte o architekturę SOA i protokół SOAP.
Serwisy które zostaną utworzone:
1. ReservationService – serwis agregujące dane biletów z dwóch linii lotniczych,
2. ResServiceAirlineA – serwis udostępniający bilety linii lotniczych A,
3. ResServiceAirlineB – serwis udostępniający bilety linii lotniczych B.
Implementacja serwisu – ResServiceAirlineA:
Tworzymy nowy projekt Apache Maven bez konkretnego archetypu:
- Plik WSDL opisujący usługi sieciowe – plik ten zamieszczamy w katalogu projektu:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://aira.sample.com/quote/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="AirLineAQuote" targetNamespace="http://aira.sample.com/quote/"> <wsdl:types> <xsd:schema targetNamespace="http://aira.sample.com/quote/"> <xsd:element name="getQuote"> <xsd:complexType> <xsd:sequence> <xsd:element name="getQuote" type="tns:getQuoteRequest" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="getQuoteRequest"> <xsd:sequence> <xsd:element name="source" type="xsd:string"></xsd:element> <xsd:element name="destination" type="xsd:string"></xsd:element> <xsd:element name="date" type="xsd:string"></xsd:element> <xsd:element name="airline" type="xsd:string" minOccurs="0"></xsd:element> </xsd:sequence> </xsd:complexType> <xsd:element name="getQuoteResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="getQuoteResponse" type="tns:getQuoteResp" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="getQuoteResp"> <xsd:sequence> <xsd:element name="price" minOccurs="0" type="tns:Quote"></xsd:element> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Quote"> <xsd:sequence> <xsd:element name="airLine" type="xsd:string" fixed="AirlineA"/> <xsd:element name="price" type="xsd:string" /> </xsd:sequence> </xsd:complexType> <xsd:element name="getQuoteFault"> <xsd:complexType> <xsd:sequence> <xsd:element name="code" type="xsd:string"></xsd:element> <xsd:element name="msg" type="xsd:string"></xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="getQuoteOperationRequest"> <wsdl:part element="tns:getQuote" name="parameters" /> </wsdl:message> <wsdl:message name="getQuoteOperationResponse"> <wsdl:part element="tns:getQuoteResponse" name="parameters" /> </wsdl:message> <wsdl:message name="getQuoteOperationFault"> <wsdl:part name="parameters" element="tns:getQuoteFault"></wsdl:part> </wsdl:message> <wsdl:portType name="AirLineAQuote"> <wsdl:operation name="getQuoteOperation"> <wsdl:input message="tns:getQuoteOperationRequest" /> <wsdl:output message="tns:getQuoteOperationResponse" /> <wsdl:fault name="fault" message="tns:getQuoteOperationFault"></wsdl:fault> </wsdl:operation> </wsdl:portType> <wsdl:binding name="AirLineQuoteSOAP" type="tns:AirLineAQuote"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="getQuoteOperation"> <soap:operation soapAction="http://aira.sample.com/quote/getQuoteOperation" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="AirLineAQuoteService"> <wsdl:port binding="tns:AirLineQuoteSOAP" name="AirLineQuoteSOAP"> <soap:address location="http://localhost:8080/QuoteOperation" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
- Plik pom.xml – niezbędne zależności:
<dependencies> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>2.0.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>3.1.0.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>2.7.0</version> </dependency> </dependencies>
Plugin – maven-war-plugin:
Plugin ten podczas budowania wynikowej paczki dodaje niezbędne pliki do zdefiniowanych katalogów:
<plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1</version> <configuration> <webXml>src/main/resources/web.xml</webXml> <webResources> <resource> <directory>${basedir}/wsdl</directory> <targetPath>WEB-INF</targetPath> <includes> <include>*.wsdl</include> <include>*.xsd</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <targetPath>WEB-INF</targetPath> <includes> <include>**.*</include> </includes> </resource> </webResources> </configuration> </plugin>
- Plugin – org.apache.cxf:
Plugin ten pozwala na podstawie pliku WSDL wygenerować niezbędne klasy usług w procesie budowania aplikacji dla fazy generate-sources :
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>2.2.3</version> <executions> <execution> <id>generate-sources</id> <phase>generate-sources</phase> <configuration> <sourceRoot>${project.basedir}/src/main/java/ws</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>${project.basedir}/wsdl/ReservationServiceAirlineA.wsdl</wsdl> <serviceName>AirLineAQuoteService</serviceName> <extraargs> <extraarg>-verbose</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin>
uruchamiamy plugin:
mvn generate-sources
w wyniku otrzymujemy wygenerowane na podstawie pliku WSDL niezbędne klasy javy.
- Implementacja serwisu zwracającego przykładowe dane:
@WebService(targetNamespace = "http://aira.sample.com/quote/", name = "AirLineAQuoteService", serviceName="AirLineAQuoteService", portName="AirLineQuoteSOAP") public class ReservationServiceImpl implements AirLineAQuote{ public GetQuoteResponse getQuoteOperation(GetQuote parameters){ GetQuoteResponse getQuoteResponse = new GetQuoteResponse(); GetQuoteResp getQuoteResp = new GetQuoteResp(); Quote quote = new Quote(); quote.setAirLine("INDIGO"); quote.setPrice("4000"); getQuoteResp.setPrice(quote); getQuoteResponse.setGetQuoteResponse(getQuoteResp); return getQuoteResponse; } }
- Definicja usługi (wyswtawienie usługi na świat):
<?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:jaxws="http://cxf.apache.org/jaxws" xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:endpoint xmlns:tns="http://aira.sample.com/quote/" id="reservationService" address="/AirLineAQuote" serviceName="tns:AirLineAQuoteService" endpointName="tns:AirLineQuoteSOAP" implementor="#reservationServiceImpl"> </jaxws:endpoint> <bean id="reservationServiceImpl" class="com.sample.impl.ReservationServiceImpl"/> </beans>
- Definicja implementacji dla servletu oraz mapowanie adresu:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>cxf</display-name> <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app>
udało się z powodzeniem wystawić usługę która dostarcza podstawowych informacji na temat biletów dla linii lotniczych ResServiceAirlineA.
Testy za pomocą narzędzia SoapUI:
Generujemy wynikową paczkę *.war i wgrywamy sa Apache Tomcat. Po tej operacji pod adresem:
http://localhost:8080/cxf-sample-airlineA-1.0/services/AirLineAQuote?wsdl
znajdziesz plik WSDL który należy wykorzystać przy testach z użyciem narzędzia SoapUI:
- Przykładowy request:
<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:quot="http://aira.sample.com/quote/"> <soapenv:Header/> <soapenv:Body> <quot:getQuote> <getQuote> <source>CHN</source> <destination>HYD</destination> <date>25/09/2013</date> <!--Optional:--> <airline>All</airline> </getQuote> </quot:getQuote> </soapenv:Body> </soapenv:Envelope>
- odpowiedź (zaszyta w kodzie na sztywno, bez pobierania danych z bazy danych):
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:getQuoteResponse xmlns:ns2="http://aira.sample.com/quote/"> <getQuoteResponse> <price> <airLine>INDIGO</airLine> <price>4000</price> </price> </getQuoteResponse> </ns2:getQuoteResponse> </soap:Body> </soap:Envelope>
Implementacja serwisu – ResServiceAirlineB:
Analogicznie postępujemy dla drugiej aplikacji zmieniając nazwę projektu na ResServiceAirlineB, przykładowe dane które są zwracane z usługi zmieniamy w taki sposób aby dotyczyły one drugiej linii lotniczej:
public GetQuoteResponse getQuoteOperation(GetQuote parameters){ GetQuoteResponse getQuoteResponse = new GetQuoteResponse(); GetQuoteResp getQuoteResp = new GetQuoteResp(); Quote quote = new Quote(); quote.setAirLine("SPICEJET"); quote.setPrice("4500"); getQuoteResp.setPrice(quote); getQuoteResponse.setGetQuoteResponse(getQuoteResp); return getQuoteResponse; }
analogicznie wgrywamy aplikację na Apache Tomcat i również testujemy za pomocą narzędzia SoapUI:
http://localhost:8080/cxf-sample-airlineB-1.0/services/AirLineBQuote?wsdl
- Przykładowy request:
<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:quot="http://airb.sample.com/quote/"> <soapenv:Header/> <soapenv:Body> <quot:getQuote> <getQuote> <source>HYD</source> <destination>CHN</destination> <date>25/09/2013</date> <!--Optional:--> <airline>All</airline> </getQuote> </quot:getQuote> </soapenv:Body> </soapenv:Envelope>
- odpowiedź (zaszyta w kodzie na sztywno, bez pobierania danych z bazy danych):
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:getQuoteResponse xmlns:ns2="http://airb.sample.com/quote/"> <getQuoteResponse> <price> <airLine>SPICEJET</airLine> <price>4500</price> </price> </getQuoteResponse> </ns2:getQuoteResponse> </soap:Body> </soap:Envelope>
W tej części udało się zaimplementować dwie usługi:
- ResServiceAirlineA
- ResServiceAirlineB
Każda z nich zwraca z użyciem protokołu SOAP na podstawie przykładowego requestu, przykładową, spreparowaną odpowiedź. Nie korzystamy z bazy danych. W kolejnej części zobaczysz w jaki sposób zintegrować te dwa serwisy za pomocą świetnego narzędzia integracji Apache Camel.
Leave a comment