Table of Contents
Client can set additional HTTP headers for making a requests
by using MessageContext.HTTP_REQUEST_HEADERS
. See the
following code for an example:
Example 5.1. Sending HTTP headers
import java.util.Collections; import javax.xml.ws.BindingProvider; import javax.xml.ws.handler.MessageContext; HelloPort port =...; ((BindingProvider) port).getRequestContext().put(MessageContext .HTTP_REQUEST_HEADERS, Collections.singletonMap ("X-Client-Version", Collections.singletonList("1.0-RC"))); // the header will be sent to all successive invocations port.sayHelloTo("duke"); port.sayHelloTo("duke");
Note that the property takes
Map<String,List<String>>
as the
type.
Clients can access the HTTP headers of the response by using
MessageContext.HTTP_RESPONSE_HEADERS
. See the
following code for example:
Example 5.2. Accessing HTTP headers
HelloPort port = ...; port.sayHelloTo("duke"); headers = (Map<String, List<String>>) ((BindingProvider) port) .getResponseContext().get(MessageContext.HTTP_RESPONSE_HEADERS);
HTTP supports compression of data at the transport level, which can substantially reduce the size of the data (at the expense of an additional CPU load.)
When sending a request to a server, a client can inform the server that it can receive compressed response like this:
Example 5.3. Request HTTP Compression
Map<String, List<String> httpHeaders = new HashMap<String, List<String>>(); httpHeaders.put("Accept-Encoding", Collections.singletonList("gzip")); Map<String, Object> reqContext = ((bindingProvider)proxy).getRequestContext(); requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpHeaders);
This works even if the server isn't capable of doing compression; it will simply respond with uncompressed response and it will work transparently.
If a client knows that the server is capable of receiving a compressed request, it can send a compressed request by adding one more HTTP header as follows:
Example 5.4. Sending Compressed Request
Map<String, List<String> httpHeaders = new HashMap<String, List<String>>(); httpHeaders.put("Content-Encoding", Collections.singletonList("gzip")); httpHeaders.put("Accept-Encoding", Collections.singletonList("gzip")); Map<String, Object> reqContext = ((bindingProvider) proxy) .getRequestContext(); requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpHeaders);
Note that this will fail if the server is incapable of dealing with compressed HTTP traffic. Most modern HTTP servers understand it, but this is not guaranteed.
To enable cookie support, you need to enable the session
property. This causes requests sent via the port to use the same
cookie jar, so if the server responds with a cookie, the next
request will go out with those cookies. This allows the server to
use the normal session tracking mechanism like
HttpSession
.
Example 5.5. Sending HTTP headers
HelloPort port = ...; port.getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
When the web service is using servlets as the transport
mechanism, you can use servlet's
native support for cookies. See the following code to how
to access javax.servlet.http.HttpServletRequest
from
your service.
Example 5.6. Accessing cookies
class MyService { @Resource WebServiceContext context; public void foo() { HttpServletRequest rq = (HttpServletRequest) context .getMessageContext().get(MessageContext.SERVLET_REQUEST); HttpServletResponse rs = (HttpServletResponse) context .getMessageContext().get(MessageContext.SERVLET_RESPONSE); } }
JAX-WS uses Java SE's HttpURLConnection to send requests to web service. By default, HttpURLConnection buffers the entire request before sending it on the wire. To enable HTTP streaming support, one needs to enable setChunkedStreamingMode() on the connection. The same thing can be achieved by doing the following in JAX-WS clients.
Example 5.7. HTTP client streaming support
int chunkSize = ...; Map<String, Object> ctxt = ((BindingProvider)proxy).getRequestContext(); ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, chunkSize);
HTTP headers can be accessed in a Handler. Here is how you can access the Content-Type HTTP header in a Handler:
HTTP headers can be accessed in a client side Handler in an incoming response. Here is Handler code that demonstrates how to do this:
Example 5.8. ClientHandler.java
public class ClientHandler implements SOAPHandler<SOAPMessageContext> { public boolean handleMessage(SOAPMessageContext context) { if (!(Boolean) context.get(MessageContext .MESSAGE_OUTBOUND_PROPERTY)) { Map<String, List<String>> map = (Map<String, List<String>>) context.get(MessageContext .HTTP_RESPONSE_HEADERS); List<String> contentType = getHTTPHeader(map, "Content-Type"); if (contentType != null) { StringBuffer strBuf = new StringBuffer(); for (String type : contentType) { strBuf.append(type); } System.out.println("Content-Type:" + strBuf.toString()); } } return true; } private @Nullable List<String> getHTTPHeader(Map<String, List<String>> headers, String header) { for (Map.Entry<String, List<String>> entry : headers.entrySet()) { String name = entry.getKey(); if (name.equalsIgnoreCase(header)) return entry.getValue(); } return null; } }
HTTP headers can be accessed in a server side Handler on an incoming request. Here is Handler code that demonstrates how to do this:
Example 5.9. ServerHandler.java
public class ServerHandler implements SOAPHandler<SOAPMessageContext> { public boolean handleMessage(SOAPMessageContext context) { if (!(Boolean) context.get(MessageContext .MESSAGE_OUTBOUND_PROPERTY)) { Map<String, List<String>> map = (Map<String, List<String>>) context.get(MessageContext .HTTP_REQUEST_HEADERS); List<String> contentType = getHTTPHeader(map, "Content-Type"); if (contentType != null) { StringBuffer strBuf = new StringBuffer(); for (String type : contentType) { strBuf.append(type); } System.out.println("Content-Type:" + strBuf.toString()); } } return true; } private @Nullable List<String> getHTTPHeader(@NotNull Map<String, List<String>> headers, @NotNull String header) { for (Map.Entry<String, List<String>> entry : headers.entrySet()) { String name = entry.getKey(); if (name.equalsIgnoreCase(header)) return entry.getValue(); } return null; } }
JAX-WS uses Java SE's HttpURLConnection to send requests to web services. URLConnection offers setConnectTimeout() and setReadTimeout() methods so that clients can control connection timeouts. The same things can be achieved by doing the following in JAX-WS clients:
Example 5.10. HTTP client timeouts
// setConnectTimeout() int timeout = ...; Map<String, Object> ctxt = ((BindingProvider)proxy).getRequestContext(); ctxt.put(JAXWSProperties.CONNECT_TIMEOUT, timeout); // setReadTimeout() int timeout = ...; Map<String, Object> ctxt = ((BindingProvider)proxy).getRequestContext(); ctxt.put("com.sun.xml.ws.request.timeout", timeout);
Persistent connections improve performance by allowing the underlying socket connection to be reused for multiple http requests. JAX-WS uses Java SE's HttpURLConnection to send requests to web services. HTTP keep-alive behavior can be controlled by the http.keepAlive (default: true) and http.maxConnections (default: 5) system properties. For more information, see Networking Properties
JAX-WS uses Java SE's HttpsURLConnection to send requests to web services that use the HTTPS transport. HttpsURLConnection offers a setHostnameVerifier() method so that the client's verification callback can be called to determine whether a connection is allowed. The same thing can be achieved by doing the following in JAX-WS clients:
Example 5.11. SSL Hostname Verification
HostNameVerifier hostNameVerifier = ...; int timeout = ...; Map<String, Object> ctxt = ((BindingProvider)proxy).getRequestContext(); ctxt.put(JAXWSProperties.HOSTNAME_VERIFIER, hostNameVerifier);
JAX-WS uses Java SE's HttpsURLConnection to send requests to web services that use HTTPS transport. HttpsURLConnection offers setSSLSocketFactory() method and that factory is used when creating sockets for secure https URL connections. The same thing can be achieved by doing the following in JAX-WS clients:
Example 5.12. HTTPS SSLSocketFactory
SSLSocketFactory sslSocketFactory = ...; Map<String, Object> ctxt = ((BindingProvider)proxy).getRequestContext(); ctxt.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslSocketFactory);
A service may be hosted in a servlet container that is behind firewall/load balancer. Then a published WSDL's soap:address, wsdl:import, xsd:import locations may point to the internal address(not to the external firewall/loadbalancer address). Metro uses the HttpServletRequest's getServerName() and getServerPort() to figure out the server's address and port respectively. This works in many cases, but you may need to configure the servlet container's server address in some cases.
This is supported in GlassFish, by configuring "server-name" attribute of <http-listener> in domain.xml. For example, set it to "http://firewall-host:firewall-port"
This is supported in Tomcat, by using the "proxyName" and "proxyPort" attributes on <Connector>. See tomcat configuration