Travel Agency Demo

Migrating Web Service

Christina Lin

Environment Setup

Install H2 database
Copy travelagency.mv.db to ~/h2 folder in your machine.

 

Setup Fabric authentication
Go to ~/.m2/settings.xml
Unser servers, add the following id/pwd information
    <server>
      <id>fabric8.upload.repo</id>
      <username>admin</username>
      <password>admin</password>
    </server>

 

You can skip this part if you already done so

You can skip this part if you already done so

Setup JBoss Fuse

  • Unzip you JBoss Fuse, (please use the one provided)
  • Startup JBoss Fuse, by going to INSTALL_PATH/jboss-fuse-6.1.1.redhat-412/bin and start it
    • Linux
      • ./fuse
    • Windows
      • fuse.bat
  • In console create Fuse Fabric by typing 
    • fabric:create --wait-for-provisioning
  • Stop your fuse by typing exit in console

We are going to create web service endpoint for different clients, these clients services are already up and running for a while. And here is how it works, after receiving hotel request from client, the web service will be dispatched to messaging queues. And because the result needs to go back to the client, we need to make sure the request comes back, there for we need to set the JMS to in-out to make sure it gets the return message back. 

Choose the blueprint archetype, 

GroupID: org.blogdemo.travelagency
ArtifactID: hotelbookingservice

 

Create a Fuse project,

Open up /example/src/main/resources/OSGI-INF/blueprint/blueprint.xml and remove the route, so you are left with a blank canvas. 

Remove the hellobean registry in the xml file. And delete all the java files.

<bean id="helloBean" class="com.mycompany.camel.blueprint.HelloBean">        
<property name="say" value="Hi from Camel"/>
</bean>​

Remove everything under

src/java/* and src/test/*

Setup the dependencies in pom.xml

<!-- For Web Service with CXF -->
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-cxf</artifactId>
      <version>2.12.0.redhat-610379</version>
      <exclusions>
        <exclusion>
          <groupId>asm</groupId>
          <artifactId>asm</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxrs</artifactId>
        <version>2.7.0.redhat-610379</version>
    </dependency>

   <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>2.7.0.redhat-610379</version>
    </dependency>
    <!-- Data transformation -->
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jackson</artifactId>
      <version>2.12.0.redhat-610379</version>
    </dependency>

 

<!-- Messging with AMQ and JMS -->
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-camel</artifactId>
        <version>5.9.0.redhat-610379</version>
    </dependency>    
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-jms</artifactId>
      <version>2.12.0.redhat-610379</version>
    </dependency>

And because we already have an webservice wsdl, we are going to use it to generate all the classes we need, so add the plugin to your pom.xml too.

<!-- to generate source code from the wsdl file -->
      <plugin>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-codegen-plugin</artifactId>
        <version>2.7.0.redhat-610379</version>
        <executions>
          <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            

 

<configuration>
              <sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
              <wsdlOptions>
                <wsdlOption>
                  <wsdl>${basedir}/src/main/resources/wsdl/HotelWS.wsdl</wsdl>
                  <extraargs>
                    <extraarg>-impl</extraarg>
                  </extraargs>
                </wsdlOption>
              </wsdlOptions>
            </configuration>
            <goals>
              <goal>wsdl2java</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

 

As you can see, we need to point the plugin to a wsdl, so place our Hotews.wsdl in src/main/resources/wsdl and click save, you should see all the classes generated. 

Next up, all we have to do, is tell our Camel CXF component where the service address is going to locate, it's service class and the WSDL file location. 

<cxf:cxfEndpoint id="hotelEndpoint"
                   address="/acme-hotel-service-2.0"
                   serviceClass="acme.service.soap.hotelws.HotelWS"
                   wsdlURL="wsdl/HotelWS.wsdl"/>

 

Rather then just a simple connection to the messaging queue, this small application needs interact with messaging a lot, so we are going to create a pool to the broker

<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
</bean>
<bean id="pooledConnectionFactory"   class="org.apache.activemq.pool.PooledConnectionFactory"  init-method="start" destroy-method="stop">
<property name="maxConnections" value="2" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>

<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
           <property name="concurrentConsumers" value="2"/>
</bean>
<bean id="activemq"  class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>

 

Take a look at the WSDL, here you see it has three services, with different inputs, so we are going to implement these services.

The first route is the universal endpoint, where it will take in the entire request, and dispatch them to the routes that actually implements the web service. 

  • CXF endpoint 
    • Uri: cxf:bean:hotelEndpoint
  • Log Endpoint
    • Message: ${header.operationName}
  • RecipientList
    • Expression: direct:${header.operationName}
    • Language: simple

Create the route to handle booking

  • Direct endpoint 
    • Uri: direct:bookHotel
  • Log Endpoint
    • Message: Book Hotel Body:[${body}]
  • ConvertBodyTo
    • Type: java.lang.String
  • ActiveMQ Endpoint
    • Uri: activemq:queue:hotelbooking
    • Pattrn:InOut
  • Log Endpoint
    • Message: Book Hotel Body:[${body}]

Create route to handle canel booking

  • Direct endpoint 
    • Uri: direct:cancelBooking
  • Log Endpoint
    • Message: Cancel Hotel Booking Body:[${body}]
  • ConvertBodyTo
    • Type: java.lang.String
  • ActiveMQ Endpoint
    • Uri: activemq:queue:cancelhotelbooking
    • Pattrn:InOut
  • ConvertBodyTo
    • Type: java.lang.Integer
  • Log Endpoint
    • Message: Cancel Hotel Body:[${body}]

The last service requires us to return a specific type of object, so we need to process with our custom code. 

Create a Java class
Package: org.blogdemo.travelagency.hotelwsendpoint
Class name: ListHotelBean

package org.blogdemo.travelagency.hotelwsendpoint;

import java.util.Map;

import acme.service.soap.hotelws.Resort;

public class ListHotelBean {
    
    public Resort getResort(Map<String, Object> promotedResorts){
        Resort resort = new Resort();
        resort.setHotelId((Integer)promotedResorts.get("hotelId"));
        resort.setHotelName((String)promotedResorts.get("hotelName"));
        resort.setHotelCity((String)promotedResorts.get("hotelCity"));
        resort.setAvailableFrom((String)promotedResorts.get("availableFrom"));
        resort.setAvailableTo((String)promotedResorts.get("availableTo"));
        resort.setRatePerPerson(((Double)promotedResorts.get("ratePerPerson")));
        return resort;
    }
}

Register  bean in camel context:

<bean id="hotelBean" class="org.blogdemo.travelagency.hotelwsendpoint.ListHotelBean" />

Create route to handle available hotel request 

  • Direct Endpoint
    • Uri: direct:getAvailableHotel
  • ConvertBodyTo
    • Type: acme.service.soap.hotelws.HotelRequest
  • Log
    • Message: listAvailable Hotels targetcity:${body.targetCity} startDate:${body.startDate} endDate{$body.endDate}
  • Marshal
    • Tab: json
    • Library: Jackson
  • ActiveMQ Endpoint
    • Uri: activemq:queue:requestHotel
    • Pattrn:InOut
  • Unmarshal
    • Tab: json
    • Library: Jackson
    • Unmarshal Type Name: java.util.HashMap
  • Bean
    • Bean Name: hotelBean
    • Method: getResort

Lab Complete!

Travel Agency Demo - Contract First CXF

By weimeilin

Travel Agency Demo - Contract First CXF

  • 2,126