jws

JAX-WS BindingProvider Example

1. Introduction

Java API for XML Web Services ( JAX-WS) is a Java programming language for creating web services, particularly SOAP services.

BindingProvider is an interface which provides access to the protocol binding and associated context objects for request and response message processing.

In this example, I will build a JAX-WS application and demonstrate how to use BindingProvider to set the http header value.

2. JAX-WS Background

JAX-WS 2.0 specification was introduced in 2005 and has become part of JDK since JDK6. JAX-WS 2.0 uses annotations to simplify the development and deployment of web services.

Other tools that implement JAX-WS specification are:

3. Create JAX-WS Server Application

In this example, I will create a JAX-WS server application in three steps:

  • Create an Interface and annotate it with@WebService
  • Create an implementation class for the Interface
    and annotate it with @WebService(endpointInterface="")
  • Create an Endpoint to publish the service

3.1. Create a Web Service Interface with RPC Style

Create MathService in the RPC style.

MathService.java

package jcg.demo.jaxws.service;

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

/**
 * A Simple MathService using the SOAP RPC style which means the message data
 * type must be Primitive types (boolean , byte , char , short , int , long ,
 * float and double)
 * 
 * @author Mary Zheng
 *
 */

@WebService
@SOAPBinding(style = Style.RPC)
public interface MathService {
	@WebMethod
	int sum(@WebParam(name = "int_a") int a, @WebParam(name = "int_b") int b);

	@WebMethod
	boolean isPrimeNumber(@WebParam(name = "number") long number);

}
  • Line 18: @WebService indicates it as a JAX-WS web service
  • Line 19: Style.RPC defines the message type – only primitive types
  • Line 21, 24: @WebMethod marks it as a web operation
  • Line 22, 25: @WebParam defines the parameters

3.2. Create a Web Service Interface with Document Style

Create BookService as Document Style.

BookService.java

package jcg.demo.jaxws.service;

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

import jcg.demo.jaxws.model.Book;

/**
 * A Simple BookService using the SOAP Document style which means the message
 * data can be any user defined POJO data type
 * 
 * @author Mary Zheng
 *
 */

@WebService
@SOAPBinding(style = Style.DOCUMENT)
public interface BookService {
	@WebMethod
	Book getBook(@WebParam(name = "bookId") Integer id);
}
  • Line 19: @WebService indicates the service as JAX-WS web service
  • Line 20: Style.DOCUMENT defines the message type
  • Line 22: @WebMethod marks it as a web operation
  • Line 23: @WebParam defines the parameters

Create Book class.

Book.java

package jcg.demo.jaxws.model;

public class Book {
	private int id;
	private String name;

	public Book() {
		super();
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Book(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
}

3.3. Create Web Service Implementation

Create a BookServiceImpl which authenticates the request based on the username and password from BindingProvider and then invokes getBook service.

BookServiceImpl.java

package jcg.demo.jaxws.service.impl;

import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.ws.WebServiceContext;

import jcg.demo.jaxws.model.Book;
import jcg.demo.jaxws.model.BookUtil;
import jcg.demo.jaxws.service.BookService;

@WebService(endpointInterface = "jcg.demo.jaxws.service.BookService")
public class BookServiceImpl implements BookService {

	@Resource
	private WebServiceContext wsctx;

	@Override
	public Book getBook(Integer id) {

		AuthenticationService authService = new AuthenticationService();
		authService.authentication(wsctx);

		return BookUtil.getBook(id);
	}
}
  • Line 11: Hook the service implementation to the endpoint
  • Line 14: Inject WebServiceContext

Create BookUtil to return Book per bookId.

BookUtil.java

package jcg.demo.jaxws.model;

import java.util.HashMap;
import java.util.Map;

public class BookUtil {
	private static Map map;

	static {
		map = new HashMap();
		map.put(1, new Book(1, "Mary Book"));
		map.put(2, new Book(2, "Terry Book "));
		map.put(3, new Book(3, "Ben Best Book"));
		map.put(4, new Book(4, "Alex Life"));
		map.put(5, new Book(5, "David Music"));
	}

	private BookUtil() {
	}

	public static Book getBook(Integer id) {
		return map.get(id);
	}
}

3.4. Create an AuthenticationService

Create an AuthenticationService which authenticates the request based on the data from BindingProvider.

AuthenticationService.java

package jcg.demo.jaxws.service.impl;

import java.util.Base64;
import java.util.LinkedList;
import java.util.Map;

import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

public class AuthenticationService{
	public void authentication(WebServiceContext wsctx) {
		MessageContext mctx = wsctx.getMessageContext();
		Map http_headers = (Map) mctx.get(MessageContext.HTTP_REQUEST_HEADERS);

		LinkedList list = (LinkedList) http_headers.get("Authorization");
		if (list == null || list.size() == 0) {
			throw new RuntimeException("Authentication failed! This WS needs BASIC Authentication!");
		}

		String userpass = (String) list.get(0);
		userpass = userpass.substring(5);
		validateUserPwd(userpass);
	}

	private void validateUserPwd(String userpass) {
		String credentials = new String(Base64.getMimeDecoder().decode(userpass.getBytes()));

		String username = null;
		String password = null;
		int colonPos = credentials.indexOf(":");
		if (colonPos > -1) {
			username = credentials.substring(0, colonPos);
			password = credentials.substring(colonPos + 1);
			
			if (!(username.equals("mzheng") && password.equals("great"))) {				
				throw new RuntimeException("Not Authentication for " + username + ":" + password);
			}
		} else {
			throw new RuntimeException("There was an error while decoding the Authentication!");
		}
	}
}
  • Line 15: Get the username and password from the context

3.5. Create a Web Service Endpoint and Publish the Service

Create BookApp to publish BookService to http://localhost:9980/bookServer.

BookApp.java

package jcg.demo.jaxws;

import javax.xml.ws.Endpoint;

import jcg.demo.jaxws.service.impl.BookServiceImpl;

public class BookApp {

	public static void main(String[] args) {
		Endpoint ep = Endpoint.create(new BookServiceImpl());
		ep.publish("http://localhost:9980/bookServer");
	}
}

Create MathApp to publish MathService to http://localhost:9990/mathServer.

MathApp.java

package jcg.demo.jaxws;

import javax.xml.ws.Endpoint;

import jcg.demo.jaxws.service.impl.MathServiceImpl;

public class MathApp {

	public static void main(String[] args) {
		Endpoint.publish("http://localhost:9990/mathServer", new MathServiceImpl());
	}
}

3.6. Verify the Web Service

Start both MathApp and BookApp. Open web browser and navigate to http://localhost:9980/bookServer?wsdl and http://localhost:9990/mathServer?wsdl.

We should see the WSDL page loaded. Save both WSDL files.

4. Create a JAX-WS Client Application

There are several ways to generate the JAX-WS client from WSDL file:

In this example, I will use wsimport to generate the java source code from the WSDL via Maven plug in.

4.1. Generate Java Stub via wsimport

Create a Maven project and set up codegen profile with Maven plug in.

pom.xml

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>jax-ws-client</groupId>
	<artifactId>jax-ws-client-wsimport</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<profiles>
		<profile>
			<id>codegen</id>
			<build>
				<plugins>
					<plugin>
						<groupId>org.codehaus.mojo</groupId>
						<artifactId>jaxws-maven-plugin</artifactId>
						<version>1.12</version>
						<executions>
							<execution>
								<id>book_wsdl</id>
								<goals>
									<goal>wsimport</goal>
								</goals>
								<configuration>
									<wsdlUrls>
										<wsdlUrl>http://localhost:9980/bookServer?wsdl</wsdlUrl>
									</wsdlUrls>
									<keep>true</keep>
									<packageName>jcg.demo.jaxws.client.book</packageName>
									<sourceDestDir>src/generated/java</sourceDestDir>
								</configuration>
							</execution>
							<execution>
								<id>math_wsdl</id>
								<goals>
									<goal>wsimport</goal>
								</goals>
								<configuration>
									<wsdlUrls>
										<wsdlUrl>${project.basedir}/wsdls/mathServer.wsdl</wsdlUrl>
									</wsdlUrls>
									<keep>true</keep>
									<packageName>jcg.demo.jaxws.client.math</packageName>
									<sourceDestDir>src/generated/java</sourceDestDir>
								</configuration>
							</execution>
						</executions>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>
</project>
  • Line 37: Set JAX-WS Service WSDL URL location
  • Line 40, 54: Generated code’s package name
  • Line 51: Set JAX-WS Service WSDL File name

Run mvn install -P codegen to generate two client packages.

Image below shows the JAX-WS client with generated codes.

Figure 1: JAX-WS Client

Note: JAXB is used to convert between Java object and XML for Document type message.

4.2. Create a Web Service Client

Create a BookServiceClient.

BookServiceClient.java

package jcg.demo.jaxws.client;

import java.util.Map;

import javax.xml.ws.BindingProvider;

import jcg.demo.jaxws.client.book.BookService;
import jcg.demo.jaxws.client.book.BookServiceImplService;

public class BookServiceClient {

	public static void main(String[] args) {
		BookServiceImplService service = new BookServiceImplService();
		BookService pService = service.getBookServiceImplPort();

		Map requestCtx = ((BindingProvider) pService).getRequestContext();
		requestCtx.put(BindingProvider.USERNAME_PROPERTY, "mzheng");
		requestCtx.put(BindingProvider.PASSWORD_PROPERTY, "great");

		String productionUrl = "http://localhost:9980/bookServer?wsdl";
		requestCtx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, productionUrl);

		for (int i = 1; i < 6; i++) {
			System.out.println(pService.getBook(i).getName());
		}
	}
}
  • Line 17: use BindingProvider.USERNAME_PROPERTY to set the username
  • Line 18: utilize BindingProvider.PASSWORD_PROPERTY to set the password
  • Line 21: use BindingProvider.ENDPOINT_ADDRESS_PROPERTY to set the endpoint address

Create a MathServiceClient.

MathServiceClient.java

package jcg.demo.jaxws.client;

import java.util.Map;

import javax.xml.ws.BindingProvider;

import jcg.demo.jaxws.client.math.MathService;
import jcg.demo.jaxws.client.math.MathServiceImplService;

public class MathServiceClient {

	public static void main(String[] args) {
		MathServiceImplService service = new MathServiceImplService();
		MathService pService = service.getMathServiceImplPort();

		Map requestCtx = ((BindingProvider) pService).getRequestContext();
		requestCtx.put(BindingProvider.USERNAME_PROPERTY, "mzheng");
		requestCtx.put(BindingProvider.PASSWORD_PROPERTY, "great");

		requestCtx.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
		requestCtx.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
		for (int i = 100000; i < 100100; i++) {
			if (pService.isPrimeNumber(i)){
				System.out.println(i + " is prime number. ");
			}
		}
		System.exit(0);
	}
}

5. Demo Time

Start two JAX-WS services: BookApp and MathApp.
Start MathServiceClient to send the request to the server.

MathServiceClient output

100003 is prime number. 
100019 is prime number. 
100043 is prime number. 
100049 is prime number. 
100057 is prime number. 
100069 is prime number.

Start BookServiceClient to send the request to the server.

MathServiceClient output

Mary Book
Terry Book 
Ben Best Book
Alex Life
David Music

6. Summary

In this example, I built a JAX-WS server and client based on JDK implementation and configured the context data via BindingProvider. Apache CXF provides richer implementation of JAX-WS. Use your best judgement to pick the best implementation library when developing a JAX-WS application.

7. Download the Source Code

This example consists of a JAX-WS server and a JAX-WS web service client using BindingProvider to send additional data to the web context.

Download
You can download the full source code of this example here: JAX-WS BindingProvider Example

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Hleb Bandarenka
Hleb Bandarenka
5 years ago

Hi, Mary
Thank you for your post.

I have a couple question
1. You use such code to set username & password on client side
requestCtx.put(BindingProvider.USERNAME_PROPERTY, “mzheng”);
requestCtx.put(BindingProvider.PASSWORD_PROPERTY, “great”);

and on server side you invoke substring() to get part of string and handle it
why did you do it?
String userpass = (String) list.get(0);
userpass = userpass.substring(5);
validateUserPwd(userpass);

2. Do you know what happen when on client side we set SESSION_MAINTAIN_PROPERTY = true ?
what are changing in request or response ?

Back to top button