So far this chapter has focused on the distinction, within JAX-WS, between the application and handler levels.
JAX-WS also provides access, on either the client side or the service side, to the transport level, which is
usually HTTP(S). Such access has been used but not studied in earlier examples. This section focuses on
the transport level with the deliberately minimalist Echo
service and a sample EchoClient
.
Access to the transport level will be
especially useful in the next chapter on security.
The Echo
service (see Example 5-13) relies upon dependency injection through the
@Resource
annotation to get a non-null
reference to the WebServiceContext
(line 1). The
WebServiceContext
, in turn, can be used to access the MessageContext
(line 2), which provides
information about the transport level. To illustrate such access, the echo
method gets the
HTTP request headers as a Map
(line 3) and then prints the map’s contents to the
standard output (line 4).
Example 5-13. The Echo service, which accesses the transport level
package
mctx
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.annotation.Resource
;
import
javax.jws.WebService
;
import
javax.jws.WebMethod
;
import
javax.xml.ws.WebServiceContext
;
import
javax.xml.ws.handler.MessageContext
;
@WebService
public
class
Echo
{
@Resource
WebServiceContext
wctx
;
![]()
@WebMethod
public
String
echo
(
String
in
)
{
String
out
=
"Echoing: "
+
in
;
// Hit the transport level to extract the HTTP headers.
MessageContext
mctx
=
wctx
.
getMessageContext
();
![]()
Map
requestHeaders
=
(
Map
)
mctx
.
get
(
MessageContext
.
HTTP_REQUEST_HEADERS
);
![]()
dump
(
requestHeaders
,
""
);
![]()
return
out
;
}
private
void
dump
(
Map
map
,
String
indent
)
{
Set
keys
=
map
.
keySet
();
for
(
Object
key
:
keys
)
{
System
.
out
.
println
(
indent
+
key
+
" : "
+
map
.
get
(
key
));
if
(
map
.
get
(
key
)
instanceof
Map
)
dump
((
Map
)
map
.
get
(
key
),
indent
+=
" "
);
}
}
}
On a sample run of the EchoClient
, to be studied shortly, the output of
the dump
method was:
Host
:
[
localhost:
7777
]
Content
-
type
:
[
text
/
xml
;
charset
=
utf
-
8
]
Accept
-
encoding
:
[
gzip
]
![]()
Content
-
length
:
[
193
]
Connection
:
[
keep
-
alive
]
Greeting
:
[
Hello
,
world
!]
![]()
User
-
agent
:
[
JAX
-
WS
RI
2.2
.
4
-
b01
]
Soapaction
:
[
"http://mctx/Echo/echoRequest"
]
Accept
:
[
text
/
xml
,
multipart
/
related
]
Most of the lines in the HTTP header are standard (e.g., the blocks with Content-type
and Accept
as their
keys). By contrast, the EchoClient
manually inserts lines 1 and 2 into the HTTP headers. HTTP 1.1 allows
arbitrary header blocks to be added to an HTTP message. In a security context, a username and a supporting
credential could be inserted into an HTTPS header.
The EchoClient
class (see Example 5-14) is a sample client against the Echo
service.
The client, too, accesses the transport level
by casting the port
reference to a BindingProvider
. As the name suggests, a BindingProvider
binds a SOAP message
to a transport message, in this case an HTTP request message.
Example 5-14. The EchoClient
against the EchoService
import
java.util.Map
;
import
java.util.Set
;
import
java.util.List
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
javax.xml.ws.BindingProvider
;
import
javax.xml.ws.handler.MessageContext
;
import
echoClient.EchoService
;
import
echoClient.Echo
;
public
class
EchoClient
{
private
static
final
String
defaultUrl
=
"http://localhost:7777/echo"
;
public
static
void
main
(
String
[
]
args
)
{
Echo
port
=
new
EchoService
().
getEchoPort
();
Map
<
String
,
Object
>
requestContext
=
((
BindingProvider
)
port
).
getRequestContext
();
![]()
/* Sample invocation:
java EchoClient http://localhost:7777/ echo */
String
url
=
(
args
.
length
>=
2
)
?
(
args
[
0
]
+
args
[
1
])
:
defaultUrl
;
requestContext
.
put
(
BindingProvider
.
ENDPOINT_ADDRESS_PROPERTY
,
url
);
![]()
// Add application-specific HTTP header blocks.
Map
<
String
,
Object
>
myHeaders
=
new
HashMap
<
String
,
Object
>();
myHeaders
.
put
(
"Accept-Encoding"
,
Collections
.
singletonList
(
"gzip"
));
![]()
myHeaders
.
put
(
"Greeting"
,
Collections
.
singletonList
(
"Hello, world!"
));
![]()
requestContext
.
put
(
MessageContext
.
HTTP_REQUEST_HEADERS
,
myHeaders
);
![]()
String
response
=
port
.
echo
(
"Have a nice day :)"
);
Map
<
String
,
Object
>
responseContext
=
((
BindingProvider
)
port
).
getResponseContext
();
![]()
dump
(
responseContext
,
""
);
}
private
static
void
dump
(
Map
map
,
String
indent
)
{
Set
keys
=
map
.
keySet
();
for
(
Object
key
:
keys
)
{
System
.
out
.
println
(
indent
+
key
+
" : "
+
map
.
get
(
key
));
if
(
map
.
get
(
key
)
instanceof
Map
)
dump
((
Map
)
map
.
get
(
key
),
indent
+=
" "
);
}
}
}
The BindingProvider
reference is used
to invoke getRequestContext
(line 1), which is a
Map
of the key/value pairs in the HTTP request. As proof of concept, the EchoClient
shows how the
endpoint address of the request can be set at the transport level (line 2). In lines 3 and 4, the class EchoClient
adds two key/value pairs to a Map
and then, in line 5, appends this Map
to the HTTP headers that the underlying
Java libraries produce.
The EchoClient
prints the responseContext
(line 6) to the standard output. On a sample run, the HTTP message from
the Echo service was:
javax
.
xml
.
ws
.
wsdl
.
port
:
{
http:
//mctx/}EchoPort
javax
.
xml
.
ws
.
soap
.
http
.
soapaction
.
uri
:
null
com
.
sun
.
xml
.
internal
.
ws
.
server
.
OneWayOperation
:
true
javax
.
xml
.
ws
.
wsdl
.
service
:
{
http:
//mctx/}EchoService
com
.
sun
.
xml
.
internal
.
ws
.
client
.
handle
:
JAX
-
WS
RI
2.2
.
4
-
b01:
Stub
for
http:
//localhost:7777/echo
javax
.
xml
.
ws
.
reference
.
parameters
:
[]
com
.
sun
.
xml
.
internal
.
ws
.
api
.
server
.
WSEndpoint
:
null
javax
.
xml
.
ws
.
http
.
response
.
code
:
200
javax
.
xml
.
ws
.
wsdl
.
interface
:
{
http:
//mctx/}Echo
javax
.
xml
.
ws
.
wsdl
.
operation
:
{
http:
//mctx/}echo
com
.
sun
.
xml
.
internal
.
ws
.
handler
.
config
:
com
.
sun
.
xml
.
internal
.
ws
.
client
.
HandlerConfiguration
@
6
c3a6465
javax
.
xml
.
ws
.
http
.
response
.
headers
:
{
null
=[
HTTP
/
1.1
200
OK
],
Content
-
type
=[
text
/
xml
;
charset
=
utf
-
8
],
Transfer
-
encoding
=[
chunked
]}
null
:
[
HTTP
/
1.1
200
OK
]
![]()
Content
-
type
:
[
text
/
xml
;
charset
=
utf
-
8
]
![]()
Transfer
-
encoding
:
[
chunked
]
javax
.
xml
.
ws
.
service
.
endpoint
.
address
:
http:
//localhost:7777/echo
![]()
com
.
sun
.
xml
.
internal
.
ws
.
api
.
message
.
HeaderList
:
[]
com
.
sun
.
xml
.
internal
.
ws
.
client
.
ContentNegotiation
:
none
The format here is Java’s own rather than standard HTTP. Nonetheless, the details are readily recognized. Line 1
is the start line in the actual HTTP response, line 3 contains the endpoint address of the Echo
service, and
line 2 is the standard key/value pair for the key Content-type
.
In summary, JAX-WS is more than just an application-level API. There is a powerful handler-level API and even a transport-level API. In the coming chapters, the transport-level API will be put to further use.