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

Playing with Spring

Archive for June, 2008

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.

Posted in Maven, Spring Web Services | Tagged: , | 2 Comments »

Groovy Spring

Posted by ice09 on June 6, 2008

Though the not really persuading (Open Source) IDE support, Groovy is my favorite script language for the Java VM. To have at least simplest support for Groovy, the Eclipse Plugin can be used. However, do not expect too much of it – it seems to be quite unstable (there are some suspicious OOME under Linux), but the Syntax Highlighting is ok. It is said that IntelliJ has the best Groovy IDE support by far, but I didn’t test it.
There exists nice Spring support for Groovy – you can transparently use Java- and Groovybeans. Combining this with Maven makes it really easy to make Spring even groovier.

Preparation

Setup

This post will focus on the Groovy usage within Spring, therefore the use case is quite simple.

  • A central Java bean has a list of several beans (ie. resembles a workflow)
  • The injected beans must implement an interface ITestStep which is very generic (Object execute(Object))
  • Implementing an interface seems the only way to inject Groovybeans transparently

Code

The Maven POM:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven.groovy</groupId>
  <artifactId>maven.groovy</artifactId>
  <name>maven.groovy</name>
  <version>0.0.1-SNAPSHOT</version>
  <description/>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>2.5.1</version>
    </dependency>
    <dependency>
      <groupId>groovy</groupId>
      <artifactId>groovy</artifactId>
      <version>1.1-rc-1</version>
    </dependency>
  </dependencies>
</project>

The Spring config:

<?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:lang="http://www.springframework.org/schema/lang"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

	<lang:groovy id="groovyTestStep"
		script-source="classpath:SimpleGroovyClass.groovy">
	</lang:groovy>

	<bean id="testFlow" class="de.groovysample.JavaGroovyTest">
<property name="testSteps">
	<list>
				<ref bean="groovyTestStep" />
			</list>
		</property>
	</bean>

</beans>

The Beans (ie. workflowsteps) interface:

package de.groovysample;

public interface ITestStep {

	Object execute(Object arg);

}

The Groovybean (NOTE: this gose to src/main/resources as SimpleGroovyClass.groovy):

import de.groovysample.ITestStep

class SimpleGroovyClass implements ITestStep {

	Object execute(Object arg) {
		println "groovy called with arg: $arg"
	}

}

The Workflow Javaclass the Groovybean is injected to:

package de.groovysample;

import java.util.ArrayList;
import java.util.List;

public class JavaGroovyTest {

	private List<ITestStep> testSteps = new ArrayList<ITestStep>();

	public void setTestSteps(List<ITestStep> testSteps) {
		this.testSteps = testSteps;
	}

	public Object execute(Object arg) {
		for (ITestStep testStep : testSteps) {
			testStep.execute(arg);
		}
		return null;
	}

}

and the Main class:

package de.groovysample;

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

public class Main {

	public static void main(String[] args) {
		ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
		JavaGroovyTest test = (JavaGroovyTest) app.getBean("testFlow");
		System.out.println(test.execute("called from Java"));
	}

}

Resulting in the overall project setup

That’s all, this way you can easily combine Java and Groovy beans (which must implement an interface).

Posted in Groovy, Maven | Tagged: , | 1 Comment »