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:
- Apache CXF
- Apache Axis2
- JBossWS in JBoss
- IBM WebSphere Jax-Ws in WebSphere
- Oracle Weblogic
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
andpassword
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:
- Java IDE, such as Eclipse, NetBeans, etc.
- Apache CXF
- Apache Axis
- JAX-WS
wsimport
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.
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.
You can download the full source code of this example here: JAX-WS BindingProvider Example
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 ?