“simple” web services using CXF deployed in JBoss

I needed web services up and running, and after a short look at what looks like the best framework for implementing web services, I ended up choosing CXF.

Now though the standalone demo is pretty simple (as explained on the site), deploying this in JBoss is somewhat more difficult. This is partly caused by difficult to find documentation, and partly by possible clashes caused by the classloader (some libraries you really don’t want to have in your classpath twice).

Let’s start by running the demo, then explain what I did and why I made some of the choices I made.

I have a small project which implements this little demo that you can download. You have to fix some of the settings in the main pom.xml file. Specifically the details of your JBoss installation which can be found in the properties in the dev-example profile.
You also need a working JBoss instance, with cargocpc in it. One option is downloading this tuned configuration. I would recommend you to remove the “jbossws.sar” directory from deploy. This contains a different web services stack. However, the demo does not include the CXF libraries, so these need to be added in your deploy directory. The easiest way is to download and extract cxf-2.0.5.sar.tgz.

When these changes are done, thanks to maven, you can run and test the simple “ping” web service by typing
mvn -Dfulltest -Ddev=example install

The actual service and implementation are very simple

package cxfdemo.ws10;

public interface PingService
{
    String getPing();
}

package cxfdemo.ws10.impl;

import cxfdemo.ws10.PingService;

import java.sql.Date;

public class PingServiceImpl
    implements PingService
{
    public String getPing()
    {
        return "Ping back @" + new Date( System.currentTimeMillis() );
    }
}

To assure this works, the following web.xml is provided

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/cxfdemo/ws10/cxf.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <display-name>Prolix Web Services 1.0</display-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

This in turn refers to the following cxf.xml configuration file

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:simple="http://cxf.apache.org/simple"
       xmlns:soap="http://cxf.apache.org/bindings/soap"
       xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd">

    <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" />

    <simple:server id="ping"
                   serviceClass="cxfdemo.ws10.PingService"
                   address="/ping"
        >
        <simple:serviceBean>
            <bean class="cxfdemo.ws10.impl.PingServiceImpl"/>
        </simple:serviceBean>
        <simple:dataBinding>
            <bean class="org.apache.cxf.aegis.databinding.AegisDatabinding"/>
        </simple:dataBinding>
    </simple:server>

</beans>

Running and testing this bean can be done using this simple program.

package cxfdemo.ws10.test;

import cxfdemo.ws10.PingService;
import junit.framework.TestCase;
import org.apache.cxf.frontend.ClientProxyFactoryBean;

public class PingTest
    extends TestCase
{
    public void testPingService()
        throws Exception
    {
        ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
        factory.setServiceClass( PingService.class );
        factory.setAddress( "http://localhost:8080/cxfdemo/ws/1.0/ping" );
        factory.getServiceFactory().setDataBinding( new AegisDatabinding() );
        PingService client = (PingService) factory.create();
        String res = client.getPing();
        assertTrue( res.startsWith( "Ping back @" ) );
    }
}

This all is very short and compact.

Why the projects is built like this.

  • The project does not include the libraries as JBoss can cause problems when a library is in the classpath more than once. “commons-logging” is a typical example of this.
    This also has the advantage that the deployments don’t need to include the libraries again.
  • The service interface is put in a separate module than the implementation. This allows easy distribution of the interfaces in java form (which for many people is more readable than wsdl files).
  • The project is built to allow compiling and installing to work without running the full tests. However, you can run them if you want to (using the fulltest profile).
  • There is a jboss web services implementation which uses CXF. However, this was not used here as this does not include the “simple” CXF interface, only the JAX-WS interface.
  • The web services module names, interface packages and URL includes a version identifier. This is part of the the way the project is built. When all the interfaces are in one module, then it should be possible to keep the services stable (same WSDL) even when the actual backend code changes. When incompatible changes are required, you can just create anoth set of modules (one interface, one implementation, and provide the changes there.

518 Comments

  1. Hi,

    We have read your “simple” web services using CXF deployed in JBoss article and thought it was really good.

    I am the community content coordinator for DZone and it would be an honor if you would share this article with our readers by giving us your permission to repost this on our website, http://www.dzone.com.

    Please let me know soon. I look forward to hearing back from you soon.

    Best regards,

    Wei Ling Chen

    Community Content Coordinator, DZone, Inc.

    Phone: 919-678-0300 ext. 105

    Email: weiling@dzone.com

    AOL/MSN/Jabber: weiling@dzone.com

  2. Jimmer says:

    The code is simple enough, but how are the files
    organized in the resulting war file?

    Thanks,

    – Jim

  3. joachim says:

    Jim,

    At the top of the article, there is a link where you can download the entire project which builds the war file.

    The war is very thin. All the libraries are deployed separately in the cxf.sar file. The war just contains the cxf.cfg file, the jar with the interfaces and the implementation classes.

    Hope this helps,
    Joachim

  4. Diego Ardila says:

    Hi,
    I modified your example to try to send and return a complex type as a parameter (for example, a Map of Employee). To make the project work, I had to specify in the client that I was using Aegis:

    factory.getServiceFactory().setDataBinding(new AegisDatabinding());

    ¿can you tell me if this is a normal step?.

    Thanks,
    Diego A.

  5. joachim says:

    Yes this seems to be normal, I have noticed this as well. Updating the description…

  6. shikarishambu says:

    Hi,
    Thanks for the article and the jar file. I tried implementing CXF with JBOss 4.2.2

    I keep getting the following error
    Janino compilation error

    Imported class “org.apache.cxf.frontend.ClientProxyFactoryBean” could not be loaded

    I am not using the tuned server that you have provided. I have a different server.

    I do see the following error, too
    Failed to find META-INF/jboss-service.xml for archive cxf-2.0.5.sar

    Please help

    TIA

  7. joachim says:

    @shikarishambu

    It is difficult to guess the cause of the problems you are reporting without seeing the full JBoss installation. I assume your server/default/lib directory still contains some libraries which need to be removed (check for duplicates in the sar).

Leave a Reply

Your email address will not be published. Required fields are marked *

question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

*