javamavenjax-wswsimportwsgen

Creating and using Webservices in same maven project


I'm trying to build a maven project, an OSGi bundle, which contains Webservices. I'm using JAX-WS with all the @WebService annotations to specify the webservices I have. To load these Webservices at a client location you are normally using wsgen and wsimport for exporting/importing WSDL files. I plan to use the jaxws-maven-plugin to do so, but here is the problem:

The bundle can act as a server and client at the same time. It can register itself as a client to a parent node of the same bundle (running on a different JVM/host). So this maven project/bundle defines an interface for the webservice and define an implementation class which implements this interface. Both interface and class use the @WebService annotation as usual.

@WebService
public interface Example {
    public void callMe();
}

@WebService
public class ExampleImpl implements Example {
    public void callMe() {};
}

And then somewhere in my code:

Endpoint p = Endpoint.publish(
                 "http://localhost:8080/example",
                 new ExampleImpl());    

The jaxws:wsgen goal reads the annotations and create the output files (.class files, .java files, WSDL files, depending on the configuration...). But how do I use these files during the jaxws:wsimport goal for the same mvn package run? In the same maven project I want to use this webservice, so I need to write something like this:

ExampleImplService service = new ExampleImplService();
Example port = service.getExampleImplPort();
port.callMe();

The jaxws:gen goal is running in the process-classes phase as it needs to read the compiled classes, but jaxws:import must be run in the generate-sources phase to prepare everything for compiling. And now I run in a chicken-egg problem. I need the compiled classes to generate the output files via wsgen, but I need the output files of wsgen for wsimport in the generate-sources phase of maven. My first try was to assign the jaxws:wsgen goal to the generate-sources phase as well but of course its not working as the classes are missing/not compiled yet.

What are my options to solve this problem? Should I run an antrun goal to compile some classes (namely only the classes with the @WebService annotations) prior the generate-sources phase so jaxws:wsgen can use it (in that phase), create the output files which are then used by jaxws:wsimport in the generate-sources phase? Are there other ways to solve this chicken-egg problem? Are there any other "maven ways" for compiling the server and client part of webservices in the same maven project? It should btw. run from a clean mvn clean build, so I don't want/like any solutions like "run mvn package twice to generate the webservices files first and then to compile everything else". In other words: mvn clean package should compile the whole maven project/osgi bundle.


Solution

  • I have managed to solve this problem by moving the jaxsw:wsgen goal to the generate-sources phase. I use the following steps.

    1. First I compile the classes with @WebService annotations via an antrun execution, which use <javac> to compile the classes. I save the resulting .class files in a temporary directory which is deleted after I have created the client stubs.
    2. I create the WSDL file from the compiled .class files with the jaxws:wsgen goal.
    3. From the temporary directory I create the client stubs with the normal jaxws:wsimport goal.
    4. I delete the temporary directory with a second antrun execution.

    The resulting pom.xml file looks as follow (only the relevant parts)

    <properties>
        <tmpdirectory>${java.io.tmpdir}${file.separator}${user.name}-${project.groupId}-${project.artifactId}</tmpdirectory>
    </properties>
    ...
            <plugin>
                <!-- clean tmp directory at every "mvn clean" -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>${tmpdirectory}</directory>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.6</version>
                <dependencies>
                      <dependency>
                          <groupId>com.sun</groupId>
                          <artifactId>tools</artifactId>
                          <version>1.6.0</version>
                          <scope>system</scope>
                          <systemPath>${java.home}/../lib/tools.jar</systemPath>
                      </dependency>
                </dependencies>  
                <executions>
                    <execution>
                        <!-- compile webservice classes into tmp directory -->
                        <id>mini compile of webservices</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <property name="compile_classpath" refid="maven.compile.classpath"/>
                                <mkdir dir="${tmpdirectory}" />
                                <javac includeAntRuntime="false"
                                       classpath="${compile_classpath}"
                                       destdir="${tmpdirectory}">
                                    <src path="${project.build.sourceDirectory}" />
                                    <include name="org/example/project/*/webservice/*.java" />
                                </javac>
                            </target>
                        </configuration>
                    </execution>
                    <execution>
                        <!-- delete temporary directory (in case mvn clean is not called) -->
                        <id>clean up tmp dir</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <delete dir="${tmpdirectory}" />
                            </target>
                        </configuration>
                    </execution>
                </executions>  
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxws-maven-plugin</artifactId>
                <version>1.10</version>
                <executions>
                    <execution>
                        <!-- generate WSDL file from the compiled classes in tmp directory -->
                        <id>generate wsdl file</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>wsgen</goal>
                        </goals>
                        <configuration>
                            <sei><!-- service endpoint implementation  --></sei>
                            <destDir>${tmpdirectory}</destDir>
                            <genWsdl>true</genWsdl>
                            <resourceDestDir>${tmpdirectory}</resourceDestDir>
                        </configuration>
                    </execution>
                    <execution>
                        <!-- create client stub files -->
                        <id>create client files from wsdl file</id>
                        <goals>
                            <goal>wsimport</goal>
                        </goals>
                        <configuration>
                            <keep>true</keep>
                            <wsdlDirectory>${tmpdirectory}</wsdlDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>