2.5.1. Dynamic tube-based message logging
As you may know, Metro creates a tubeline for each WS
endpoint and endoint client to process SOAP messages flowing from
and to the endpoint and or its client. Each tubeline consist of a
set of tube instances chained together. A tube is a basic SOAP
message processing unit. Standard Metro tubes are used to
implement processing logic for different SOAP processing aspects
(validation, Java-XML mapping etc.) and higher-level QoS domains
(security, reliable messaging etc.) As an experimental feature,
custom tubes are supported as well.
When developing an advanced web service that requires
Quality of Service features or adding a custom tube into the
default Metro tubeline, the ability to see the SOAP message
content at different processing stages as the message flows
through the tubeline may be very useful. As Metro tubeline get's
dynamically created for each endpoint or client, Metro (since
version 2.0) provides a new message logging facility that copes
with the dynamics of a tubeline creation by defining a set of
templating rules that provide a generic way for constructing
system-level properties able to control message content logging
before and/or after each tube's processing.
To turn on the logging for any particular tube (or a set of
tubes) created by a specific tube factory, the developer needs to
set one or more of the following system properties, depending on
the target scope:
<tube_factory_class_name>.dump
- expects boolean string, if set to true
turns on the logging before and after tube's
processing
<tube_factory_class_name>.dump.before
- expects boolean string, if set to true
turns on the logging before tube's processing
<tube_factory_class_name>.dump.after
- expects boolean string, if set to true
turns on the logging after tube's processing
<tube_factory_class_name>.dump.level
- expects string representing
java.util.logging.Level
, if set,
overrides the default message dumping level for the
class, which is
java.util.logging.Level.INFO
There is a set of common system properties that control
logging for all tubes and take the lowest precedence so that they
can be overriden by a tube-specific properties:
com.sun.metro.soap.dump
- expects a
boolean string, if set to true
turns on
the message dumping before and after each tube's
processing on both sides client and endpoint
com.sun.metro.soap.dump.before/after
- expects a boolean string, if set to
true
turns on the message dumping
before/after each tube's processing on both sides
client and endpoint.
com.sun.metro.soap.dump.client/endpoint
- expects a boolean string, if set to
true
turns on the message dumping before
and after each tube's processing on the respective
side (client or endpoint).
com.sun.metro.soap.dump.client/endpoint.before/after
- expects a boolean string, if set to
true
turns on the message dumping
before/after each tube's processing on the respective
side (client or endpoint).
com.sun.metro.soap.dump.level
and
com.sun.metro.soap.dump.client/endpoint.level
- controls the logging level for the whole
tubeline
The logger root used for message dumping is
<tube_factory_class_name>
.
Most of the factories create tubes on both client and
endpoint side. To narrow down the message dumping scope, following
system properties can be used:
<tube_factory_class_name>.dump.client/endpoint
- expects boolean string, if set to true
turns on the logging before and after tube's
processing
<tube_factory_class_name>.dump.client/endpoint.before
- expects boolean string, if set to true
turns on the logging before tube's processing
<tube_factory_class_name>.dump.client/endpoint.after
- expects boolean string, if set to true
turns on the logging after tube's processing
<tube_factory_class_name>.dump.client/endpoint.level
- expects string representing
java.util.logging.Level
, if set,
overrides anything set by
<tube_factory_class_name>.level
and
or the default message dumping level for the class,
which is
java.util.logging.Level.INFO
In the following examples we will be working with the
metro-default.xml
file that defines the default
Metro tubeline and looks like this:
Example 2.19.
<metro xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://java.sun.com/xml/ns/metro/config'
version="1.0">
<tubelines default="#default-metro-tubeline">
<tubeline name="default-metro-tubeline">
<client-side>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.TerminalTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.HandlerTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.ValidationTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.MustUnderstandTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.MonitoringTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.AddressingTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.tx.runtime.TxTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.rx.rm.runtime.RmTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.rx.mc.runtime.McTubeFactory"/>
<tube-factory
className="com.sun.xml.wss.provider.wsit.SecurityTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.dump.ActionDumpTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.rx.testing.PacketFilteringTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.dump.MessageDumpingTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.TransportTubeFactory"/>
</client-side>
<endpoint-side>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.TransportTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.dump.MessageDumpingTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.rx.testing.PacketFilteringTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.dump.ActionDumpTubeFactory"/>
<tube-factory
className="com.sun.xml.wss.provider.wsit.SecurityTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.rx.mc.runtime.McTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.AddressingTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.rx.rm.runtime.RmTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.tx.runtime.TxTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.MonitoringTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.MustUnderstandTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.HandlerTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.ValidationTubeFactory"/>
<tube-factory
className="com.sun.xml.ws.assembler.jaxws.TerminalTubeFactory"/>
</endpoint-side>
</tubeline>
</tubelines>
</metro>
Example 1
To turn on the the message dumping before and after
security tube's processing on both, client and endpoint side,
following system property needs to be set to true:
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump=true
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump=true
Example 2
To turn on the the message dumping only after security
tube's processing on both, client and server side, following
system property needs to be set to true:
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump.after=true
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump.after=true
Example 3
To turn on the the message dumping only after security
tube's processing only on the client side, following system
property needs to be set to true:
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump.client.after=true
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump.client.after=true
Example 4
This example sets message dumping before and after
security processing, except for before security processing on
the endpoint side. The logging level for message dumps is set
to FINE
on both sides:
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump=true
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump.endpoint.before=false
com.sun.xml.wss.provider.wsit.SecurityTubeFactory.dump.level=FINE
2.5.2. Dumping SOAP messages on client
2.5.2.1. Transport level dump
One of the things people want to do while developing Web
Services is to look at what the client is sending and
receiving. To monitor soap traffic, there are some GUI tools
like TCP
Monitor and WSMonitor.
These monitors are implemented with a 'man in the middle'
approach where-in, the monitor listens to a port (Client send
requests to this port) and forwards it to another port (Server
listens to this port). Since these tools use port forwarding,
you need to change your Web Service client to send request to
the port where the monitor listens (Especially, if you are
using static clients generated by wsimport, the default
endpoint address taken from the wsdl needs to be overidden by
setting ENDPOINT_ADDRESS_PROPERTY
on the
proxy).
In Eclipse implementation of Jakarta XML Web Services,
you can monitor the request and response
messages without changing the client. When you invoke the Web
Service, just pass the system property com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true,
it prints out the request and response message.
If you are using an Apache Ant script to run your
client, this system property can be set as a
<jvmarg/>
element:
Example 2.20. Setting system properties via Ant
<project name="metro client" basedir=".">
<property environment="env"/>
<property name="build.dir" location="$${basedir}/build"/>
<property name="build.classes.dir" location="$${build.dir}/classes"/>
<target name="run">
<java classname="client.MyClient" fork="yes">
<arg value="xxx"/>
<!-- optional args[0] sent to MyClient.main() -->
<arg value="xxx"/>
<!-- optional args[1], etc. -->
<classpath>
<pathelement location="$${build.classes.dir}"/>
<pathelement location="$${env.AS_HOME}/lib/javaee.jar"/>
<pathelement location="$${env.AS_HOME}/lib/webservices-rt.jar"/>
<pathelement location="$${env.AS_HOME}/lib/activation.jar"/>
</classpath>
<jvmarg value="-Dcom
.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true"/>
</java>
</target>
</project>
Alternatively you can execute
com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true;
from your Java program to programatically enable/disable
logging. Since you often run XML Web Services in a container where
setting system properties can be tedious, you might find this
easier.
With this switch enabled, you'll see message dumps like
the following in System.out
.
Example 2.21. Sample dump
---[HTTP request]---
SOAPAction:
Content-Type: text/xml
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><addNumbers xmlns="http://duke.example.org"><arg0>10</arg0><arg1>20</arg1></addNumbers></S:Body></S:Envelope>--------------------
---[HTTP response 200]---
Date: Thu, 17 Aug 2006 00:35:42 GMT
Content-type: text/xml
Transfer-encoding: chunked
Server: Apache-Coyote/1.1
null: HTTP/1.1 200 OK
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><addNumbersResponse xmlns="http://duke.example.org"><return>30</return></addNumbersResponse></S:Body></S:Envelope>--------------------
A similar property com.sun.xml.ws.transport.local.LocalTransportPipe.dump=true
is available for the local transport.
2.5.2.2. Transport-agnostic dump
The dump mechanism explained above allows you to get the
actual bytes that are sent over the wire, as well as any
transport specific information (such as HTTP headers), but the
mechanism is different from transports to transports. Eclipse
implementation of Jakarta XML Web Services
also defines a transport-agnostic dump, which works regardless
of what transport you use.
This dump happens after Eclipse implementation of Jakarta
XML Web Services parses the incoming
message into XML infoset. So you will not be able to
investigate a well-formedness error with this dump.
To enable such dump, set the system property com.sun.xml.ws.util.pipe.StandaloneTubeAssembler.dump=true
or execute that as a Java program.
2.5.3. Dumping SOAP messages on server
You can dump incoming HTTP requests and responses to
System.out
on the server side by using the system
property com.sun.xml.ws.transport.http.HttpAdapter.dump=true.
This works exactly like above (except that this works on server,
not client.) You can also set this property programatically by
executing com.sun.xml.ws.transport.http.HttpAdapter.dump=true;
as Java progrma.
The transport agnostic dump as explained above also works on
the server for incoming messages and responses.