Writing the Hello World CXF webservice

Before I get into this post, I’m well aware that SOAP hasn’t been the cool kid on the block in terms of web service messaging for a while, but I’m looking at updating an old application’s webservice from a framework which is no longer supported on an older version of Java to a supported framework. So we need to keep everything working using SOAP.

Following these steps, we can get a service up and running in next to no time (ofcourse it took me far longer than “no time” to find out how to do this :)).

  • Create yourself a folder for your project, mine’s cxftest
  • Within your project’s folder create a Maven pom.xml to grab all our required dependencies we’ll require – here’s the pom
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.putridparrot.core</groupId>
      <artifactId>cxftest</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>cxftest</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <cxf.version>2.2.3</cxf.version>
      </properties>
    
      <dependencies>
    
        <dependency>
          <groupId>org.apache.cxf</groupId>
          <artifactId>cxf-rt-frontend-jaxws</artifactId>
          <version>${cxf.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.apache.cxf</groupId>
          <artifactId>cxf-rt-transports-http</artifactId>
          <version>${cxf.version}</version>
        </dependency>
    
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    
  • We’re going to do everything from scratch here, but continue with the layout that Maven might generate for us, so off of your project’s folder create src/main/java/putridparrot/core
  • Now add three files, App.java, HelloWorld.java and HelloWorldImpl.java
  • Paste the following code into HelloWorld.java
    package com.putridparrot.core;
    
    import javax.jws.WebParam;
    import javax.jws.WebService;
    
    @WebService
    public interface HelloWorld {
        String reply(@WebParam(name="text") String text);
    }
    
  • Now let’s paste the following into the HelloWorldImpl
    package com.putridparrot.core;
    
    import javax.jws.WebParam;
    import javax.jws.WebService;
    
    @WebService(endpointInterface = "com.putridparrot.core.HelloWorld", serviceName="HelloWorld")
    public class HelloWorldImpl implements HelloWorld {
        public String reply(@WebParam(name = "text") String text) {
            return "Hello " + text;
        }
    }
    
  • Finally paste the following into App.java
    package com.putridparrot.core;
    
    import javax.xml.ws.Endpoint;
    import java.io.IOException;
    
    public class App {
       public static void main( String[] args ) 
          throws IOException, InterruptedException  {
    
       HelloWorldImpl impl = new HelloWorldImpl();
       String address = "http://localhost:9000/HelloWorld";
       Endpoint.publish(address, impl);
    
       // hold the service open
       System.in.read();
    
       System.exit(0);
    }
    

As you’ve probably noticed, we’re not using Spring to create our webservice (the HelloWorldImpl) and thus there’s no spring configuration or the likes. This really is a bare bones implementation to get us started.

Now if you run this you should be able to use the URL http://localhost:9000/HelloWorld?wsdl to grab the definition meta data. Hence from a C# client you can use wsdl.exe or using Visual Studio’s Add Service reference to generate C# classes to use this service.

Alternate code to start the server

In the above we used Endpoint to create the server, the alternative is to use the JaxWsServerFactoryBean, here’s the code

JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setServiceClass(HelloWorld.class);
factory.setAddress("http://localhost:9000/HelloWorld");
factory.create();

Beanify it

Okay, so we’ve proved the service works at this point, but we really don’t want to hardcode the service like this, so it’s type to turn it into a Spring bean.

First off let’s add to our pom.xml file, you’ll need the following added to the properties element

<spring.version>3.0.5.RELEASE</spring.version>

and then the following dependencies need to be added

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot</artifactId>
      <version>1.5.2.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>1.5.2.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2.2</version>
    </dependency>

and we’re going to use Jetty as the HTTP server, so also add the following dependency

<dependency>
   <groupId>org.apache.cxf</groupId>
   <artifactId>cxf-rt-transports-http-jetty</artifactId>
   <version>${cxf.version}</version>
</dependency>

Obviously you’ll need to run mvn install to get the dependencies updated.

Next we need to create our beans file, within this we’ll actually create a server/endpoint which will be executed. So create a resources folder off of src/main in your project’s folder and add an XML file, mine’s named cxf.xml – within this file we can use one of either of these configurations

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />

    <jaxws:server id="helloWorld"  serviceClass="com.putridparrot.core.HelloWorld" address="http://localhost:9000/HelloWorld">
        <jaxws:serviceBean>
            <bean class="com.putridparrot.core.HelloWorldImpl"/>
        </jaxws:serviceBean>
    </jaxws:server>
</beans>

or using an Endpoint we can use the following

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />

 <jaxws:endpoint id="helloWorld" implementor="com.putridparrot.core.HelloWorldImpl"
                    address="http://localhost:9000/HelloWorld">
        <jaxws:features>
            <bean class="org.apache.cxf.feature.LoggingFeature"/>
        </jaxws:features>
    </jaxws:endpoint>
</beans>

You can change the address to address=”/HelloWorld” if you are using the default port etc. Otherwise to remove this will require looking into overriding Jetty’s port etc. (which is outside the scope of this post).

Finally we need to have the main method wire everything up, so within main we should have the following

new ClassPathXmlApplicationContext("cxf.xml");

// stop the server shutting down
System.in.read();
System.exit(0);