del.icio.us Digg DZone Reddit StumbleUpon
Make Web Services Transparent with Spring 2.5 and Apache CXF 2.0 - Willie Wheeler
« Previous | 1 | 2 | 3 | 4 | Next »

Creating the Client Application

This sample app is based on Spring MVC. For that we'll need to create a couple of MVC controllers, a couple of JSPs, a web.xml file, and a Spring application context file.

Spring MVC controller for viewing messages

First we'll create a Spring MVC controller called myapp.ViewMessagesController.

package myapp;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import contactus.ContactUsService;

@Controller
public final class ViewMessagesController {
    private ContactUsService contactUsService;
    
    public void setContactUsService(ContactUsService contactUsService) {
        this.contactUsService = contactUsService;
    }
    
    @RequestMapping("/viewmessages.do")
    public ModelMap viewMessages() {
        return new ModelMap("messages", contactUsService.getMessages());
    }
}

Since this is an article about Spring/CXF integration and not about Spring MVC, I won't go into the details of Spring MVC or annotation-based configuration. If however you are interested in learning more, please see my article Annotation-Based MVC in Spring 2.5.

At any rate, the code is easy enough to understand. We have a dependency injection method setContactUsService. Any implementation of ContactUsService could go in there, including the one we wrote in the previous article, contactus.ContactUsServiceImpl. In this case, though, we're going to use a CXF-generated dynamic proxy as shown below.

The viewMessages method simply grabs a list of messages from the ContactUsService and puts it in a model that the JSP will be able to see.

JSP for viewing messages

You will need to put this file at /WEB-INF/jsp/viewmessages.jsp in order for the request mapping to work as specified in ViewMessagesController above and myapp-servlet.xml below. For those who are unfamiliar with Spring's annotation-based MVC configuration, the @RequestMapping("/viewmessages.do") annotation maps the given path to the viewMessages method, and the view resolver in myapp-servlet.xml tells Spring to look inside /WEB-INF/jsp/ for the corresponding JSP.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>View Messages</title>
    </head>
    <body>
        <h1>View Messages</h1>
        <ul>
            <c:forEach var="message" items="${messages}">
                <li>${message.lastNameFirstName} (${message.email}): ${message.text}</li>
            </c:forEach>
        </ul>
    </body>
</html>

This just displays a list of user messages. I'm using JSTL and JSTL EL. The ${messages} reference in the forEach tag refers to the list of messages that I placed in the ModelMap in ViewMessagesController.viewMessages above. Spring takes care of making the contents of the ModelMap available to the JSP.

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="ws" version="2.5">
    
    <servlet>
        <servlet-name>myapp</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>myapp</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

This just sets up the Spring MVC DispatcherServlet and tells the servlet container that the *.do extension mapping goes to the DispatcherServlet.

Now let's dig into the guts of it—the Spring application context.

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

Comments (31)

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

Hi Willie,

I managed to get it working with JAXB by moving to cxf 2.2.3 and Spring 2.5 (or higher).

The change to the myapp-servlet.xml is as follows:

<jaxws:client id="contactUsService"
              serviceClass="contactus.ContactUsService"
              address="http://localhost:8080/Cxf/contactus" />

<!-- Controllers -->
<bean class="myapp.ViewMessagesController">
    <property name="contactUsService" ref="contactUsService"/>
</bean>

<!-- View resolvers -->
<bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean> 

Please note that CXF and Spring will not work on Websphere 7.0x because the websphere jax-ws engine does not honor spring bean dependencies for web service endpoints. (i.e. the WAS engine instantiates the web service impl every time a call is made, bypassing the already instantiated one in spring (assuming you are using a singleton)) This is true even if you turn off annotation scanning and revert to the 2.4 servlet specification. I am working with IBM on fixing the issue.

By Terry Trippany on Sep 10, 2009 at 8:44 AM PDT

As a follow up on the WAS 7.0 issue the fix is simple. It is a matter of telling the container not to search the source code for annotations relying instead on the web.xml file. This is accomplished by by adding metadata-complete="true" to the web.xml as shown in the following example:

It will also decrease startup time but you must make sure to include all your resources in the web.xml.

  • Trip
By Terry Trippany on Sep 11, 2009 at 9:36 AM PDT

Sorry, the blog stripped my example:

web-app
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app 25.xsd" metadata-complete="true"
version="2.5">

By Terry Trippany on Sep 11, 2009 at 9:39 AM PDT

Hi Willie

Great tutorial.

This is the first time i try the CXF Web Service with Spring. I am using Eclipse and Tomcat 6. Your previous tutorial works fine on my environment. When trying this one, I copied your code and followed the steps, but every time I deploy the app on my Tomcat, I got this error below. Could you help?

SEVERE: StandardWrapper.Throwable java.lang.NoSuchMethodError: org.springframework.web.context.ConfigurableWebApplicationContext.setConfigLocation(Ljava/lang/String;)V at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:398) at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316) at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:282) at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126) at javax.servlet.GenericServlet.init(GenericServlet.java:212) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1172) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:992) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4058) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4371) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045) at org.apache.catalina.core.StandardHost.start(StandardHost.java:719) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443) at org.apache.catalina.core.StandardService.start(StandardService.java:516) at org.apache.catalina.core.StandardServer.start(StandardServer.java:710) at org.apache.catalina.startup.Catalina.start(Catalina.java:578) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)

By Alex on Nov 9, 2009 at 5:04 AM PST

The Pandora pandora schmuck myth first Pandora Armreifenappears in lines Pandora Halsketten of Hesiod's poem in Pandora Charms epic meter, the Theogony (ca. 8th?7th centuries BC), without ever giving the woman a name. After humans Pandora Sets have received thethe myth is a rosetta stone kind of theodicy, addressing the question pop information, web easy get, sports fashion, news-fashionof why there is evil in the world. In the seventh hot-winter century BC, Hesiod, both in his Theogony (briefly, without naming Pandora outright rosetta stone language, rosetta stone spanish, abercrombie and fitch , Abercrombie Fitch

By pandora schmuck on Aug 30, 2010 at 11:14 PM 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-08-30 - Check out my two-part series on DZone: Spring Integration: A Hands-On Tutorial.
2009-03-25 - My new article Getting Started with Spring Batch 2.0 is available on DZone.
Home | Consulting | Tech Articles | Mailing List | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.