31
May
13

How to initialize Spring Framework inside JAX-WS Service


This page describes how to write a JAX-WS, Spring Framework based web service.

JAX-WS makes it easier to write web services in Java. It shilds the programmer from implementation
specifics just like JDBC API did for databases.

The two popular implementations out there are the Apache CXF and the Java Reference Implementation. This page describes an application that will run on both.

The project will be tested in Tomcat 6 with the Reference Implementation and we will move to JBoss that has a built in CXF implementation.

Few Notes about the application servers

  • Tomcat 6 does not ship with JAX-WS RI (needs to be installed) or the Spring Framework (needs to be included in the WAR)
  • JBoss 5.1 has the CXF and Spring Framework built in to the server. Therefore don’t provide your own JAX-WS or spring implementation JARS.
  • The Spring application context should be initialized first. Use the ContextLoaderListener to accomplish this.
  • The JAX-WS endpoint servlet/class should be defined in the web.xml and annotated with the JAX-WS annotations. In addition you should use the @PostConstruct on one of the methods to initialize. Within the method use the SpringBeanAutowiringSupport. See the Spring user manual for an example code.

Software versions

  • Tomcat 6 and/or JBoss 5.1
  • w. Servlet Spec 2.5
  • Java 6
  • Spring 2.5.6.SEC01 – older version used since JBOSSWS 5.1 comes pre-packaged with it.
  • Maven 3
  • Soap UI eclipse plugin – to call the web service

pom.xml

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>jax-ws-spring-jboss</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
	<dependencies>
	<dependency>
		<artifactId>spring-context</artifactId>
		<groupId>org.springframework</groupId>
		<version>2.5.6.SEC01</version>
	</dependency>
	<dependency>
		<artifactId>spring-core</artifactId>
		<groupId>org.springframework</groupId>
		<version>2.5.6.SEC01</version>
	</dependency>
	<dependency>
		<artifactId>spring-beans</artifactId>
		<groupId>org.springframework</groupId>
		<version>2.5.6.SEC01</version>
	</dependency>

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>2.5.6.SEC01</version>
	</dependency>

	</dependencies>
	<build>
		<finalName>jax-ws-spring-jboss</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>  
</project>

src/main/java/com/test/Customer.java

package com.test;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="customer",namespace="http://com/test/")
public class Customer implements Serializable {
	private static final long serialVersionUID = 1L;

	private String id;
    private String name;
     
    public Customer() {
		super();
	}
	public Customer(String id) {
		super();
		this.id = id;
	}
	public Customer(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	@XmlElement(nillable=false,namespace="http://com/test/")
	public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
	@XmlElement(nillable=false,namespace="http://com/test/")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

src/main/java/com/test/CustomerService.java

package com.test;

import java.util.List;

import javax.jws.WebMethod;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService(targetNamespace="http://com/test/")
@SOAPBinding(style=Style.DOCUMENT)
public interface CustomerService {
    @WebMethod @WebResult(name="customer")
    List<Customer> getCustomer(String customerID);
}

src/main/java/com/test/CustomerServiceImpl.java

package com.test;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.jws.WebService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

@WebService(endpointInterface="com.test.CustomerService") 
public class CustomerServiceImpl implements CustomerService {

	@Autowired
	private TestDataManager testDataManager;
	
	public TestDataManager getTestDataManager() {
		return testDataManager;
	}
	public void setTestDataManager(TestDataManager testDataManager) {
		this.testDataManager = testDataManager;
	}
	@PostConstruct
	public void postConstruct() {
		System.out.println("postconstruct has run.");
		SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
	}
	@Override
    public List<Customer> getCustomer(String customerId) {
    	System.out.println("JAX-WS getCustomer called");
		return testDataManager.getCustomers();
    }
}

src/main/java/com/test/TestDataManager.java

package com.test;

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

public class TestDataManager {
	/* (non-Javadoc)
	 * @see com.test.TestDataManager#getCustomers()
	 */
	public List<Customer> getCustomers() {
		List<Customer> customerList = new ArrayList<Customer>();
		customerList.add(new Customer("1"));
		customerList.add(new Customer("2"));
		return customerList;
	}
	
}

src/main/webapp/WEB-INF/applicationContext.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"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <bean id="testDataManager" class="com.test.TestDataManager"/>

</beans>

src/main/webapp/WEB-INF/sun-jaxws.xml

<?xml version="1.0" encoding="UTF-8"?>
<endpoints
  xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
  version="2.0">
  <endpoint
      name="CustomerService"
      implementation="com.test.CustomerServiceImpl"
      url-pattern="/customerService"/>
</endpoints>

Running within JBossWS 5.1 container

As mentioned above the JBossWS continer comes prepackaged with Spring Framework 2.5.6.SEC01. To make things easier I have used this older version has been used for Tomcat 6 as well. But interoperatibility is not a problem between Tomcat 6 and JBoss then feel free to use a newer version of the framework.

Since JBoss comes with the Spring Framework and by default it is packaged into the WAR we will need to tell JBoss to use the “parent-first” class loading scheme.

This is done by creating the following file into the WEB-INF folder of the WAR.

src/main/webapp/WEB-INF/jboss-classloading.xml

<classloading xmlns="urn:jboss:classloading:1.0"
    domain="yourDomain"
    parent-first="true">
</classloading>

JBoss uses a different method to initialize the JAX-WS Endpoints. It expects the endpoints to be defined in web.xml as regular servlets. This eliminates the need for the sun-jaxws.xml file.

src/main/webapp/WEB-INF/web.xml

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- Initialize the spring framework first. -->
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>	

	<!-- Use the following with JBossWS CXF implementation 
	<servlet>
		<servlet-name>customerService</servlet-name>
		<servlet-class>com.test.CustomerServiceImpl</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>customerService</servlet-name>
		<url-pattern>/customerService</url-pattern>
	</servlet-mapping>
	-->

	<!-- Use the following with Tomcat and JAX-WS RI 
	-->
    <listener>
        <listener-class>
                com.sun.xml.ws.transport.http.servlet.WSServletContextListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>customerService</servlet-name>
        <servlet-class>
            com.sun.xml.ws.transport.http.servlet.WSServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>customerService</servlet-name>
        <url-pattern>/customerService</url-pattern>
    </servlet-mapping>

	<!-- Test the application using the following URL: 
	http://localhost:8080/jax-ws-spring-jboss/customerService?wsdl -->

</web-app>

The web.xml file above contains both versions of the initilization logic. Comment out the proper section to run the application in JBoss or Tomcat. This is the only file you will need to change when switching between application servers.

Test using the SOAP UI plugin

Soap UI is the best interface I have seen so far to develop test and debug web services. Use it to submit a request to the server and you will see the following response.

Request

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://com/test/">
   <soapenv:Header/>
   <soapenv:Body>
      <test:getCustomer>
         <!--Optional:-->
         <arg0>1</arg0>
      </test:getCustomer>
   </soapenv:Body>
</soapenv:Envelope>

Response

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:getCustomerResponse xmlns:ns2="http://com/test/">
         <customer>
            <ns2:id>1</ns2:id>
         </customer>
         <customer>
            <ns2:id>2</ns2:id>
         </customer>
      </ns2:getCustomerResponse>
   </S:Body>
</S:Envelope>
Advertisements

1 Response to “How to initialize Spring Framework inside JAX-WS Service”



Leave a Reply

Please log in using one of these methods to post your comment:

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


Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 75 other followers

May 2013
S M T W T F S
« Feb   Aug »
 1234
567891011
12131415161718
19202122232425
262728293031  

Blog Stats

  • 813,810 hits

%d bloggers like this: