ICE09 . playing with java, scala, groovy and spring .

Playing with Spring

Service Oriented Spring

Posted by ice09 on June 29, 2008

There is a downloadable zipped Eclipse project at the end of this post.

An interesting almost new subproject in the Spring environment is Spring Web Services.
In short: in finest Spring manner, DI and small little helper form a contract-first Web Service framework. The pros and cons about contract-first vs. contract-last Web Services is explained in the tutorial. From personal experience, contract-first requires more initial effort, but pays a lot afterwards. In our application, the aspect of versioning was underestimated first. By using contract-first, it was really easy to introduce detailed versioning (on basis of namespaces with the PayloadRootAnnotationMethodEndpointMapping)
Depending on the data structure which should be transferred, it may be better to choose the XPathParamAnnotationMethodEndpointAdapter
(for little payloads) over the GenericMarshallingMethodEndpointAdapter (for huge, object oriented payloads).

Excursion

When marshalling should be used, the Java classes for the XML Schema must be generated. There exist several framework to ease this process. In this sample, JAXB2 is used. There are several helper for using JAXB and automize the process of class generation.

  • Create a quickstart Maven project (using the Eclipse-Maven plugin, compare this post).
  • Overwrite the generated POM with the following
<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>javabinding</groupId>
	<artifactId>javabinding</artifactId>
	<packaging>jar</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>javabinding</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.0</version>
		</dependency>
	</dependencies>
	<repositories>
		<repository>
			<id>java.net</id>
			<name>java.net Maven Repository</name>
			<url>https://maven-repository.dev.java.net/nonav/repository</url>
			<layout>legacy</layout>
		</repository>
	</repositories>
	<build>
		<plugins>
			<plugin>
				<groupId>com.sun.tools.xjc.maven2</groupId>
				<artifactId>maven-jaxb-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>generate</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

This POM includes several configuration and dependency information which allows for using the JAXB-Maven2-Plugin

  • You can put your XSDs into the subdirectory /src/main/resources.
  • Below is a sample XML Schema which defines a Request and Response object (this convention is necessary for automatic WSDL generation).
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/WSSchema"
	xmlns:tns="http://www.example.org/WSSchema" elementFormDefault="qualified">

	<element name="SampleRequest">
		<complexType>
			<sequence>
				<element name="StringArgument" type="string"></element>
			</sequence>
		</complexType>
	</element>

	<element name="SampleResponse">
		<complexType>
			<sequence>
				<element name="StringArgument" type="string"></element>
			</sequence>
		</complexType>
	</element>
</schema>
  • Run Maven with goals clean,install.

Afterwards (and a refresh (F5) on the project), there should be a generated-resources directory in subdirectory target. The compiled classes reside in classes.

  • Add target/generated-sources/xjc to the project’s buildpath.
  • You can now include the generated, compiled classes in other projects with this dependency in the POM.
<dependency>
  <groupId>javabinding</groupId>
  <artifactId>javabinding</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</dependency>

Setup

  • Following the tutorial, create the Maven project first
mvn archetype:create -DarchetypeGroupId=org.springframework.ws -DarchetypeArtifactId=spring-ws-archetype -DarchetypeVersion=1.5.2 -DgroupId=de.wssample -DartifactId=wssample
  • Afterwards, create a eclipse project from the maven resources.
cd wssample
mvn eclipse:eclipse
  • The generated eclipse project can now be imported as a Eclipse project into eclipse.
  • Remove the M2_REPO entries from the project’s build path.
  • Use the follwing POM which includes the javabinding we generated above and the jetty-plugin for fast deployments.
<?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>de.wssample</groupId>
    <artifactId>wssample</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>wssample Spring-WS Application</name>
    <url>http://www.springframework.org/spring-ws</url>
    <build>
        <finalName>wssample</finalName>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<inherited>true</inherited>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>maven-jetty-plugin</artifactId>
				<version>6.1.4</version>
				<configuration>
					<contextPath>/</contextPath>
					<scanIntervalSeconds>10</scanIntervalSeconds>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>1.5.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-oxm-tiger</artifactId>
			<version>1.5.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-ws-core</artifactId>
			<version>1.5.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-ws-core-tiger</artifactId>
			<version>1.5.2</version>
		</dependency>
		<dependency>
			<groupId>javabinding</groupId>
			<artifactId>javabinding</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>
</project>
  • Put your XSD in the WEB-INF directory (in the sample above, the WSSample.xsd). This is necessary for the automatic WSDL generation.

The project structure should look like this:

The spring-ws-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 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-2.0.xsd">

	<!-- Register PayloadRootAnnotationMethodEndpointMapping -->
	<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />

	<!-- Register Endpoint -->
	<bean id="sampleEndpoint" class="de.wssample.SampleEndpoint"></bean>

	
	<!-- Configure XML Marshaller -->
	<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
		<constructor-arg ref="marshaller" />
	</bean>

	<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
		<property name="classesToBeBound">
			<list>
				<value>org.example.wsschema.SampleRequest</value>
				<value>org.example.wsschema.SampleResponse</value>
			</list>
		</property>
	</bean>

	<!-- Add automatic WSDL generation support -->
	<bean id="sample" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
		<property name="schema" ref="schema" />
		<property name="portTypeName" value="SampleWS" />
		<property name="locationUri" value="http://localhost:8080/samplews/" />
		<property name="targetNamespace" value="http://samplews" />
	</bean>

	<bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
		<property name="xsd" value="/WEB-INF/WSSchema.xsd" />
	</bean>

</beans>

The web.xml was generated automatically, the Endpoint is as follows

package de.wssample;

import org.example.wsschema.SampleRequest;
import org.example.wsschema.SampleResponse;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;

@Endpoint
public class SampleEndpoint {
    
    @PayloadRoot(localPart = "SampleRequest", namespace = "http://www.example.org/WSSchema")
    public SampleResponse doit(SampleRequest request) {
    	SampleResponse response = new SampleResponse();
    	response.setStringArgument("response");
        return response;
    }

}
  • Run mvn with goals clean,compile,jetty:run.
  • Point the browser to the generated WSDL.
  • It is important to note that with this setup, the root context can be used and the WSDL is generated if the org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition bean id + .wsdl is called (“sample” in this case).

You can now test the Web Service with the great tool soapUI, which generates test request data for you, let’s you modify the data and allows for creating and executing test cases.

Sampleproject: A mail web service

In the project a web services around the velocitymailsample is created which results in a mail web service.

Instructions:

  1. Download the velocitymail-sample
  2. Download the mail-databinding-sample
  3. Download the mail-service-sample

server in /velocitymail/src/main/resources/applicationContext.xml has to be set and access to a (secured) SMTP mail server is necessary to run the sample.

If correctly installed into the same eclipse workspace, the dependencies should be resolved automatically. However, to deploy the application as a WAR, you will need to mvn clean install sampledatabinding, velocitymail and mailservice in this order.

To run the web service with the jetty-maven-plugin, you can run the mailservice project with goals mvn clean install jetty:run.

Advertisements

2 Responses to “Service Oriented Spring”

  1. Daniel Camargo said

    How could I secure my Web Services using this approach?

  2. Clinton said

    Great article on deploying Spring Web Services. I enjoyed it alot along with the screen-shots 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: