JAX-WS Logging with Handler Example
1. Introduction
In this post, we feature a comprehensive Example on JAX-WS Logging with Handler. Java API for XML Web Services (JAX-WS) is a Java programming language for creating web services, particularly SOAP services. JAX-WS 2.0 specification was introduced in 2005 and has become part of JDK since JDK6. It uses annotations to simplify the development and deployment of web services. It also includes a Handler interface to intercept the request and response SOAP messages. SOAPHandler
objects have access to the soap messages and headers. LogicalHandler
objects are independent of protocol and only have access to the payload of the message.
In this article, I will create a JAX-WS web service which utilizes the SOAPHandler
to log the request and response messages using five steps:
- Create an
Interface
and annotate it with@WebService
,@SOAPBinding
,@WebMethod
, and@WebParam
. - Create a
LogHandler
which implementsSOAPHandler
. - Create a
HandlerChain
XML
file. - Create an implementation class for the service and annotate it with
@HandlerChain
. - Create an
Endpoint
to publish the service.
2. Technologies Used
The example code in this article was built and run using:
- Java 1.8.101
- Maven 3.3.9
- Eclipse Oxygen
- Log4j2 2.8.2
3. Maven Project
In this step, I will create a Maven project to publish a JAX-WS web service.
3.1 Dependencies
I will include the libraries in the pom.xml
.
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-handler</groupId> <artifactId>Jax-ws-handler</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <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> <dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.8.2</version> </dependency> </dependencies> </project>
3.2 Book Model
Create a Book
class which has two members: id
and name
.
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 a Web Service Interface
Create a BookService
interface with JAX-WS annotations: @WebService
, @SOAPBinding
, @WebMethod
, and @WebParam
.
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); }
3.4 Create Log Handler
Create a LogHandler
class to implement SOAPHandler
. It logs the soap messages at both handleMessage
and handleFault
modules using the Logger
from log4j
library.
LogHandler.java
package jcg.demo.jaxws.handler; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class LogHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOG = LogManager.getLogger(LogHandler.class); @Override public boolean handleMessage(SOAPMessageContext context) { LOG.info("***handleMessage***"); logSoapMessage(context); return true; } @Override public boolean handleFault(SOAPMessageContext context) { LOG.info("***handleFault***"); logSoapMessage(context); return false; } @Override public void close(MessageContext context) { LOG.info("_______________close_____________ "); } @Override public Set<QName> getHeaders() { return new HashSet<QName>(); } private void logSoapMessage(SOAPMessageContext context) { Boolean isOutBound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage soapMsg = context.getMessage(); try { if (isOutBound) { LOG.info("Intercepting outbound message:"); } else { LOG.info("Intercepting inbound message:"); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); soapMsg.writeTo(baos); LOG.info(baos); LOG.info("\n________________________________"); } catch (SOAPException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
Create a handlers.xml
file to configure the handler-chains
with the LogHandler
.
handlers.xml
<?xml version="1.0" encoding="UTF-8"?> <handler-chains xmlns="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-name>LoggingHandler</handler-name> <handler-class>jcg.demo.jaxws.handler.LogHandler</handler-class> </handler> </handler-chain> </handler-chains>
3.5 Create a Web Service Implementation
Create a BookServiceImpl
which implements BookService. I will mark it @WebService(endpointInterface = "jcg.demo.jaxws.service.BookService")
to associate it to the service interface. I will add the @HandlerChain
annotation to associate a handler chain defined in the handlers.xml
file.
BookServiceImpl.java
package jcg.demo.jaxws.service; import javax.jws.HandlerChain; import javax.jws.WebService; import jcg.demo.jaxws.model.Book; import jcg.demo.jaxws.util.BookUtil; @WebService(endpointInterface = "jcg.demo.jaxws.service.BookService") @HandlerChain(file = "handlers.xml") public class BookServiceImpl implements BookService { @Override public Book getBook(Integer id) { if( id.intValue() < 0) { throw new IllegalArgumentException("Invalid book Id"); } return BookUtil.getBook(id); } }
Create a book utility class to find the book based on its identifier.
BookUtil.java
package jcg.demo.jaxws.util; import java.util.HashMap; import java.util.Map; import jcg.demo.jaxws.model.Book; public class BookUtil { private static Map<Integer, Book> map; static { map = new HashMap<>(); map.put(1, new Book(1, "Harry Potter")); map.put(2, new Book(2, "The Wonky Donkey ")); map.put(3, new Book(3, "The President Is Missing")); map.put(4, new Book(4, "The Outsider")); map.put(5, new Book(5, "The Woman in the Window")); } private BookUtil() { } public static Book getBook(Integer id) { return map.get(id); } }
3.6 Create a Web Service Endpoint and Publish the Service
Create a BookApp
to publish the BookService
at http://localhost:9980/bookServer
.
BookApp.java
package jcg.demo.jaxws; import javax.xml.ws.Endpoint; import jcg.demo.jaxws.service.BookServiceImpl; public class BookApp { public static void main(String[] args) { Endpoint ep = Endpoint.create(new BookServiceImpl()); ep.publish("http://localhost:9980/bookServer"); System.out.println("Book Service is Started!"); } }
4. Verify the Web Service
Start the BookApp
as a Java application and go to http://localhost:9980/bookServer?wsdl
to confirm that the service has started.
5. Soap UI Demo
Create a new SoapUI project and send requests for both valid and invalid book IDs.
SOAPUI Request.
Request.xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"> <soapenv:Header/> <soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>1</bookId> </ser:getBook> </soapenv:Body> </soapenv:Envelope>
SOAPUI Response.
Response.xml
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <S:Body> <ns2:getBookResponse xmlns:ns2="http://service.jaxws.demo.jcg/"> <return> <id>1</id> <name>Harry Potter</name> </return> </ns2:getBookResponse> </S:Body> </S:Envelope>
6. Server Log
I configured log4j2.xml
to capture the logging information. You can see the log file includes successful and unsuccessful requests and responses.
Server.log
INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:30) - Intercepting inbound message: INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:28) - Intercepting outbound message: INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://service.jaxws.demo.jcg/"><return><id>1</id><name>Harry Potter</name></return></ns2:getBookResponse></S:Body></S:Envelope> INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 08:59:49 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:55) - ***close*** INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:30) - Intercepting inbound message: INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>0</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:28) - Intercepting outbound message: INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://service.jaxws.demo.jcg/"/></S:Body></S:Envelope> INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:00:07 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:55) - ***close*** INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:30) - Intercepting inbound message: INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>-1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:28) - Intercepting outbound message: INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://service.jaxws.demo.jcg/"/></S:Body></S:Envelope> INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:00:16 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:55) - ***close*** INFO | 2018-09-27 09:03:28 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:30) - Intercepting inbound message: INFO | 2018-09-27 09:03:28 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>-1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:03:28 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:03:28 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:49) - ***handleFault*** INFO | 2018-09-27 09:03:28 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:55) - ***close*** INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:30) - Intercepting inbound message: INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:28) - Intercepting outbound message: INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:35) - <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://service.jaxws.demo.jcg/"><return><id>1</id><name>Harry Potter</name></return></ns2:getBookResponse></S:Body></S:Envelope> INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ________________________________ INFO | 2018-09-27 09:04:14 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:55) - ***close*** INFO | 2018-09-27 09:06:13 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:23) - ***handleMessage*** INFO | 2018-09-27 09:06:19 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:31) - Intercepting inbound message: INFO | 2018-09-27 09:06:19 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:36) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>-1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:06:19 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:38) - ________________________________ INFO | 2018-09-27 09:06:19 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:50) - ***handleFault*** INFO | 2018-09-27 09:07:42 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:56) - ***close*** INFO | 2018-09-27 09:10:11 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:23) - ***handleMessage*** INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:53) - Intercepting inbound message: INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:58) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>-1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:60) - ________________________________ INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:30) - ***handleFault*** INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:51) - Intercepting outbound message: INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:58) - <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><S:Fault xmlns:ns3="http://www.w3.org/2003/05/soap-envelope"><faultcode>S:Server</faultcode><faultstring>Invalid book Id</faultstring></S:Fault></S:Body></S:Envelope> INFO | 2018-09-27 09:10:15 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:60) - ________________________________ INFO | 2018-09-27 09:10:24 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ***close*** INFO | 2018-09-27 09:10:31 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:23) - ***handleMessage*** INFO | 2018-09-27 09:10:33 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:53) - Intercepting inbound message: INFO | 2018-09-27 09:10:33 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:58) - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.jaxws.demo.jcg/"><soapenv:Header/><soapenv:Body> <ser:getBook> <!--Optional:--> <bookId>1</bookId> </ser:getBook> </soapenv:Body></soapenv:Envelope> INFO | 2018-09-27 09:10:33 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:60) - ________________________________ INFO | 2018-09-27 09:10:33 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:23) - ***handleMessage*** INFO | 2018-09-27 09:10:34 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:51) - Intercepting outbound message: INFO | 2018-09-27 09:10:34 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:58) - <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://service.jaxws.demo.jcg/"><return><id>1</id><name>Harry Potter</name></return></ns2:getBookResponse></S:Body></S:Envelope> INFO | 2018-09-27 09:10:34 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:60) - ________________________________ INFO | 2018-09-27 09:10:34 | [pool-2-thread-1] handler.LogHandler (LogHandler.java:37) - ***close***
7. JAX-WS Logging with Handler – Summary
In this article, I built a JAX-WS web service based on JDK implementations and configured it with a SOAPHandler
to log the request and response messages.
8. Download the Source Code
This tutorial consists of a Maven project. I demonstrated how to create a JAX-WS web service and hook it with SOAPHandler
to log the request and response messages.
You can download the full source code of this example here: JAX-WS Logging with Handler Example
i am trying to log not well formed soap request which is directly invoking the handlefault method and it is logging the fault response but not the incoming soap request could you please
You sir, gave me the solution for the problem i was having. I tried a lot of solutions, but your was the only one that work. Thanks!!!
Eclipse was complaining (but still working) about handlers.xml file.
To fix it, I have changed the Line 2 to:
<handler-chains xmlns=”http://java.sun.com/xml/ns/javaee”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/javaee_web_services_metadata_handler_2_0.xsd“>