tanakawho
Photo credit: tanakawho
del.icio.us Digg DZone Reddit StumbleUpon
1 | 2 | 3 | 4 | Next »
Software Development

Make Web Services Transparent with Spring 2.5 and Apache CXF 2.0

Write web service clients that don't know they're web service clients using Spring and CXF.

In our previous installment, we showed how to create Java-first web services in Spring 2.5 using Apache CXF 2.0. This time we're going to show how to consume web services, once again using Spring 2.5 and Apache CXF 2.0.

Something great about the Spring/CXF duo is that your web service clients don't know that they're web service clients. The approach is simple: as in any Spring app, you define Java interfaces for your services and inject the service implementations into the client classes that use them (such as MVC controllers). CXF allows you to generate dynamic proxies according to the same Java service contract—the proxies are just another service implementation—and hence your client classes have no idea that they're calling web services.

This article shows you what you need to do to get it to work. If you haven't already done so, please see the previous article, Web Services with Spring 2.5 and Apache CXF 2.0, to get your web services set up. That article describes a user comment service that I build upon in the current article.

Project Setup

First we need to set up the web service client project. Here are the various dependencies involved.

Spring 2.5

These all come from the Spring 2.5 distribution. You can use whatever Spring 2.5 libraries you need for your own app. Here I just happen to be using Spring MVC and JSTL, though neither of those is required for Spring/CXF integration.

  • jstl.jar (in lib/j2ee)
  • spring.jar
  • spring-mvc.jar (in dist/modules; the sample app uses Spring MVC)
  • standard.jar (in lib/jakarta-taglibs; this is the JSTL reference implementation)

CXF and dependencies

You can get these from the CXF 2.0.4 distribution. Whether all of these are really necessary I don't know—for example I'm not sure why we need the JavaMail library—but I'm just going by what the CXF user manual says.

  • commons-logging-1.1.jar
  • cxf-2.0.4-incubator.jar (this is the main CXF JAR)
  • geronimo-activation_1.1_spec-1.0-M1.jar (or Sun's Activation jar)
  • geronimo-annotation_1.0_spec-1.1.jar (JSR 250)
  • geronimo-javamail_1.4_spec-1.0-M1.jar (or Sun's JavaMail jar)
  • geronimo-servlet_2.5_spec-1.1-M1.jar (or Sun's Servlet jar)
  • geronimo-stax-api_1.0_spec-1.0.jar
  • geronimo-ws-metadata_2.0_spec-1.1.1.jar (JSR 181)
  • jaxb-api-2.0.jar
  • jaxb-impl-2.0.5.jar
  • jaxws-api-2.0.jar
  • neethi-2.0.2.jar
  • saaj-api-1.3.jar
  • saaj-impl-1.3.jar
  • wsdl4j-1.6.1.jar
  • wstx-asl-3.2.1.jar
  • XmlSchema-1.3.2.jar
  • xml-resolver-1.2.jar

Aegis dependencies

In addition to the above, you will need to add jdom-1.0.jar since Aegis databinding uses it.

Client library dependencies

In the previous article we created three classes in the contactus package: ContactUsService, ContactUsServiceImpl, and Message. You will need to JAR ContactUsService (which is a service interface) and Message (which is a domain model class) and add the JAR as a dependency for the client application. You do not need to include ContactUsServiceImpl since that's the backend for the web service; it's not part of the interface. On the client side we will see that CXF will create a web service proxy according to the ContactUsService interface, and it will use Message for marshalling and unmarshalling.

With the dependencies in place, we'll now create a simple client that can view user messages using the web service we created the last time. We're not going to treat the "post user message" operation in this article though it works in exactly the same way (which is why we're not going to treat it).

Social bookmarks: del.icio.us Digg DZone Reddit StumbleUpon
1 | 2 | 3 | 4 | Next »

Comments (25)

Good stuff. Did you ever get JAXB working?
By dj on Mar 14, 2008 at 11:09 AM PDT
Thanks DJ. Nope, though I didn't try after I wrote the article. JAXB worked fine as long as I stuck with simple data types. You can try it yourself by just removing the serviceFactory injection from the contactUsFactory in myapp-servlet.xml. Maybe you'll have better luck than I did. If so I'd be interested to hear.
By Willie Wheeler on Mar 14, 2008 at 10:36 PM PDT
Is there a URL that I can get your example source code?
Thanks!
By XML on Mar 21, 2008 at 5:34 AM PDT
Hi XML. I added the source code for the services and client app to the Resources section at the end of the article. I did not include the third-party JARs since those mostly come from the CXF distribution itself.
By Willie Wheeler on Mar 21, 2008 at 11:28 PM PDT
Tried the tutorial, it works great as is
1. except the one JAR file as JDOM1.0.Jar needs to be added as mentioned in your earlier tutorial.
2. JSP file does not print anything, but I am getting the output in Console.
${message.lastNameFirstName} (${message.email}): ${message.text}
By Mark on Apr 4, 2008 at 1:06 PM PDT
It works with Spring 2.5.2 using JBoss 4.3 CXF stack (not with the default included 2.0.4, but with 2.0.5).
By Marek Lange on Apr 9, 2008 at 2:17 AM PDT
I cant get the client to work with spring 2.5.x, there is a very annoying bug for me:

java.lang.NoSuchMethodError: setConfigLocation
org.springframework.web.servlet.FrameworkServlet.c reateWebApplicationContext(FrameworkServlet.java:3 98)....

I changed the client for spring 2.0.x and it works.
By Isaias on May 8, 2008 at 7:53 AM PDT
Not sure exactly what you're running into but the API changes from time to time. The setConfigLocation() method appears in Spring 2.5.2; compare the Spring 2.5.1 API

http://static.springframework.org/spring/docs/2.5.1/api/org/springframework/web/context/ConfigurableWebApplicationContext.html

with the Spring 2.5.2 API

http://static.springframework.org/spring/docs/2.5.2/api/org/springframework/web/context/ConfigurableWebApplicationContext.html

When I wrote the article I was using the Spring 2.5.0 distribution. If you aren't already doing so I would try using the latest versions of Spring and CXF and see if you have any luck. Sounds like you aren't the only one who's had this issue though:

http://forum.springframework.org/showthread.php?p=179390
By Willie Wheeler on May 9, 2008 at 8:43 PM PDT
Hi, I'm beginner and I have a problem with client :(
I use tomcat 6.0.x, spring 2.5.4 and CXF 2.1

org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader.
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:70)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:35)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:221)
..........
..........
Thanks for help
By Petross on May 15, 2008 at 5:53 PM PDT
how to access a webservice from another webservice
By kiran on Sep 2, 2008 at 4:51 AM PDT
Thanks for the article! I created a maven build so that folks can run (and change) the code instantly. See: http://www.jroller.com/brodkin/entry/a_maven_project_for_willie
By Sam Brodkin on Sep 3, 2008 at 5:44 AM PDT
Great Article, indeed cxf works well with aegis...until you dont use circular references in your model...
By Sylvain on Sep 11, 2008 at 3:09 AM PDT
Great Article. Thanks.
I want to use a Java client for this rather than the web client. What should I do?

Regards,
Srikanth
By Srikanth Vishwanath on Nov 4, 2008 at 3:36 AM PST
Hi Srikanth. Just inject the service bean proxy into your Java client and you should be in business. So to use the example from the article, you'd inject the contactUsService (the service bean proxy) into your Java class.
By Willie Wheeler on Nov 4, 2008 at 6:38 AM PST
The only thing that strikes me as bad is the fact that we have to place a server side jar on the client side which kinda seems to defeat the purpose of using web services in the first place. By introducing a dependency and that too by placing jars your going to run into maintenance nightmares when you want to change/upgrade your server and you need all your clients to upgrade along with you
By Nikhil on Nov 8, 2008 at 7:10 AM PST
Thanks for the excellent articles.

I get the following error when I compile against a new WSDL.

Rpc/encoded wsdls are not supported in JAXWS 2.0

Is there any way that I can use CXF with RPC encoded WSDLs??
By Steve Daly on Dec 1, 2008 at 9:05 AM PST
Haven't run into it myself but here's a forum post I found about it:

http://www.nabble.com/Rpc-encoded-wsdls-are-not-supported-in-JAXWS-2.0-error-td20420617.html
By Willie Wheeler on Dec 1, 2008 at 11:34 PM PST
Hi,
I've just tried your code without AEGIS and got it working without any problem. Maybe that's because I'm using CXF 2.1.3 ?
By Frédéric ESNAULT on Dec 17, 2008 at 6:50 AM PST

Great articles Willie!

I tried following both tutorials and got it working but for some reason, if the client is spring injected, its method which is supposed to return a DataHandler for binary data is returning null.

I tried this programmatically instead of using Spring and it works perfectly. Would you have any ideas why?

By Jarell on Feb 24, 2009 at 5:32 AM PST

@Jarell: Can you post the relevant part of your app context file? (Please use the <pre> tag to format it.)

By Willie Wheeler on Feb 24, 2009 at 6:58 AM PST

Hi Willie,

Here's the programmatic way:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(JasperWebService.class);
factory.setAddress("http://localhost:8081/JasperWebServiceApp/jasper");
JasperWebService client = (JasperWebService) factory.create();
DataHandler dh = client.generateCommsTreeSample();
fos = new FileOutputStream(filePath);
dh.writeTo(fos); 

Here's the Spring Config when I try to inject the client, (I'm using JSF support of Spring to inject it to the backing bean):

<bean id="JasperWebServiceFactory" 
        class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
   <property name="serviceClass" 
        value="com.hp.bcp.jasperws.contract.service.JasperWebService"/>
   <property name="address" 
        value="http://localhost:8081/JasperWebServiceApp/jasper"/>
   <property name="serviceFactory" 
        ref="jaxwsAndAegisServiceFactory"/>
</bean>


<bean id="jasperWebService"
          class="com.hp.bcp.jasperws.contract.service.JasperWebService"
          factory-bean="JasperWebServiceFactory"
          factory-method="create"/>

<bean id="aegisBean"
           class="org.apache.cxf.aegis.databinding.AegisDatabinding"
           scope="prototype"/>

<bean id="jaxwsAndAegisServiceFactory"
           class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"
           scope="prototype"> 
   <property name="dataBinding" ref="aegisBean"/>
   <property name="serviceConfigurations">
   <list>
     <bean class="org.apache.cxf.jaxws.support.JaxWsServiceConfiguration"/>
     <bean class="org.apache.cxf.aegis.databinding.AegisServiceConfiguration"/>
     <bean class="org.apache.cxf.service.factory.DefaultServiceConfiguration"/> 
   </list>
   </property>
</bean> 
By Jarell Mallari on Feb 24, 2009 at 11:08 PM PST

The server seems to work just fine. However, I'm having accessing the client.

Once i set up everything and when i try to access using the client web site(e.g. http://localhost:9006/CXFClient/viewMessages.do)

I'm having this error from the client console:

16:49:35,813 WARN [PageNotFound] No mapping found for HTTP request with URI [/CXFClient/viewMessages.do] in DispatcherServlet with name 'myapp'

please help

By nel on Apr 15, 2009 at 5:11 PM PDT

Very usefull article,

I get the server to run without any problems, however, the client is a pain in the ass.

I'm using Java 6, TomCat 6, Spring 2.5 and CXF 2.2

I get the following exception when i start the client:

print("Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cxf' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:971)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:435)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:409)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:537)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:192)
at org.springframework.beans.factory.annotation.InjectionMetadata.injectMethods(InjectionMetadata.java:117)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:302)
... 56 more"); 

I solved the problem by adding the following code the CXF Spring config:

print("<!-- Load CXF modules from cxf.jar -->
<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" />"); 
By Chris Gunnink on Apr 25, 2009 at 7:21 AM PDT

Hmm, weird input form...

The Exception message was:

"Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'cxf' is defined".

By Chris Gunnink on Apr 25, 2009 at 7:23 AM PDT

i have this exception:

java.lang.NoSuchMethodError: org.apache.ws.commons.schema.XmlSchema.getTypeByName

for jar XmlSchema-1.3.2

what this ? i use be tomcat-6 and jboos

By Gilberto Santos on May 12, 2009 at 6:33 AM PDT

Post a comment

Your name:
Your e-mail address (won't be displayed):
Your web site (optional):
example: www.xyz.com
Your comment:
Preview:
By You
Please help us reduce comment spam:
Spring in Practice
My brother and I are writing Spring in Practice for Manning!

What's New?

2009-03-25 - My new article Getting Started with Spring Batch 2.0 is available on DZone.
2008-12-14 - We've just submitted a few more chapters of the book for review, so we're about halfway done.
2008-10-20 - I've added a new mailing list feature to the site. Sign up to receive e-mail updates about new articles.
Home | Consulting | Tech Articles | Mailing List | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.