Archive for the 'Web Service' Category

06
Nov
09

Accessing a Web Service using Apache CXF and Spring Framework Take 2

This page describes how to generate a client to call a few popular web services that are available on the web.

Requirements:

We will be generating clients for the following web services

Before we can start to use any of the above web services we need to create a new Java project in Eclipse. Name the project

Go ahead and create a new java project in eclipse and save the following pom.xml file to the main folder.

<?xml version="1.0" encoding="UTF-8"?>
<project 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.vermatech</groupId>
	<artifactId>TestApacheCXFClient</artifactId>
	<packaging>war</packaging>
	<version>1.0.1-SNAPSHOT</version>
	<name>TestApacheCXFClient</name>
	<url>http://maven.apache.org</url>

	<build>
		<sourceDirectory>src</sourceDirectory>
<resources><resource><directory>src</directory></resource></resources>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
		  <groupId>log4j</groupId>
		  <artifactId>log4j</artifactId>
		  <version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.activation</groupId>
					<artifactId>activation</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf</artifactId>
			<version>2.1</version>
			<type>pom</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>2.2.4</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>2.2.4</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>

	</dependencies>
</project>

regenerate the project by dropping to the command line and typing:

mvn eclipse:clean eclipse:eclipse

IP2Geo

This web service accepts an ip address and returns some information about it.

We start by getting the wsdl and saving it to our project as

document.wsdl

We insert the following into the pom.xml file in the plugins section.

<plugin>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-codegen-plugin</artifactId>
	<version>2.2.4</version>
	<executions>
		<execution>
			<id>generate-sources</id>
			<phase>generate-sources</phase>
			<configuration>
				<sourceRoot>generated/cxf</sourceRoot>
				<wsdlOptions>
					<wsdlOption>
						<wsdl>document.wsdl</wsdl>
					</wsdlOption>
				</wsdlOptions>
			</configuration>
			<goals>
				<goal>wsdl2java</goal>
			</goals>
		</execution>
	</executions>
</plugin>

To generate the code type the following at the command prompt inside your eclipse project:

mvn generate-sources

  • Return to eclipse and refresh the project.
  • You will see additional files added to the /generated/cxf folder within the project.
  • Copy these files to the folder where your javasource files are located.

Create a simple client that calls these web services.

SimpleClientApp.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.cdyne.ws.IP2GeoSoap;
import com.cdyne.ws.IPInformation;

public class HelloWorldClientApp {
public static void main(String args[]) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});

IP2GeoSoap ip2Geo = (IP2GeoSoap) context.getBean("ip2Geo");
IPInformation ipInformation = ip2Geo.resolveIP("12.12.12.12", "0");

System.out.println("City: " + ipInformation.getCity());
System.out.println("State: " + ipInformation.getStateProvince());
System.out.println("Country: " + ipInformation.getCountry());
}
}

The above program initialized the spring application context and gets a bean that represents the web service. It invokes a method called “resolveIp()” to get a ipInformation object. Next it simply displays the values on the console.

One thing to note here is that the client code does not need all the files the wsdl2java has generated for us. We can trim down the generated code by deleting some classes we dont need.

We first start with the ObjectFactory. At this point it does not look like the object factory provides any benefit.

Delete the following

  • ObjectFactory.java
  • IP2GeoHttpGet.java
  • IP2GeoHttpPost.java

Modify

  • IP2GeoSoap.java and comment out the following line…
  • @XmlSeeAlso({ObjectFactory.class})
  • Delete the IP2GeoHttpGet.java and IP2GeoHttpPost.java as these methods will not be used to access the service
  • Delete the IP2Geo.java class because we will use spring to generate the proxy that will access the service.
  • Delete the ObjectFactory.java, ResolveIP.java, and ResolveIPResponse.java files as well
  • Fix any compile issues that may arise from doing the deletes

You should only be left with 3 class files in your package

  • IP2GeoSoap.jvaa
  • IPInformation.java
  • package-info.java

Next you need to make your app-context.xml should look like this… this file is located at the top package.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    <jaxws:client id="ip2Geo"
                  serviceClass="com.cdyne.ws.IP2GeoSoap"
                  address="http://ws.cdyne.com/ip2geo/ip2geo.asmx" />
</beans>

Testing the program

Create a class in the test package.
HelloWorldClientApp.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.cdyne.ws.IP2GeoSoap;
import com.cdyne.ws.IPInformation;

public class HelloWorldClientApp {
	public static void main(String args[]) throws Exception {
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});

		IP2GeoSoap ip2Geo = (IP2GeoSoap) context.getBean("ip2Geo");
		IPInformation ipInformation = ip2Geo.resolveIP("12.12.12.12", "0");

		System.out.println("City: " + ipInformation.getCity());
		System.out.println("State: " + ipInformation.getStateProvince());
		System.out.println("Country: " + ipInformation.getCountry());
	}
}

Run the program

you should get output similar to the following

log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
Nov 6, 2009 6:07:51 PM org.apache.cxf.bus.spring.BusApplicationContext getConfigResources
INFO: No cxf.xml configuration file detected, relying on defaults.
Nov 6, 2009 6:07:52 PM org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
INFO: Creating Service {http://ws.cdyne.com/}IP2GeoSoapService from class com.cdyne.ws.IP2GeoSoap
City: Anchorage
State: AK
Country: United States

Currency Converter

We will now investigate how to convert over the currency conversion web service that can be accessed using the following wsdl.


http://webservice.webserviceshare.com/currencyconverter/rates.asmx?WSDL

We start by saving the file to
document.wsdl

To generate the code type the following:

Open a command prompt and cd to the project’s folder

mvn generate-sources

you should see the following output

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building TestApacheCXFClient
[INFO]    task-segment: [generate-sources]
[INFO] ------------------------------------------------------------------------
[INFO] [cxf-codegen:wsdl2java {execution: generate-sources}]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Fri Nov 06 18:23:44 EST 2009
[INFO] Final Memory: 25M/534M
[INFO] ------------------------------------------------------------------------

Return to the eclipse project and click refresh.
At this point you should see new files under the project /generated/cxf/com/websevriceshare folder.

We quickly identify that CurrencyConverterSoap.java is the main interface class for the web service. This class has the following methods

  • getRates
  • getSupportedCurrencies
  • getRatesInAllCurrencies
  • getConvertedAmount
  • getConvertedAmountInAllCurrencies

Create a package com.websvriceshare (spelled incorrectly I know but do it anyway) and paste in all the generated code. We will run the project as-is.

We test he web service by defining the following in your spring configuration file…

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    <jaxws:client id="currencyConverter"
                  serviceClass="com.websevriceshare.CurrencyConverterSoap"
                  address="http://webservice.webserviceshare.com/currencyconverter/rates.asmx" />

</beans>

Define the following test code

HelloWorldClientApp.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.websevriceshare.CurrencyConverterSoap;
import com.websevriceshare.CurrencyListRow;

public class HelloWorldClientApp {
	public static void main(String args[]) throws Exception {
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});

		CurrencyConverterSoap currencyConverter = (CurrencyConverterSoap) context
				.getBean("currencyConverter");

		System.out.println("These currencies are supported: ");
		for (CurrencyListRow row : currencyConverter.getSupportedCurrencies().getCurrencyListRow()) {
			System.out.println(row.getCurrencyName());
		}

	}
}

Run the class and you should get output to the console that looks like this…

log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
Nov 6, 2009 6:44:04 PM org.apache.cxf.bus.spring.BusApplicationContext getConfigResources
INFO: No cxf.xml configuration file detected, relying on defaults.
Nov 6, 2009 6:44:04 PM org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
INFO: Creating Service {http://websevriceshare.com/}CurrencyConverterSoapService from class com.websevriceshare.CurrencyConverterSoap
These currencies are supported:
Albanian Lek
Algerian Dinar
Argentine Peso
Aruba Florin
Australian Dollar
Bahamian Dollar
...
Yemen Riyal
Zambian Kwacha
Zimbabwe Dollar
Croatian Kuna
Russian Rouble

Once we are comfortable that its running we will start deleting un-necessary code that was generated.

Bible Web Service

This web service list all versus by Book Title ,Chapter and Verse from the Kings James version Bible

Download the source of the wsdl and again put it into document.wsdl

re-run the command to generate the sources and copy the generated sources to its package under the src folder. This time the source code got generated into the net.webservicex package. We create a similar package in our src folder within our project.

We quickly look at the generated classes once they have been moved over to our source folder and find out that BibleWebserviceSoap.java is the main web service class. It contains the following methods. All of them return a String. This is unfortunate since whomever is implementing the web service will need to parse the xml. It would have been better for the web service author to create a complex Type object and save the client programmers some time.

  • getBibleWordsbyKeyWord
  • getBookTitles
  • getBibleWordsByChapterAndVerse
  • getBibleWordsByBookTitleAndChapter

 

Modify the spring configuration file to generate the proxy for this service.

    <jaxws:client id="bibleWebService"
                  serviceClass="net.webservicex.BibleWebserviceSoap"
                  address="http://www.webservicex.net/BibleWebservice.asmx" />

Create a client program to test the service

package test;

import net.webservicex.BibleWebserviceSoap;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloWorldClientApp {
	public static void main(String args[]) throws Exception {
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"app-context.xml"});
		
		BibleWebserviceSoap bibleWebService = (BibleWebserviceSoap) context
				.getBean("bibleWebService");
		
		System.out.println(bibleWebService.getBookTitles());		
	}
}

This is the output we get.

<NewDataSet>
  <Table>
    <Book>1</Book>
    <BookTitle>Genesis</BookTitle>
  </Table>
  <Table>
    <Book>2</Book>
    <BookTitle>Exodus</BookTitle>
  </Table>
  <Table>
    <Book>3</Book>
    <BookTitle>Leviticus</BookTitle>
  </Table>
  <Table>
    <Book>4</Book>
    <BookTitle>Numbers</BookTitle>
  </Table>

Once we are comfortable with this we delete any un-necessary code.

We have successfully generated code that calls 3 web services using the Apache CXF framework.

Thats All for now!!!




Follow

Get every new post delivered to your Inbox.

Join 50 other followers