Posts Tagged ‘Web Service

07
Nov
12

JAX-WS Hello World Standalone / Tomcat / JBoss

The following page describes how to create a simple JAX-WS web service and run it under JBoss and Tomcat and as a standalone App.

Background

JAX-WS supports both traditional SOAP-RPC as well as the newer RESTful/JSON type services. Its a plug and play framework where the developer annotate their classes and the application server takes care of the rest.

Requirements

  1. Java 6 or above
  2. Tomcat 6 or JBoss 5
  3. Maven 3

Interface

vi src/main/java/server/HelloWorld.java

package server;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.RPC)
public interface HelloWorld {
@WebMethod String getHelloWorldAsString(String name);
}

Implementation

vi src/main/java/server/HelloWorldImpl.java

package server;

import javax.jws.WebService;
import javax.xml.ws.Endpoint;

@WebService(endpointInterface = "server.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
	@Override
	public String getHelloWorldAsString(String name) {
		return "Hello World JAX-WS " + name;
	}
	public static void main(String args[]) { // for test purposes only
		Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());		
	}	
}

Client Application

If you would like to test without generating the client application you can do the following.

vi HelloWorldApp.java

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import server.HelloWorld;

public class HelloWorldApp {
	
	public static void main(String args[]) throws Exception {
		URL url = new URL("http://localhost:9999/ws/hello?wsdl");
		QName qname = new QName("http://server/", "HelloWorldImplService");	
		Service service = Service.create(url, qname);
                addDebugSupport(service); // optional (see method below)
		HelloWorld hello = service.getPort(HelloWorld.class);
		System.out.println(hello.getHelloWorldAsString("name"));
	}
}

The following method allows for the incoming and outgoing SOAP messages to be logged. It requires HTMLTidy dependency

    <dependency>
        <groupId>jtidy</groupId>
        <artifactId>jtidy</artifactId>
        <version>4aug2000r7-dev</version>
    </dependency>
<!--try the new version of jtidy
    <dependency>
        <groupId>net.sf.jtidy</groupId>
        <artifactId>jtidy</artifactId>
        <version>r938</version>
    </dependency>
-->
private static void addDebugSupport(Service service) {
	service.setHandlerResolver(new HandlerResolver() {
		public List<Handler> getHandlerChain(PortInfo portInfo) {
			List<Handler> handlerChain = new ArrayList<Handler>();
			handlerChain.add(new SOAPHandler<SOAPMessageContext>() {
				public boolean handleFault(SOAPMessageContext context) {
					log(context);
					return true;
				}
				public boolean handleMessage(SOAPMessageContext context) {
					log(context);
					return true;
				}
				public void close(MessageContext context) {}
				public Set<QName> getHeaders() {return null;}
			});
			return handlerChain;
		}
		private void log(SOAPMessageContext smc) {
			Boolean outboundProperty = (Boolean) smc
					.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
			if(outboundProperty.booleanValue()) {
				logger.info("Outbound message:");					
			} else {
				logger.info("Inbound message:");
			}
			SOAPMessage message = smc.getMessage();
			try {
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				message.writeTo(baos);
				ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
				Tidy tidy = new Tidy();
				tidy.setXmlOut(true);
				tidy.setXmlTags(true);
				baos = new ByteArrayOutputStream();
				tidy.parse(bais, baos);
				logger.info("\n" + new String(baos.toByteArray()));
			} catch (Exception e) {
				logger.error("Exception in handler: " + e);
			}
		}
    });
}

Package and Deploy the JAX-WS Web Service

Create a sun-jaxws.xml file if you are planning to use the Reference Implementation. Otherwise skip it.

src/main/webapp/WEB-INF/sun-jaxws.xml

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

The following is the way the web.xml file should look if you are using the Reference Implementation. Otherwise just skip to the JBoss section.

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, 
Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
 
<web-app>
    <listener>
        <listener-class>
                com.sun.xml.ws.transport.http.servlet.WSServletContextListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>hello</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>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>120</session-timeout>
    </session-config>
</web-app>

Run under Tomcat

Tomcat 6 does not include the JAX-WS RI jars, instead download them from oracle and place them in the tomcat6/lib directory of your server or your WEB-INF/lib folder or the WAR file.

The following is a sample list: your version of JAX-WS can vary.

jaxb-impl.jar
jaxws-api.jar
jaxws-rt.jar
gmbal-api-only.jar
management-api.jar
stax-ex.jar
streambuffer.jar
policy.jar

Run under JBoss 5

JBoss comes pre-installed with a JAX-WS implementation. No need to package the JAX-WS implementation in the war. Instead just put the following in the web.xml file and navigate to the following URL:

http://127.0.0.1:8080/jaxwsTest/hello?wsdl

 <servlet>
  <servlet-name>HelloService</servlet-name>
  <servlet-class>server.HelloWorldImpl</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>HelloService</servlet-name>
  <url-pattern>/hello</url-pattern>
 </servlet-mapping>

JAX-WS Web Service Client

To create a standalone client application use wsimport command provided by the JDK 6.

Appendix: MockServer

The following is an implementation of a mock server that could be used for testing.

package service;

import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.ws.Endpoint;

public class MockServer {

	private static final MockServer instance = new MockServer();
	
	private Map<QName, String> urlMap = new HashMap<QName, String>();
	
	private MockServer() {
		super();
		publish("DataManagerImplService", "http://service/", getAvailablePort(), new DataManagerImpl());
	}

	private void publish(String serviceName, String uri, int port, Object implObject) {
		String url = "http://localhost:" + port + "/ws/" + serviceName + "?wsdl";
		QName qname = new QName(uri, serviceName);
		Endpoint.publish(url, implObject);
		urlMap.put(qname, url);
	}
	
	public static MockServer getInstance() {
		return instance;
	}

	public URL getUrl(QName qname) {
		URL url = null;
		try {
			url = new URL(urlMap.get(qname));
		} catch (MalformedURLException e) {
		}
		return url;
	}
	
	private static int getAvailablePort() {
		int count = 0;
		int port = 0;
		while (true) {
			try {
				ServerSocket s = new ServerSocket(0);
				port = s.getLocalPort();
				s.close();				
				break;			
			} catch (Exception ex) {
				if (count++ > 3) throw new RuntimeException(ex.getMessage());
			}
		}
		return port;
	}
	
}



Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 78 other followers

July 2017
S M T W T F S
« Mar    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Blog Stats

  • 822,600 hits