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.
I have managed to solve this problem by moving the jaxsw:wsgen
goal to the generate-sources
phase. I use the following steps.
@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.jaxws:wsgen
goal.jaxws:wsimport
goal.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>