This is a continuation of the previous entry, where we dealt pimarily with building a pom project for the JAX-WS RI 2.1 EA3 jars so that we can reference in our Web Services maven java project. Personally, I am not really sure about all this WS-* specification now being pimped as a way to deliver on the (drum-roll,please) SOA principle. But, that is what my current activities are focused on, so I need to keep plugging away.
So if you remember from the previous entry we will be working on the contract-last paradigm, where we build the service interface in JAX-WS annotated POJOS, then run it through the apt processor to generate the concrete implementations for the bindings and then deploy it in Tomcat. We will do all this in a Maven 2 project. The requirements for this project are:
- Java 5 (because of annotations)
- Maven 2
- JAX-WS RI (we will be using 2.1-EA3)
- Tomcat 5.5.16 (that is what I have tested in)
Step By Step Approach
1.1 Setting up the Maven project for JAX-WS
First thing we do is create a Maven webapp project (war artifact) and then add the dependency for JAX-WS in the pom.xml as illustrated in the previous Part 1 blog entry. The following should go in the <dependencies> element in the project (pom) file:
<dependency>
<groupId>local.sun.java.net</groupId>
<artifactId>jaxws-ri</artifactId>
<version>2.1-EA3-SNAPSHOT</version>
<type>pom</type>
</dependency>
Now, all the JAX-WS RI jars should be accessible.
1.2 JAX-WS Test Package
At this point we are ready to build the service interface, we will use the addNumbers Interface that comes with the samples bundle in the JAX-WS RI bundle and will use the JSR181 annotations. Remember, this project is just to illustrate how to build a JAX-WS RI project and deploy in tomcat. Here is my AddNumbersImpl.java file in test.testsvc package, please note for this project my service endpoint interface and the implementation class are the same. In general, you should break it up into an interface and implementation class.
package test.websvc;
import javax.jws.WebService;
@WebService
public class AddNumbersImpl{public int addNumbers(int x, int y) {
return x+y;
}
}
All the JSR181 annotation documentation can be found here. The above exports all the public methods as WS operations on our interface, in this case just the addNumbers.
1.3 Setting up the Maven Plugin to generate JAX-WS artifacts
Before you can deploy this in Tomcat, you need to generate the JAX-WS portable artifacts neccessary so that the WSServlet that we will be using (part of JAX-WS bundle) can work. Till we can find a Maven plugin to generate the artifacts we will use the good old antrun plugin to generate the artifacts and automatically inject it into the maven build mechanism. Put the following in your <build> -> <plugins> element:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>apt-task</id>
<phase>generate-sources</phase> (1)
<configuration>
<tasks verbose=”true”><property name=”gen.src.java” value=”target/generated-sources/main/java” /> (2)
<mkdir dir=”${gen.src.java}”/>
<taskdef name=”apt” classname=”com.sun.tools.ws.ant.Apt”>
<classpath refid=”maven.compile.classpath”/>
</taskdef>
<apt
fork=”true”
debug=”false”
verbose=”false”
destdir=”target/classes”
sourcedestdir=”${gen.src.java}”
nocompile=”true”
sourcepath=”src/main/java”>
<classpath>
<path refid=”maven.compile.classpath”/>
<!– this is for the apt task –>
<pathelement location=”${java.home}/../lib/tools.jar”/>
</classpath>
<option key=”r” value=”target”/>
<source dir=”src/main/java”>
<include name=”**/websvcs/**/*.java”/> (3)
</source>
</apt>
</tasks>
<!– add it to maven source root –>
<sourceRoot>${gen.src.java}</sourceRoot> (4)
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.6.5</version>
</dependency>
</dependencies>
</plugin>
Things of note (or change for your porject) are:
(1) Bind the goal to the maven generate-sources phase.
(2) Specify where the generated sources should go relative to the project ${basedir}.
(3) Include all your JSR181 annotated sources.
(4) This ensures that generated sources are added to your compile phase.
Note, here I have decided to fork the apt task so, the classpath element needs to be specified so all the jars
are found.
1.4 Deploy in Tomcat
At this point we are ready to deploy in Tomcat. Since we are going to be using the Servlet from the JAX-WS bundle, we need to ensure that the WAR adheres to the format as documented here. Note, this is a proprietary format. Basically the steps involved are:
- Create the web.xml.
- Create the sun-jaxws.xml.
- Create the archive and deploy in Tomcat.
Here is my web.xml:
<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app version=”2.4″
xmlns=”http://java.sun.com/xml/ns/j2ee”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd”>
<display-name>JAX-WS RI Test Web Application</display-name>
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<description>Add Numbers Service</description>
<display-name>testwebsvc</display-name>
<servlet-name>testwebsvc</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>testwebsvc</servlet-name>
<url-pattern>/addnumbers</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
Nothing special here except the <url-pattern> and <servlet-name> element which you will need in the sun-jaxws.xml file, which for us looks like:
<?xml version=”1.0″ encoding=”UTF-8″?>
<endpoints xmlns=’http://java.sun.com/xml/ns/jax-ws/ri/runtime’ version=’2.0′>
<endpoint
name=”testwebsvc”
implementation=”test.websvc.AddNumbersImpl”
url-pattern=”/addnumbers”/>
</endpoints>
Note the implementation is set to our @WebService annotated class (if you used the Interface/Implementation class pattern, this would be the implementation class).
1.5 Conclusion
Hoepfully this is useful information for people on the bleeding edge, using maven 2 and want to try out the JAX-WS RI implementation from java.net and deploy it in Tomcat. I do need to mention that I tried XFire 1.2.3 too and really like it as you can skip the step of generating the artifacts as it is done at runtime, but I did run into known issues with Spring 2.0,JAXB2 and JAX-WS 2, so I will have to wait till it is fixed.
Elad Kehat said
Thanks again for the great guide. Saved me a lot of time.
I arrived at the JAX-WS solution too after trying XFire and getting into some issues with Spring and JAXB2.
Why do you say though that you’re going to go back to XFire once those issues are fixed? JAX-WS RI seems to work fine, and apparently has better support and many more people working on it than XFire.
Mohan said
The only reason to go with XFire was the easier integration with Spring (which is the app I am currently working on).
But since then, I have managed to integrate it with JAX-WS RI, so I guess I will not pursue it in the near term.
Thanks
narayan said
Hi Mohan,
When i use the maven ant plagin to execute the apt i got the following error, Did you have this problem before?
[INFO] Executing tasks
[apt] command line: apt -d C:\service-WS\targ
et\classes -s C:\service-WS\target\generated-source
s\main\java -sourcepath C:\service-WS\src\main\java
-g -verbose -Ar=target -nocompile -classpath C:\jdk1.5.0_06\lib\tools
.jar
[apt] Usage: apt
[apt] where apt options include:
[apt] -classpath Specify where to find user class files
and annotation processor factories
[apt] -cp Specify where to find user class files
and annotation processor factories
[apt] -d Specify where to place processor and ja
vac generated class files
[apt] -s Specify where to place processor genera
ted source files
[apt] -source Provide source compatibility with speci
fied release
[apt] -version Version information
[apt] -help Print a synopsis of standard options; u
se javac -help for more options
[apt] -X Print a synopsis of nonstandard options
[apt] -J Pass directly to the runtime sys
tem
[apt] -A[key[=value]] Options to pass to annotation processor
s
[apt] -nocompile Do not compile source files to class fi
les
[apt] -print Print out textual representation of spe
cified types
[apt] -factorypath Specify where to find annotation proces
sor factories
[apt] -factory Name of AnnotationProcessorFactory to u
se; bypasses default discovery process
[apt] See javac -help for information on javac options.
[INFO] ————————————————————————
[ERROR] BUILD ERROR
[INFO] ————————————————————————
[INFO] Error executing ant tasks
Embedded error: apt failed
Mohan said
Narayan,
From the output you posted, it appears that your classpath element is not set properly. So the apt processor is not able to find the AnnotationFactory. You must have the
entry within the element (as we are forking it).
Mohan said
Oops, the following got stripped from the
comment above (just in case, it is the classpath element as shown in the article).
Stephen said
Thanks for putting this together. It’s a great help. One problem I ran into was that the sourceRoot value wasn’t getting set, so none of the generated sources were compiled. After I changed the sourceRoot element to this:
${project.build.directory}/generated-sources/main/java
everything worked great.
sphinxmember said
Hi , this is an excellent step by step detailed stuff.
Can you also publish the client generation steps as I am having hard time generating client classes using wsimport
TIA