Integrating JAX-WS into Magnolia CMS

Integrating JAX-WS into Magnolia CMS

Got a task today to add support of JAX-WS into our Magnolia based project. Hell. I took me 30 minutes to add support for JAX-RS(Jersey). But it took about four hours to do this for JAX-WS.

The first step is quite trivial we need to create web service itself:

package com.softteco.ws;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService(serviceName="PingService")
public class PingService {
  @WebMethod(operationName="ping")
  public String ping(@WebParam(name="s") String data) {
    return data;
  }
}

The second step is also quite trivial. You’ll need to add one more listener into your web.xml. If you won’t do this – your services won’t do anything.

<listener>
  <listener-class>
    com.sun.xml.ws.transport.http.servlet.WSServletContextListener
  </listener-class>
</listener>

The third step will be putting a file named sun-jaxws.xml into the WEB-INF folder. In my case it looked like:

<?xml version="1.0" encoding="UTF-8"?>
<endpoints version="2.0"
      xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">
  <endpoint implementation="com.softteco.ws.PingService"
      name="PingService" url-pattern="/ws/PingService/*"/>
</endpoints>

And the last step is to create a new node in magnolia tree which will register a new servlet used to parse web service data. It’s a node in Configuration repository named /server/filters/servlets/your_name. This node shoud reference com.sun.xml.ws.transport.http.servlet.WSServlet class.

The only thing you need to do now is to generate definitions for this web services and deploy application. However it was a real pain. We’re using Maven for builds. The first step was quite trivial. Just add the following dependency into your pom.xml.

<dependency>
  <groupId>com.sun.xml.ws</groupId>
  <artifactId>jaxws-tools</artifactId>
  <version>2.2.3</version>
</dependency>

And the funny things started here. We’re using two Maven repos in exactly the following order:
1. http://svn.magnolia.info/maven/m2
2. http://download.java.net/maven/2

It appeared the magnolia repo contains some strange libraries which are downloaded instead of libraries from Java.net and causing compilation issues. So I’ve changed an order and went further.

The next step was to provide automatic generation of the stubs from the EndPoint web service. For this purpose jaxws-maven-plugin was found. It’s quite old and looks like nobody maintains it now. Making it working was impossible without source code. At some point you just get NullPointerException which says nothing to you or ClassNotFoundException for the class located at Java tools.jar. It also refused to see some classes from the project which POM has been edited to add auto-generation support. As a result I’ve got the following plugin configuration:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxws-maven-plugin</artifactId>
  <version>1.12</version>
  <dependencies>
    <dependency>
      <groupId>com.sun.xml.ws</groupId>
      <artifactId>jaxws-tools</artifactId>
      <version>2.2.3</version>
    </dependency>
    <dependency>
      <groupId>com.sun</groupId>
      <artifactId>tools</artifactId>
      <version>1.6</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
    <dependency>
      <groupId>com.softteco</groupId>
      <artifactId>zgenes-magnolia-module</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
  <executions>
    <execution>
    <id>generate-ping-wsdl</id>
    <phase>process-classes</phase>
    <goals>
      <goal>wsgen</goal>
    </goals>
    <configuration>
      <sei>com.softteco.ws.PingService</sei>
      <genWsdl>true</genWsdl>
      <verbose>true</verbose>
    </configuration>
  </execution>
  <execution>
    <id>generate-data-wsdl</id>
    <phase>process-classes</phase>
    <goals>
      <goal>wsgen</goal>
    </goals>
    <configuration>
      <sei>com.softteco.ws.DataService</sei>
      <genWsdl>true</genWsdl>
      <verbose>true</verbose>
    </configuration>
    </execution>
  </executions>
  <configuration>
    <packageName>com.softteco.ws</packageName>
  </configuration>
</plugin>

Please note that you should specify a separate execution for every service.

UPD: Was trying to compile the same stuff on the additional test host but it failed. After struggling with plugin for several hours I’ve decided to rewrite maven plugin with a set of simple commands:
1. Create folder to store WSDL definitions.
2. Create service infrastructure with wsgen.
So now the pom.xml stuff looks like and it works nicely:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
     <id>generate-folder</id>
     <phase>process-classes</phase>
     <goals>
      <goal>run</goal>
     </goals>
     <configuration>
      <tasks>
        <mkdir dir="${basedir}/target/jaxws/wsgen/wsdl" />
      </tasks>
     </configuration>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <version>1.2</version>
  <executions>
    <execution>
     <id>generate-ping-wsdl</id>
     <phase>process-classes</phase>
     <goals>
      <goal>exec</goal>
     </goals>
     <configuration>
      <executable>${java.home}/../bin/wsgen</executable>
      <arguments>
        <argument>-verbose</argument>
        <argument>-d</argument>
        <argument>${project.build.outputDirectory}</argument>
        <argument>-cp</argument>
        <argument>${project.build.outputDirectory}</argument>
        <argument>-wsdl</argument>
        <argument>-r</argument>
        <argument>${basedir}/target/jaxws/wsgen/wsdl</argument>
        <argument>com.softteco.ws.PingService</argument>
      </arguments>
     </configuration>
    </execution>
  </executions>
</plugin>