SOA

Java template for WSDL-first web services using CXF (for Maven2 and Eclipse)

October 23rd, 2008 / Joe on Computing

This took me a while to put together so I thought I’d post it. I wanted the simplest possible template for building a web service in Java. I wanted it to be JAX-WS compliant, so I used the CXF open source implementation which is not only compliant, but also flexible and fast. I also wanted the template to be WSDL first, meaning that I should be able to edit the WSDL by hand to maintain total control over the service contract, then from that, generate Java code to make it easy to fill in the implementation.  (I consider that to be an important part of web service best practices. Doing it the other way - automatically generating WSDL from code - is simpler, but results in messy, sometimes incorrect WSDL that limits your ability to change web service implementations later.) Furthermore, I didn’t want to edit any generated code. I wanted to be able to fill in the implementation details by inheriting from a generated class or implementing a generated interface. Finally, I wanted to take advantage of Maven to build the project, but also be able to work on it in Eclipse, taking advantage of its Web Tools Platform (WTP) to allow synchronization with a live application server. Here’s the result in just under 300 lines of code. (Or you can cut to the chase and just download the zip file and follow the instructions at the end of this posting.)

First, here is the trade.xsd schema file containing the input and output datatypes used by the web services:

<?xml version="1.0" encoding="UTF-8"?>

<xsd:schema targetNamespace="http://com.joemo.schema.trade" xmlns="http://com.joemo.schema.trade"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">

	<!-- web service input types -->

	<xsd:element name="trade">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="security" type="xsd:string" minOccurs="1" maxOccurs="1" />
				<xsd:element name="quantity" type="xsd:integer" minOccurs="1" maxOccurs="1" />
				<!-- note the use of "unbounded"; comments can occur multiple times -->
				<xsd:element name="comments" type="comment" minOccurs="1" maxOccurs="unbounded" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

	<xsd:complexType name="comment">
		<xsd:sequence>
			<xsd:element name="message" type="xsd:string" minOccurs="1" maxOccurs="1" />
			<xsd:element name="author" type="xsd:string" minOccurs="1" maxOccurs="1" />
		</xsd:sequence>
	</xsd:complexType>

	<!-- web service output types -->

	<xsd:element name="status">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="id" type="xsd:string" minOccurs="1" maxOccurs="1" />
				<xsd:element name="message" type="xsd:string" minOccurs="1" maxOccurs="1" />
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>

</xsd:schema>

Next, we need the trade.wsdl file which imports the schema file and completes the WSDL definition:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://com.joemo.schema.tradeservice"
	xmlns="http://com.joemo.schema.tradeservice"
	xmlns:tr="http://com.joemo.schema.trade"
	xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
	xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

	<wsdl:types>
		<xsd:schema targetNamespace="http://com.joemo.schema.tradeservice">
			<xsd:import namespace="http://com.joemo.schema.trade" schemaLocation="trade.xsd" />
		</xsd:schema>
	</wsdl:types>

	<wsdl:message name="tradeInput">
		<wsdl:part name="trade" element="tr:trade" />
	</wsdl:message>

	<wsdl:message name="tradeOutput">
		<wsdl:part name="status" element="tr:status" />
	</wsdl:message>

	<wsdl:portType name="TradeService">
		<wsdl:operation name="book">
			<wsdl:input message="tradeInput" />
			<wsdl:output message="tradeOutput" />
		</wsdl:operation>
	</wsdl:portType>

	<wsdl:binding name="TradeServiceHTTPBinding" type="TradeService">
		<wsdlsoap:binding style="document"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="book">
			<wsdlsoap:operation soapAction="" />
			<wsdl:input>
				<wsdlsoap:body use="literal" />
			</wsdl:input>
			<wsdl:output>
				<wsdlsoap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>

	<wsdl:service name="TradeServicePorts">
		<wsdl:port binding="TradeServiceHTTPBinding" name="TradeService">
			<wsdlsoap:address
				location="http://localhost:9084/tradeService/TradeServicePorts" />
		</wsdl:port>
	</wsdl:service>

</wsdl:definitions>

Now we need a Maven project file that will take this WSDL and generate the Java code. Here’s what the pom.xml file looks like. It’s long and messy but it does a lot. It specifies all the dependencies and the compiler level, includes the rule to generate Java code from WSDL whenever necessary, and includes Jetty and WTP support for testing and running the web services in different environments.

<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.joemo</groupId>
	<artifactId>ws-example</artifactId>
	<packaging>war</packaging>
	<version>0.1</version>
	<name>ws-example</name>
	<url>http://maven.apache.org</url>
	<properties>
		<cxf.version>2.1</cxf.version>
		<spring.version>2.5</spring.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-core</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-common-utilities</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.4</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- Use Java 5 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>

			<!-- CXF WSDL-to-Java code generation -->
			<plugin>
				<groupId>org.apache.cxf</groupId>
				<artifactId>cxf-codegen-plugin</artifactId>
				<version>2.0.6</version>
				<executions>
					<execution>
						<id>generate-sources</id>
						<phase>generate-sources</phase>
						<configuration>
							<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
							<wsdlOptions>
								<wsdlOption>
									<wsdl>src/main/resources/trade.wsdl</wsdl>
								</wsdlOption>
							</wsdlOptions>
						</configuration>
						<goals>
							<goal>wsdl2java</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<!-- Jetty support for testing -->
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
			</plugin>
		</plugins>
		<!-- Eclipse WTP support -->
		<pluginManagement>
			<plugins>
				<plugin>
					<artifactId>maven-eclipse-plugin</artifactId>
					<configuration>
						<wtpversion>2.0</wtpversion>
						<wtpapplicationxml>true</wtpapplicationxml>
						<wtpmanifest>true</wtpmanifest>
						<downloadSources>true</downloadSources>
						<downloadJavadocs>true</downloadJavadocs>
						<projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
						<manifest>${basedir}/src/main/resources/META-INF/MANIFEST.MF</manifest>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>

Among other things, the rules in this pom.xml file will generate a Java interface called TradeService (based on the names in the WSDL file). The only code we will have to write is the implementation of this interface. Although this generation is done automatically by any Maven commands that need it (e.g. mvn package or mvn install) you might want to force it to be done sooner rather than later, so that you can refresh your Eclipse project with the generated code, enabling Eclipse to recognize the interface that you’re trying to implement. You can do this using the commands:

mvn generate-sources
mvn eclipse:clean eclipse:eclipse

This generates Java code from the WSDL, then regenerates the Eclipse project files, after which you should be able to refresh the project in Eclipse. If you see errors about libraries not being found, you may need to configure Eclipse to know about your Maven repository, i.e. select Eclipse / Window / Preferences / Java / Build Path / Classpath Variables, then enter the appropriate settings, e.g.

Name: M2_REPO
Path: C:/Documents and Settings/MyAccount/.m2/repository

Once the project is properly configured in Eclipse, you can fill in the implementation:

package com.joemo.service;

import trade.schema.joemo.com.Comment;
import trade.schema.joemo.com.Status;
import trade.schema.joemo.com.Trade;
import tradeservice.schema.joemo.com.TradeService;

public class TradeServiceImpl implements TradeService {

	public Status book(Trade trade) {
		System.out.print ("Booking security ");
		System.out.print (trade.getSecurity());
		System.out.print (", quantity ");
		System.out.print (trade.getQuantity());
		System.out.println();
		if (trade.getComments() != null) {
			System.out.println ("Comments:");
			for (Comment c : trade.getComments()) {
				System.out.print (c.getAuthor());
				System.out.print (": ");
				System.out.print (c.getMessage());
				System.out.println();
			}
		}
		Status s = new Status();
		s.setId("12345");
		s.setMessage("ok");
		return s;
	}

}

We are almost done. We still need a web.xml file which will direct SOAP requests to the CXF infrastructure:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:appContext.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

Finally, we need the appContext.xml file, which is the Spring configuration file loaded by CXF that defines the web service endpoint:

<?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:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
	default-dependency-check="none" default-lazy-init="false">

	<!-- Load the needed resources that are present in the cxf* jars -->
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<!-- Hook up the web service -->
	<jaxws:endpoint id="ws-example" implementor="com.joemo.service.TradeServiceImpl"
		address="/ws-example" />

</beans>

That’s everything. There are six files, only one of which contains any Java code. You need to make sure you put each file in the right place:

ws-example/pom.xml
ws-example/src/main/resources/trade.xsd
ws-example/src/main/resources/trade.wsdl
ws-example/src/main/resources/appContext.xml
ws-example/src/main/webapp/WEB-INF/web.xml
ws-example/src/main/java/com/joemo/service/TradeServiceImpl.java

A zip file of this example is available for download here. To build and run it, you will need Maven to be installed on your development system. Unzip the file, and in the directory containing the pom.xml file, run the command:

mvn jetty:run

That will generate the Java code from the WSDL, build the example, and run the web service in the Jetty container. You should be able to visit the URL http://localhost:8080/ws-example/ws-example?wsdl from a web browser and see the WSDL for the web service, test the web service using SoapUI, and so on.

Alternatively you can run the command:

mvn eclipse:eclipse

and follow the directions from my earlier blog entry to run the example using Eclipse WTP, which will allow you to edit the code while keeping it synchronized with a live application server.

Good luck! If you encounter any problems using this template, please email me or post a comment so that I can look into it and revise the instructions if necessary.

A maze of twisty little Java web service standards, all alike

October 22nd, 2008 / Joe on Computing

It’s almost impossible to keep up with all the fractal-like Java standards related to web services. As fast as each can be learned, Sun invents another, and a dozen open source implementations appear. For my own sanity I tried to create a rough map of some of them. I’ll try to avoid making recommendations; my main objective is to sketch out how they fit together.

First, it’s important to understand that there are three main players with implementations of of these standards: Sun, the Apache foundation, and Codehaus. There are many other open source implementations as well, but these are the three 800 pound gorillas, for a total of 2400 pounds, or almost exactly one metric tonne (for our international audience).

Second, keep in mind that there are three important APIs which are inter-related: JAX-WS, JAXB, and StAX. Once you understand how these fit together, everything else falls into place more easily.

JAX-WS

Let’s begin our journey with the latest Sun standard for creating and consuming web services: JAX-WS, which stands for Java API for XML Web Services. This standard was introduced in 2004. You can ignore JAX-RPC, since JAX-WS replaces it.

There are three noteworthy implementations of JAX-WS. The first is from Sun, and is called JAX-WS RI for the JAX-WS Reference Implementation (they always had a way with names). The second and third are both from the Apache Group and are called Axis2 and CXF. You can ignore Axis1, XFire, and Celtix, since they are all obsolete. There is also a web service framework called Spring-WS, but it’s not JAX-WS compliant.

So if you are creating web services in Java, the first order of business is to to choose an implementation to work with, and unless you have a reason not to, you should probably stick to one that complies with JAX-WS, which means either JAX-WS RI, Axis2, or CXF.

Related to these is an open source project from Sun called Web Services Interoperability Technologies (WSIT), previously known as Project Tango. This is an implementation of several web service standards (WS-SecurityPolicy, WS-ReliableMessaging, and so on). Metro is an open source web service stack which is a combination of JAX-WS RI and WSIT (so it’s actually a reasonable fourth option).

JAX-WS is oriented around SOAP web services, but many programmers are now using the REST approach. Sun is coming out with the JAX-RS API to support that, but it’s not quite ready yet.

JAXB

Web service development requires mapping between XML and Java objects. JAXB is the Sun API for that (also referred to as JAXB2 since the latest version is the important one). There are two noteworthy implementations: JAXB-RI (Sun’s reference implementation) and JaxMe (the unfortunately named contribution from Apache). JaxMe is in the incubation stage and is not formally part of Apache yet. There are many other interesting and popular XML/Java mapping frameworks, but most of them are not compliant with JAXB. Examples include Castor (from Codehaus), JiBX (a spectacularly fast open source implementation), and XMLBeans (a flexible implementation from Apache).

A recurring source of confusion is that in the past, Sun was less clear about the distinction between APIs and reference implementations, so people would take JAXB to mean both, and you would often see online articles like “Which is better: JAXB or JiBX?” But today developers should always try to use the JAXB API, which will enable a choice of compliant implementations such as JAXB-RI or JaxMe with minimal or no code changes.

StAX

For Java code that needs to read and write large XML documents quickly without necessarily mapping them to objects, there is the Streaming API for XML (StAX). There are several implementations of this API too. There is the Sun Java Streaming XML Parser called SJSXP (another snappy name from Sun), the Woodstox open source implementation which is excellent, and the StAX reference implementation from Codehaus which is referred to simply as StAX (unfortunately perpetuating the confusion between APIs and implementations). Xerces is a streaming XML processing library which used to be part of the Apache project, and work was underway to make it StAX compliant, but that was dropped.

Putting it all together

Web services need to process XML, sometimes mapping it to and from Java objects (e.g. for creating proxy objects and an RPC-like experience), and sometimes processing it directly (e.g. for streaming results when high performance is needed). Therefore Sun designed the JAX-WS API to rely on the JAXB API, which makes perfect sense; any JAX-WS compliant web service implementation should therefore be able to use any JAXB compliant mapping library. Other relationships between these APIs are up to individual implementations. For example, JAX-WS RI supports the StAX API, so you can use any StAX implementation for streaming. CXF also supports the StAX API, as well as a host of Java/XML mapping options including JAXB (allowing the use of any JAXB compliant implementation), XMLBeans, Castor, and JiBX. Yes, they are heroes.

So if you get confused, just ask yourself clarifying questions like: Does this Java web service library support JAX-WS? Which JAXB compliant Java/XML mapping implentation shall I use? Which is better for processing streaming XML? Woodstox or the StAX reference implementation?

If you’re still confused, then just accept the recommendations I promised not to make: Use CXF for your web services (which complies with JAX-WS), JAXB-RI for your Java/XML mapping (which complies with JAXB), and Woodstox for streaming (which complies with StAX).

Developing Web applications with Maven and Eclipse: You *can* have it all

June 1st, 2008 / Joe on Computing

When developing applications using Eclipse or a similar IDE, you quickly get used to being able to test your software immediately after making a change. Plugins like MyEclipseIDE enable that kind of instant edit/compile/test cycle for web applications as well.

But if you’re building web applications with Maven, it’s not so easy. Maven is a fantastic tool for building applications and managing dependencies, but it lends itself to a more batch-oriented mode of operation in which you build and deploy war files from the command line. I found myself wishing I could have the best of both worlds; building my web applications using Maven, but with a seamless edit/compile/test cycle when using Eclipse. Then I discovered the WTP (Web Tools Platform) project. Hallelujah!
(more…)

The network is the network, the computer is the computer - sorry about the confusion

September 30th, 2007 / Joe on Computing

This post continues my ongoing theme: That networks are great as long as software doesn’t pretend they are perfect. (I can’t take credit for the title - it’s been floating around for a long time.)

Increasingly, software is being designed based on the idea of treating network resources as local. The practice of generating proxy objects to invoke remote services increases the tendency to think this way, as does the success of HTTP based remote invocation patterns like REST, SOAP, etc. (It’s tempting to think of HTTP services like function calls: Send request with parameters, wait until results come back, proceed.)

But this is a bad idea. The concept of a network as a means of instantaneous communication between software components anywhere on the globe is an incorrect abstraction. Software should be designed based on the notion that networks are unreliable and introduce unpredictable amounts of latency into communication.

(more…)

Ten meta-requirements for enterprise software development

September 3rd, 2007 / Joe on Computing

When you start a project to build a custom application for an enterprise customer, there are always universal requirements the customer doesn’t tell you about. These are things you have to do in order to implement the stated requirements, so I call them meta-requirements.

It’s helpful to keep a checklist of these and review them at the beginning of any new project, especially if the project is in an unfamiliar IT environment. Here’s my checklist of ten.

(more…)

Protecting your SOA application (and your job) from remote failures

August 26th, 2007 / Joe on Computing

SOA - for Service Oriented Architecture - is the buzzword du jour. Organizations in all industries want to realize its promises, which include sharing information more openly and coherently across the enterprise and increasing organizational agility by making it easier to assemble new applications from existing components. Although there are fierce debates about the details (SOAP vs REST, contract first vs schema first vs code first, etc.) there is little disagreement about the general principles. Software should be constructed in the form of loosely coupled, coarse-grained, stateless services which can be invoked remotely over a network, and which form the basis of enterprise code reuse. This is a huge topic about which volumes have been written, but for now I’m going to focus on one issue: The importance of designing your SOA services to be resilient against network failures.
(more…)

WCF looking good

July 9th, 2007

Been using WCF on an application for the last few weeks. The use case is point-to-point delivery of high-speed data. I’m using binary encoding with net tcp bindings. The messages are reasonably large, and complex (using strongly-typed Dictionaries etc). The gating factor on performance seems to be server CPU; I’m finding I can get around 10,000 messages per second per CPU. So, with a decent quad proc server, I can serve around 40,000 messages per second. It’s not going to compete with 29 West anytime soon, but it’s more than adequate for some fairly high performance application scenarios. And the programming model is an absolute pleasure.