Basic Spring Web services with XFire and JSR 181

Basic Spring Web services with XFire and JSR 181

I hadn’t intended to expose any of our functionality with Web services so soon, but that’s the great thing about Spring—many of the services are orthogonal to each other. Let’s look at how we can expose some Spring beans as Web services. We’ll do it using JSR 181 too, which means that the Web service implementation is so easy that even a Ruby hacker could write it…;-)
Web Services and JSR 181

Look here for an introduction to JSR 181 and where it fits in to the world of Web services. You need not though, as it’s pretty simple. First, let’s define the interface to our simple Web service:

package com.memestorm.ws;

import javax.jws.WebService;

@WebService( targetNamespace = “http://memestorm.com/skeleton1/AuthorService” )
public interface AuthorService {

	public String sayHello();

}

That’s it. Note the nice @WebService annotation. It’s all that’s really necessary. I threw in the targetNamespace attribute to show how you can modify things. The system will automatically generate a WSDL file - and using these attributes (and others) you can modify the generated WSDL. Now that we have the interface, let’s implement it!

package com.memestorm.ws;

import javax.jws.WebService;

@WebService(
  serviceName = "MyAuthorService",
  endpointInterface = "com.memestorm.ws.AuthorService"
)
public class AuthorServiceImpl implements AuthorService {

  public String sayHello() {
    return "Hello World Services!";
  }
}

Oh my, that was easy….There’s nothing to say, except:

  • Do you see how there aren’t any external dependencies in this code? The only thing I import is the annotation…this is cool…
  • This is just a POJO - which we’ll be defining in a Spring context file. So we can easy wire it up with other beans using IoC.
  • This is an example of CoC again—you don’t have to do much other than write @WebService.

Okay, now that we’ve written our Web service - and you can write as many as you like of course, let’s look at how to wire it all together.

Hooking XFire into your Spring Application

I used XFire as the Web services stack here. It implements some nice things that I don’t find in Apache Axis, such as the JSR 181 stuff, multiple XML binding mechanisms, multiple transports (including Jabber & JMS) etc. You only have to hook it into your web application once. After that, simply create your POJOs and expose them. What you need to do is:

  1. Create the XFire Spring context configuration file. It’s here that you expose your POJOs, and where you can wire in other Spring beans etc.
  2. Modify the Web application web.xml to deploy the XFire servlet
  3. Modify your build process to include all the right JARs

Let’s look at these in order.

1. XFire Configuration File

Now XFire’s pretty powerful. You can configure just about anything, and much of this you can do from the configuration file. It’s also where you expose your POJOs. The following file, xfire-servlet.xml, contains a little of both:

<beans>

 <!--  add your beans here -->
 <bean id=”annotatedAuthorService”
     class=”com.memestorm.ws.AuthorServiceImpl”/>
 <!–  fin  –>

 <bean id=”webAnnotations”
     class=”org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations”/>
 <bean id=”handlerMapping”
     class=”org.codehaus.xfire.spring.remoting.Jsr181HandlerMapping”>
        <property name=”typeMappingRegistry”>
            <ref bean=”xfire.typeMappingRegistry”/>
        </property>
        <property name=”xfire”>
            <ref bean=”xfire”/>
        </property>
        <property name=”webAnnotations”>
            <ref bean=”webAnnotations”/>
        </property>
 </bean>

 <bean class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
        <property name=”urlMap”>
            <map>
                <entry key=”/”>
                    <ref bean=”handlerMapping”/>
                </entry>
            </map>
        </property>
    </bean>

    <import resource=”classpath:org/codehaus/xfire/spring/xfire.xml”/>

</beans>

The lines in bold are the only ones that matter to us - it exposes our bean implemented by com.memestorm.ws.AuthorServiceImpl. The rest configures XFire to use annotations in the first place and sets up some defaults. You will want to come back here when you do more advanced stuff such as type mappings.

2. Configuring the XFire Servlet

As you’ve seen, we’ve got this xfire-servlet.xml context configuration file. You’ll want to tell Spring about it, and as we’ve shown before, you can do this by modifying the contextConfigLocation context parameter in web.xml:

 <context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>
     /WEB-INF/applicationContext.xml /WEB-INF/jdbcContext.xml
     /WEB-INF/xfire-servlet.xml
   </param-value>
 </context-param>

You also need to add the following lines:

   <servlet>
     <servlet-name>XFireServlet</servlet-name>
     <servlet-class>
       org.codehaus.xfire.spring.XFireSpringServlet
     </servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>XFireServlet</servlet-name>
      <url-pattern>/servlet/XFireServlet/*</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
     <servlet-name>XFireServlet</servlet-name>
     <url-pattern>/services/*</url-pattern>
   </servlet-mapping>

That simply ensures that XFire is deployed as a servlet.

3. Build

XFire has an astounding array of dependencies - and you only need some under various circumstances. Here’s how I had to modify the build file to account for this:

  • Modify the master-classpath so that I had the right JARs in my path to compile everything:

     

     <fileset dir="${xfire.root}">
       <include name="xfire-all-1.1.jar" />
     </fileset>
     <fileset dir="${xfire.root}/lib">
       <include name="xfire-jsr181-api-1.0-M1.jar" />
     </fileset>
    
  • Modify the libraries target to ensure all run-time JARs are available:
    <fileset dir="${xfire.root}">
      <include name="xfire-all-1.1.jar" />
    </fileset>
    <fileset dir="${xfire.root}/lib">
      <include name="stax-api-1.0.1.jar" />
      <include name="xfire-jsr181-api-1.0-M1.jar" />
      <include name="activation-1.1.jar" />
      <include name="mail-1.4.jar" />
      <include name="jaxen-1.1-beta-8.jar" />
      <include name="jdom-1.0.jar" />
      <include name="wsdl4j-1.5.2.jar" />
      <include name="wstx-asl-2.9.3.jar" />
    </fileset>
    

Okay, I admit there is a little pain here. But you only need to do this once of course, and you are deploying an awesome Web service stack that will bring you hours of pleasure…

4. Running it

That’s it though - grab the source below, run build, deploy, and you’ll have exposed the web service. The XFire servlet provides a nice way to view the deployed Web services too. If you go to http://localhost:8080/skeleton2/services/ you’ll see:

 Services:
  o MyAuthorService [wsdl]

with a link to the WSDL file. Viewing the WSDL file you’ll get the expected output:

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:tns=”http://memestorm.com/skeleton1/AuthorService” xmlns:wsdlsoap=”http://schemas.xmlsoap.org/wsdl/soap/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” targetNamespace=”http://memestorm.com/skeleton1/AuthorService”>
  <wsdl:types>
    <xsd:schema targetNamespace=”http://memestorm.com/skeleton1/AuthorService” elementFormDefault=”qualified” attributeFormDefault=”qualified”>
      <xsd:element name=”sayHello”>
        <xsd:complexType />
      </xsd:element>
      <xsd:element name=”sayHelloResponse”>
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name=”out” type=”xsd:string” nillable=”true” minOccurs=”1″ maxOccurs=”1″ />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>

……

  <wsdl:service name=”MyAuthorService“>
    <wsdl:port binding=”tns:MyAuthorServiceHttpBinding” name=”MyAuthorServiceHttpPort”>
      <wsdlsoap:address location=”http://localhost:8080/skeleton1/services/MyAuthorService” />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Nice huh? No hassle Web services…

A Client

Okay, here’s a client that you can run against the Web service. Read the XFire documentation to learn more about it if you like:

package com.memestorm.ws.client;

import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.annotations.AnnotationServiceFactory;
import com.memestorm.ws.*;

import java.net.MalformedURLException;

public class Test {
	public static void main(String[] args) {
		Service serviceModel = new AnnotationServiceFactory()
				.create(AuthorServiceImpl.class);
		try {
			AuthorService service = (AuthorService) new XFireProxyFactory().create(
					serviceModel,
					"http://localhost:8080/skeleton1/services/MyAuthorService");
			String s = service.sayHello();
			System.out.println(s);

		} catch (MalformedURLException e) {
			e.printStackTrace();
		}

	}
}
Summary

What we’ve done here is set up a scenario where you can easily expose POJOs as Web services using JSR 181 standard annotations. These are standard annotations that you’ll find in Java EE 5 - so it’s pretty nice to be able to use them here in the XFire Web services stack.

Moreover, this scenario is hooked into our Spring web application. We can trivially add additional POJOs, and use the full Spring toolbox to manipulate them.

Download

Here’s a JAR of all the source, with instructions on how to build and deploy:
skeleton2-1.zip

Acknowledgements

I’d like to reference the Logemann Blog that showed me how to do most of this stuff. 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值