A Technology Blog About Code Development, Architecture, Operating System, Hardware, Tips and Tutorials for Developers.

Sunday, November 25, 2012

JAX-WS Web Integration (Glassfish Metro)

9:35:00 PM Posted by Satish Kumar , , , , No comments
Here I will demonstrate web integration of web services. I have created document style, RPC style and MTOM web services in the tutorials Web Service using JAX-WS (RPC Style), Web Service using JAX-WS (Document Style) and Web Service using JAX-WS (MTOM) respectively. The code which I will be sharing will have the implementation for all those three web services. But here in this tutorial, I am going to demonstrate the document style web service. I will be using the Glassfish Metro which is one of the implementation of JAX-WS. 

For this tutorial I will be using the following tools

1. JDK 7
2. Eclipse Juno
3. Maven2
4. GlassFish Metro

Most of the time web services are part of web applications, so let's deploy a web service in application server. Along with integration I am going to show you how the RPC and Document style web services are different from each other.

This tutorial shows you how to do the following tasks:

1. Create a SOAP-based Document style web service end point by using JAX-WS.
2. Deployment in Tomcat 7.

Before start coding let's create a java project using the following maven command.

1
mvn archetype:generate -DgroupId=com.techiekernel -DartifactId=webservice-JAX-WS-Web-Metro -Dpackagename=com.techiekernel -DarchetypeArtifactId=maven-archetype-webapp

After you execute, the project will be get created with "pom.xml" file. As I am using JDK 7 and annotations, I have to specify the updated maven plugin. And I have to specify the dependency for GlassFish Metro. So the final pom.xml is shown bellow.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<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.techiekernel</groupId>
 <artifactId>webservice-JAX-WS-Web</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>webservice-JAX-WS-Web Maven Webapp</name>
 <url>http://maven.apache.org</url>
 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-rt</artifactId>
            <version>2.1.5</version>
        </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
   </plugin>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
  </plugins>
  <finalName>webservice-JAX-WS-Web</finalName>
 </build>
</project>

his example I will demonstrate using a Server Object, which will be the return type for one of the web method. So let's create a class called Server, which we will be using to populate the server details and send that back to the client.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.techiekernel.ws.jaxws.document;

public class Server {
 private String name;
 private String ip;
 private String mac;
 private String os;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getIp() {
  return ip;
 }
 public void setIp(String ip) {
  this.ip = ip;
 }
 public String getMac() {
  return mac;
 }
 public void setMac(String mac) {
  this.mac = mac;
 }
 public String getOs() {
  return os;
 }
 public void setOs(String os) {
  this.os = os;
 }
 @Override
 public String toString() {
  return "Server [name=" + name + ", ip=" + ip + ", mac=" + mac + ", os="
    + os + ", toString()=" + super.toString() + "]";
 }
}

Web Service Endpoint Implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.techiekernel.ws.jaxws.document;

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

@WebService
public class FooBarImpl{

 public String callFooBar(String name) {
  // TODO Auto-generated method stub
  return "FooBar called by " + name;
 }

 public Server getServerDetail(String client) {
  // TODO Auto-generated method stub
  Server server = new Server();
  server.setName("Techie Kernel");
  server.setIp("192.168.1.0");
  server.setMac("12-75-61-09-12-22");
  server.setOs("Ubuntu");
  return server;
 }
}

In order to integrate the web service to web application, we have to declare and listener and a front controller in web.xml. So the final "web.xml" will look like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>webservice-JAX-WS-Web</display-name>
  <listener>
  <listener-class>
   com.sun.xml.ws.transport.http.servlet.WSServletContextListener
                </listener-class>
 </listener>
 <servlet>
  <servlet-name>WSFrontController</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>WSFrontController</servlet-name>
  <url-pattern>/*</url-pattern>
 </servlet-mapping>
</web-app>

Once the front controller in place, we have to map the web service url to the end point implementation. That we are going to do in "sun-jaxws.xml" at the same place where web.xml is located i.e. it should be there at the web application class path.

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<endpoints
  xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
  version="2.0">
  <endpoint
      name="FooBarWsDocument"
      implementation="com.techiekernel.ws.jaxws.document.FooBarImpl"
      url-pattern="/foobar"/>
</endpoints>

Now we are set to create our war using maven. But when you try to deploy the war following exception will be thrown. Check here for complete information. 

1
2
SEVERE: WSSERVLET11: failed to parse runtime descriptor: runtime modeler error: Wrapper class com.techiekernel.ws.jaxws.document.jaxws.CallFooBar is not found. Have you run APT to generate them?
com.sun.xml.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class com.techiekernel.ws.jaxws.document.jaxws.CallFooBar is not found. Have you run APT to generate them?

If you remember in my article RPC-style vs Document-Style Web Service, I have said in document style web service there are no overheads of marshalling and de marshalling associated with SOAP engine. So you have to generate the artifact classes for the web services. Once we create the artifact classes and deploy the application, you can notice that for RPC style web services, we don't have to create the artifact classes as SOAP engine will take the responsibility to marshal and unmarshal the request/ response xml. You can use the "wsgen" tool from JDK to generate the artifact classes or you can use the maven plugin to achieve that. I am doing to show both way to generate the artifact classes.

1
wsgen -verbose -keep -cp target/classes/ com.techiekernel.ws.jaxws.document.FooBarImpl -d src/main/java/

After adding the plug in the "pom.xml" will look like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<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.techiekernel</groupId>
 <artifactId>webservice-JAX-WS-Web</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>webservice-JAX-WS-Web Maven Webapp</name>
 <url>http://maven.apache.org</url>
 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-rt</artifactId>
            <version>2.1.5</version>
        </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
   </plugin>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
   <!-- wsgen for web service artifact generation -->
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>1.11</version>
    <executions>
     <execution>
      <id>document</id>
      <goals>
       <goal>wsgen</goal>
      </goals>
      <configuration>
       <sei>com.techiekernel.ws.jaxws.document.FooBarImpl</sei>
       <genWsdl>true</genWsdl>
       <keep>true</keep>
       <verbose>true</verbose>
      </configuration>
     </execution>
     <execution>
      <id>mtom</id>
      <goals>
       <goal>wsgen</goal>
      </goals>
      <configuration>
       <sei>com.techiekernel.ws.jaxws.mtom.FileImageServer</sei>
       <genWsdl>true</genWsdl>
       <keep>true</keep>
       <verbose>true</verbose>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
  <finalName>webservice-JAX-WS-Web</finalName>
 </build>
</project>

After executing the command following class files will be get created.

CallFooBar

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.techiekernel.ws.jaxws.document.jaxws;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "callFooBar", namespace = "http://document.jaxws.ws.techiekernel.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "callFooBar", namespace = "http://document.jaxws.ws.techiekernel.com/")
public class CallFooBar {

    @XmlElement(name = "arg0", namespace = "")
    private String arg0;

    /**
     * 
     * @return
     *     returns String
     */
    public String getArg0() {
        return this.arg0;
    }

    /**
     * 
     * @param arg0
     *     the value for the arg0 property
     */
    public void setArg0(String arg0) {
        this.arg0 = arg0;
    }

}

CallFooBarResponse

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ackage com.techiekernel.ws.jaxws.document.jaxws;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "callFooBarResponse", namespace = "http://document.jaxws.ws.techiekernel.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "callFooBarResponse", namespace = "http://document.jaxws.ws.techiekernel.com/")
public class CallFooBarResponse {

    @XmlElement(name = "return", namespace = "")
    private String _return;

    /**
     * 
     * @return
     *     returns String
     */
    public String getReturn() {
        return this._return;
    }

    /**
     * 
     * @param _return
     *     the value for the _return property
     */
    public void setReturn(String _return) {
        this._return = _return;
    }

}

GetServerDetail

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.techiekernel.ws.jaxws.document.jaxws;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "getServerDetail", namespace = "http://document.jaxws.ws.techiekernel.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getServerDetail", namespace = "http://document.jaxws.ws.techiekernel.com/")
public class GetServerDetail {

    @XmlElement(name = "arg0", namespace = "")
    private String arg0;

    /**
     * 
     * @return
     *     returns String
     */
    public String getArg0() {
        return this.arg0;
    }

    /**
     * 
     * @param arg0
     *     the value for the arg0 property
     */
    public void setArg0(String arg0) {
        this.arg0 = arg0;
    }

}

GetServerDetailResponse

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.techiekernel.ws.jaxws.document.jaxws;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "getServerDetailResponse", namespace = "http://document.jaxws.ws.techiekernel.com/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getServerDetailResponse", namespace = "http://document.jaxws.ws.techiekernel.com/")
public class GetServerDetailResponse {

    @XmlElement(name = "return", namespace = "")
    private com.techiekernel.ws.jaxws.document.Server _return;

    /**
     * 
     * @return
     *     returns Server
     */
    public com.techiekernel.ws.jaxws.document.Server getReturn() {
        return this._return;
    }

    /**
     * 
     * @param _return
     *     the value for the _return property
     */
    public void setReturn(com.techiekernel.ws.jaxws.document.Server _return) {
        this._return = _return;
    }

}

You may encounter the following error while executing the maven. Try changing the plugin version of jaxws-maven-plugin. In my case, it worked from changing it from 1.10 to 1.11. Click here to know more.


1
2
3
4
5
6
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to execute wsgen

Embedded error: com/sun/mirror/apt/AnnotationProcessorFactory
com.sun.mirror.apt.AnnotationProcessorFactory


Any way now you are ready to create a war and depoly the war to the web server.

Code Base:

You can pull the entire source code from GitHub.

0 comments:

Post a Comment