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

Configure Your Web Service

We need to create web.xml and a Spring application context file.

web.xml configuration

<?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="services" version="2.5">
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/appContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>
            org.apache.cxf.transport.servlet.CXFServlet
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Nothing surprising here. The main thing worth mentioning is that we're using the CXFServlet to process all requests, which we're assuming are all requests for web services.

As you might guess from the web.xml file above, we need to create a Spring application context file called appContext.xml.

appContext.xml configuration

<?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"
    xmlns:cxf="http://cxf.apache.org/core"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    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
        http://cxf.apache.org/core
        http://cxf.apache.org/schemas/core.xsd
        http://cxf.apache.org/jaxws
        http://cxf.apache.org/schemas/jaxws.xsd"
    default-autowire="byName">

    <!-- 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" />
    
    <!-- Enable message logging using the CXF logging feature -->
    <cxf:bus>
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>
    
    <!-- The service bean -->
    <bean id="contactUsServiceImpl" class="contactus.ContactUsServiceImpl"/>

    <!-- Aegis data binding -->
    <bean id="aegisBean"
        class="org.apache.cxf.aegis.databinding.AegisDatabinding"
        scope="prototype"/> 
    <bean id="jaxws-and-aegis-service-factory"
        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>
 
    <!-- Service endpoint -->
    <!-- See http://incubator.apache.org/cxf/faq.html regarding CXF + Spring AOP -->
    <jaxws:endpoint id="contactUsService"
            implementorClass="contactus.ContactUsServiceImpl"
            implementor="#contactUsServiceImpl"
            address="/contactus">
        <jaxws:serviceFactory>
            <ref bean="jaxws-and-aegis-service-factory"/>
        </jaxws:serviceFactory>
    </jaxws:endpoint>
</beans>

Let's talk about appContext.xml.

The first three imports just import some bean definitions from the CXF JAR file. I don't know the details and I don't think we're supposed to care about the details.

The bus config just puts logging in. That's optional. If you run this in a production environment you probably want to turn that off because it's verbose.

The service bean definition is just telling Spring about the service bean we wrote. We're going to put a web service endpoint in front of it.

The next piece on Aegis specifies the databinding mechanism we want to use for mapping back and forth between Java and XML. I mentioned earlier that I tried using the default JAXB but was having problems getting it to work, so someone recommended to me to try Aegis and that worked like a charm.

Finally we define the web service endpoint. The #contactUsServiceImpl piece connects the endpoint up to the service bean. (Yes, the hash mark is required.) We use the JAX-WS/Aegis service factory that we defined earlier so we can use the Aegis databinding.

I'm not using transactions or persistence in my simple service bean. In a realistic service you are going to have transactions and persistence. To make CXF play nicely with AOP (and hence Spring's declarative transactions) you are going to need to include the implementorClass attribute as I've done. For more details on that see the CXF FAQs at http://incubator.apache.org/cxf/faq.html.

A validation annoyance in Eclipse

Though it in no way reflects a fault with Eclipse itself, if you are using Eclipse 3.3 you may be getting some annoying validation errors in the IDE, such as "cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'jaxws:endpoint'." This is because the schema locations for the http://cxf.apache.org/core and http://cxf.apache.org/jaxws keys don't actually point at real XSDs, so the validator won't recognize elements from the cxf and jaxws namespaces. (That's why I say it isn't Eclipse's fault.) This doesn't create a problem with the actual build, but the IDE will complain as it tries to validate the Spring app context files against the missing XSDs. I haven't yet discovered the "right" solution to this problem (I'd be delighted to have somebody tell me) but there are three workarounds I know about:

  • You can map the http://www.springframework.org/schema/beans key to the http://www.springframework.org/schema/beans/spring-beans.xsd location (notice that I've removed the -2.5 part). That gets rid of the validation errors though now you're using the Spring 2.0 beans schema. That may be OK for you.
  • You can turn off XML validation. That seems pretty drastic but it's an option (and in fact it's what I've myself done).
  • You can just ignore the errors. Can't... bring... myself... to... do... it... .

There may be something you can do with Window → Preferences → Web and XML → XML Catalog but I didn't see it: even if you put the core.xsd and jaxws.xsd in the catalog, those XSDs in turn reference other schema locations that don't resolve to an XSD and it looks like a lot of work to me.

Anyway as I say if somebody knows the right way to handle this please let me know and I'll gladly update the article and credit you. :-)

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

Post a comment

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

What's New?

2008-10-20 - I've added a new mailing list feature to the site. Sign up to receive e-mail updates about new articles.
2008-09-30 - We've released chapter 4 (User registration) and chapter 5 (Authentication) of Spring in Practice.
2008-09-11 - By popular demand, I've added an RSS feed to the site.
Home | Consulting | Tech Articles | Mailing List | About | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.