Apache Camel : How to call java webservice

I have made up my mind to get rid of WSO2 ESB at my office. It is clumsy, buggy, hard to test, no body wants to work on it and the documentation is horrible. I looked at various alternative and Apache Camel was free and easy to set up and work with me.

To cut the story short, I was able to run most of the example but was struggling with CXF to call a third party service hosted at a random url. The documentation on the website is focused on exposing web service built in Camel. I was finally able to figure this out with a couple of slide show on slideshare.

Here’s the scenario: I have a third party webservice hosted on the web which gives you the the conversion rate between two currencies. I am going to call this web service and log the response.

As usual I will start from scratch. My webservice is hosted at this url –http://www.webservicex.net/CurrencyConvertor.asmx?WSDL. This webservice exposes a operation called – “ConversionRate”.

I am using Fuse Ide(free – Developer version) but you can use Intellij Or Eclipse.

Prerequisites – Must have Maven.

Step 1: Create a new Camel-Spring project.

Step 2:  Add the following dependencies in your pom.xml. “camel-cxf”

<dependency>

      <groupId>org.apache.camel</groupId>

      <artifactId>camel-cxf</artifactId>

      <version>2.10.0.redhat-60024</version>

    </dependency>

My pom.xml looks like this –

<!–?xml version=”1.0″ encoding=”UTF-8″?>

xmlns=”http://maven.apache.org/POM/4.0.0″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd”>

 

  <modelVersion>4.0.0</modelVersion>

 

  <groupId>com.mycompany</groupId>

  <artifactId>camel-spring</artifactId>

  <packaging>jar</packaging>

  <version>1.0.0-SNAPSHOT</version>

  <name>A Camel Spring Route</name>

  <url>http://www.myorganization.org</url>

  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

  </properties>

  <repositories>

    <repository>

      <id>release.fusesource.org</id>

      FuseSource Release Repository

      <url>http://repo.fusesource.com/nexus/content/repositories/releases</url>

      <snapshots>

        <enabled>false</enabled>

      </snapshots>

      <releases>

        <enabled>true</enabled>

      </releases>

    </repository>

    <repository>

      <id>snapshot.fusesource.org</id>

      FuseSource Snapshot Repository

      <url>http://repo.fusesource.com/nexus/content/repositories/snapshots</url>

      <snapshots>

        <enabled>true</enabled>

      </snapshots>

      <releases>

        <enabled>false</enabled>

      </releases>

    </repository>

  </repositories>

  <pluginRepositories>

    <pluginRepository>

      <id>release.fusesource.org</id>

      FuseSource Release Repository

      <url>http://repo.fusesource.com/nexus/content/repositories/releases</url>

      <snapshots>

        <enabled>false</enabled>

      </snapshots>

      <releases>

        <enabled>true</enabled>

      </releases>

    </pluginRepository>

    <pluginRepository>

      <id>snapshot.fusesource.org</id>

      FuseSource Snapshot Repository

      <url>http://repo.fusesource.com/nexus/content/repositories/snapshots</url>

      <snapshots>

        <enabled>true</enabled>

      </snapshots>

      <releases>

        <enabled>false</enabled>

      </releases>

    </pluginRepository>  

  </pluginRepositories>

 

  <dependencies>

    <dependency>

      <groupId>org.apache.camel</groupId>

      <artifactId>camel-core</artifactId>

      <version>2.10.0.redhat-60024</version>

    </dependency>

    <dependency>

      <groupId>org.apache.camel</groupId>

      <artifactId>camel-spring</artifactId>

      <version>2.10.0.redhat-60024</version>

    </dependency>

    <!– logging –>

    <dependency>

      <groupId>org.slf4j</groupId>

      <artifactId>slf4j-api</artifactId>

      <version>1.6.6</version>

    </dependency>

    <dependency>

      <groupId>org.slf4j</groupId>

      <artifactId>slf4j-log4j12</artifactId>

      <version>1.6.6</version>

    </dependency>

    <dependency>

      <groupId>log4j</groupId>

      <artifactId>log4j</artifactId>

      <version>1.2.17</version>

    </dependency>

    <!– testing –>

    <dependency>

      <groupId>org.apache.camel</groupId>

      <artifactId>camel-test-spring</artifactId>

      <version>2.10.0.redhat-60024</version>

      <scope>test</scope>

    </dependency>

<dependency>

      <groupId>org.apache.camel</groupId>

      <artifactId>camel-cxf</artifactId>

      <version>2.10.0.redhat-60024</version>

    </dependency>

  </dependencies>

  <build>

    <defaultGoal>install</defaultGoal>

    <plugins>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-compiler-plugin</artifactId>

        <version>2.5.1</version>

        <configuration>

          <source>1.6</source>

          <target>1.6</target>

        </configuration>

      </plugin>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-resources-plugin</artifactId>

        <version>2.4.3</version>

        <configuration>

          <encoding>UTF-8</encoding>

        </configuration>

      </plugin>

      <!– allows the route to be ran via ‘mvn camel:run’ –>

      <plugin>

        <groupId>org.apache.camel</groupId>

        <artifactId>camel-maven-plugin</artifactId>

        <version>2.10.0.redhat-60024</version>

      </plugin>

    </plugins>

  </build>

</project>

Step 2: Under src/main.resources/META-INF folder(if not there then create one) create file called camel-context.xml.  Your camel file should like this –

<?xml version=”1.0″ encoding=”UTF-8″?>

xmlns=”http://www.springframework.org/schema/beans”

        xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

        xmlns:cxf=”http://camel.apache.org/schema/cxf”

        xsi:schemaLocation=”

        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd

        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd”>

  <cxf:cxfEndpoint id=”wsdlEndpoint”

                     address=”http://www.webservicex.net/CurrencyConvertor.asmx”

                     endpointName=”c:SOAPOverHTTP”

                     serviceName=”c:CurrencyConvertor”

                     xmlns:s=”http://www.webserviceX.NET”/>

  

  <camelContext xmlns=”http://camel.apache.org/schema/spring”>

  <route>

        here is a sample which processes the input files

         (leaving them in place – see the ‘noop’ flag)

         then performs content based routing on the message using XPath</description>

        src/data/order?noop=true”/>

        <log message=”${body}”/>

        wsdl&serviceName={http://www.webserviceX.NET/}CurrencyConvertor&portName={http://www.webserviceX.NET/}CurrencyConvertorSoap&dataFormat=MESSAGE”/>

         <log message=”${body}”/>

    </route>

</camelContext>

 

</beans>

Step 4: Place the payload or input data xml in src/data/input/order.xml. The order.xml should like this –

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:web=”http://www.webserviceX.NET/”>

   <soapenv:Header/>

   <soapenv:Body>

      <web:ConversionRate>

         <web:FromCurrency>AUD</web:FromCurrency>

         <web:ToCurrency>USD</web:ToCurrency>

      </web:ConversionRate>

   <!–soapenv:Body>–>

<!–soapenv:Envelope>–>

That’s it!!!!

The interesting part is all in the camel-context.xml. Here’s what is happening in this file

src/data/order?noop=true”/>

This line reads the file order.xml. The option noop=true makes the file to be read again and again. By default this values is false. If this value is false, then after one read, camel marks it as read and when you run the example for second time, it will not read this file.

<log message=”${body}”/>

This line will simply log the contents of order.xml.

serviceName={http://www.webserviceX.NET/}CurrencyConvertor&portName={http://www.webserviceX.NET/}CurrencyConvertorSoap&dataFormat=MESSAGE”/>

 This line tells cxf component that it needs to call the webservice –  http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

-URL – is the url of the wsdl http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

  • serviceName – is the name of the service. Remember it is the name of teh service not the oepration!! The value between {} is the namespace. If you do not want to write {http://….} then add another tag xmlns   – {http://www.webserviceX.NET/}CurrencyConvertor. 
  • portName – is the name of the port.

portName={http://www.webserviceX.NET/}CurrencyConvertorSoap. This is again preceded by {http://…} which is the namespace value. This value is defined in the wsdl as –<wsdl:port name=”CurrencyConvertorSoap” binding=”tns:CurrencyConvertorSoap”>

The last piece is dataFormat  – dataFormat=MESSAGE. This tells that the body is of type message.

Part 2 – In production you would want to avoid writing cxf in the above format as it is prone to error because the string value is very long and difficult to test independently and cannot be reused if you want to call the service in another route. So the best way is to define this as cxf endpoint. All you need to do is slighly modify the camel-context.xml. 

  1. Add this(be sure to remove the earlier version of <to uri=”cxf….”)

<to uri=”cxf:bean:wsdlEndpoint?dataFormat=MESSAGE”/>

  1. Define the cxf endpoint called wsdlEndpoint (You call it whatever you want).

<cxf:cxfEndpoint id=”wsdlEndpoint”

                     address=”http://www.webservicex.net/CurrencyConvertor.asmx”

                     endpointName=”c:SOAPOverHTTP”

                     serviceName=”c:CurrencyConvertor”

                     xmlns:s=”http://www.webserviceX.NET”/>

That’s it.

Now just run the app. This will print the following-

[ead #0 – file://src/data/order] route1                         INFO

<soapenv:Header/>

<soapenv:Body>

<web:ConversionRate>

<web:FromCurrency>AUD</web:FromCurrency>

<web:ToCurrency>USD</web:ToCurrency>

</web:ConversionRate>

<!–soapenv:Body>–>

<!–soapenv:Envelope>–>

[           default-workqueue-1] route1                         INFO  0.8951

~~~~ Enjoy Cameling ….

  • code is not readable. use SyntaxHighlighter

    • Sorry.. I am porting my blog to wordpress.org and will fix it after the port.

  • Surya

    Hi,

    Can you please share the complete project here or send in email.

    Thanks

  • Aman

    hi,,, great turorial…;)
    i have deployed my webservice at http://localhost:8080/OrderManagementFuseWebService/OrderImpl,
    but when i try to run my camel route that actually consumes and xml file from folder and requests the webservice as SOAP message, i get the following error.
    I am really not able to figure out where i am doing wrong. Kindly help..

    [1) thread #0 – file://src/data] GenericFileOnCompletion WARN Rollback file strategy: org.apache.camel.component.file.strategy.GenericFileRenameProcess[email protected] for file: GenericFile[message3.xml]
    [1) thread #0 – file://src/data] route1 INFO


    34

    23

    [1) thread #0 – file://src/data] DefaultErrorHandler ERROR Failed delivery for (MessageId: ID-Aman-36020-1428526617355-0-5 on ExchangeId: ID-Aman-36020-1428526617355-0-6). Exhausted after delivery attempt: 1 caught: org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[message3.xml]

    Message History
    —————————————————————————————————————————————
    RouteId ProcessorId Processor Elapsed (ms)
    [route1 ] [route1 ] [file://src/data?noop=true ] [ 1]
    [route1 ] [log1 ] [log ] [ 0]
    [route1 ] [to1 ] [cxf://http://localhost:8080/OrderManagementFuseWebService/OrderImpl?serviceNam] [ 0]

    Exchange
    —————————————————————————————————————————————
    Exchange[
    Id ID-Aman-36020-1428526617355-0-6
    ExchangePattern InOnly
    Headers {breadcrumbId=ID-Aman-36020-1428526617355-0-5, CamelFileAbsolute=false, CamelFileAbsolutePath=C:\Users\Aman Verma\JBossworkspace\orderManagement\src\data\message3.xml, CamelFileLastModified=1428526603589, CamelFileLength=395, CamelFileName=message3.xml, CamelFileNameConsumed=message3.xml, CamelFileNameOnly=message3.xml, CamelFileParent=src\data, CamelFilePath=src\data\message3.xml, CamelFileRelativePath=message3.xml, CamelRedelivered=false, CamelRedeliveryCounter=0}
    BodyType org.apache.camel.component.file.GenericFile
    Body [Body is file based: GenericFile[message3.xml]]
    ]

    Stacktrace
    —————————————————————————————————————————————
    org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[message3.xml]
    at org.apache.camel.util.ObjectHelper.wrapCamelExecutionException(ObjectHelper.java:1379)
    at org.apache.camel.impl.DefaultExchange.setException(DefaultExchange.java:283)
    at org.apache.camel.component.cxf.CxfProducer.process(CxfProducer.java:120)
    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:110)
    at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:72)
    at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:398)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:118)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:80)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
    at org.apache.camel.component.file.GenericFileConsumer.processExchange(GenericFileConsumer.java:401)
    at org.apache.camel.component.file.GenericFileConsumer.processBatch(GenericFileConsumer.java:201)
    at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:165)
    at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:187)
    at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:114)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
    Caused by: java.lang.NoSuchMethodError: org.apache.camel.util.ObjectHelper.notNull(Ljava/lang/Object;Ljava/lang/String;)V
    at org.apache.camel.component.cxf.CxfProducer.prepareBindingOperation(CxfProducer.java:202)
    at org.apache.camel.component.cxf.CxfProducer.process(CxfProducer.java:102)
    … 20 more

    Here’s my route

    • Dinesh

      Check if you have the right jar files.
      Looking at the error
      Caused by: java.lang.NoSuchMethodError: org.apache.camel.util.ObjectHelper.notNull(Ljava/lang/Object;Ljava/lang/String;)V
      This smells like you have multiple different versions of camel JARs on the classpath. Can you double check that thet camel JARs are ALL the SAME version.
      Try adding this in your pom.xml

      org.apache.camel
      camel-jms
      CHECK YOUR CAME VERSION COPATIBILITY …. ${camel.version}

  • And this works better for you than WSO2? Just curious what the clumsyness, horrifying things are with WSO2 compared to Camel ?

    • Dinesh

      We started with WSO2 in 2010 with version 3.7 or 3.8 I think, we are at 4.3 now. There were many issues with UI consoles.
      1. This issue was present in 3.7 and 4.3 – When you start a new sequence and use DbScript mediator and replace or populate an existing payload, the service works fine. However when you shutdown and restart, using the same xml where you in the sequence you used dbScript mediator, the log starts showing weird errors(don’t remember the errors) about DbScript mediator. After 4 days, I realized that in order to make this particular mediator work after a restart is to turn trace logging, which resolves this issue.

      2. The documentation is still not up to the mark. WSO2 tries to sell its ESB that they have a UI console that you can work with instead of working on ugly XML files. That’s good! However if as company you are trying to sell UI console instead of just picking up raw Apache Synapse project then you should mention example and description about the UI components instead of showing examples picked up from Apache Syanpse and showing it how to make things work in XML!!! All they have in description is a screenshot of UI Console, example Filter. They just had a pickture of filter in UI console and name of the empty fields. The documentation never explained or gave an example of how or what to put in those fields. It’s like looking at gas stove for the first time and the manual says – This is a gas knob but never tells you that to turn it on, you need to have a gas connection or push the knob and twist to turn it on or off.

      3. Many of the times, the UI code is not saved properly and you had to start all over again.

      The newer 5.0 may have worked on some of the issues, but I am not going back to WSO2 now.

      However there data services product is awesome and I would highly recommend it.

© 2016. Your Company. All Rights Reserved.