blob: 489a75c8341cd889c1f238032a969e9c2419b146 [file] [log] [blame]
/*
* Portions Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.xml.internal.ws.protocol.xml.client;
import com.sun.xml.internal.messaging.saaj.packaging.mime.MessagingException;
import com.sun.xml.internal.ws.binding.BindingImpl;
import com.sun.xml.internal.ws.client.*;
import static com.sun.xml.internal.ws.client.BindingProviderProperties.*;
import com.sun.xml.internal.ws.client.dispatch.DispatchContext;
import com.sun.xml.internal.ws.client.dispatch.ResponseImpl;
import com.sun.xml.internal.ws.encoding.soap.SOAPEncoder;
import com.sun.xml.internal.ws.encoding.soap.client.SOAP12XMLEncoder;
import com.sun.xml.internal.ws.encoding.soap.client.SOAPXMLEncoder;
import com.sun.xml.internal.ws.encoding.soap.internal.MessageInfoBase;
import com.sun.xml.internal.ws.encoding.xml.XMLEncoder;
import com.sun.xml.internal.ws.encoding.xml.XMLMessage;
import com.sun.xml.internal.ws.handler.HandlerChainCaller;
import com.sun.xml.internal.ws.handler.HandlerChainCaller.Direction;
import com.sun.xml.internal.ws.handler.HandlerChainCaller.RequestOrResponse;
import com.sun.xml.internal.ws.handler.MessageContextUtil;
import com.sun.xml.internal.ws.handler.XMLHandlerContext;
import com.sun.xml.internal.ws.handler.HandlerContext;
import com.sun.xml.internal.ws.model.JavaMethod;
import com.sun.xml.internal.ws.pept.ept.EPTFactory;
import com.sun.xml.internal.ws.pept.ept.MessageInfo;
import com.sun.xml.internal.ws.pept.presentation.MessageStruct;
import com.sun.xml.internal.ws.pept.protocol.MessageDispatcher;
import com.sun.xml.internal.ws.server.RuntimeContext;
import com.sun.xml.internal.ws.spi.runtime.ClientTransportFactory;
import com.sun.xml.internal.ws.spi.runtime.WSConnection;
import com.sun.xml.internal.ws.transport.http.client.HttpClientTransportFactory;
import com.sun.xml.internal.ws.util.Base64Util;
import com.sun.xml.internal.ws.util.XMLConnectionUtil;
import com.sun.xml.internal.ws.util.xml.XmlUtil;
import javax.activation.DataSource;
import javax.activation.DataHandler;
import javax.xml.bind.JAXBContext;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.*;
import static javax.xml.ws.BindingProvider.PASSWORD_PROPERTY;
import static javax.xml.ws.BindingProvider.USERNAME_PROPERTY;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.http.HTTPBinding;
import javax.xml.ws.http.HTTPException;
import javax.xml.ws.soap.SOAPBinding;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.*;
/**
* Client-side XML-based message dispatcher {@link com.sun.xml.internal.ws.pept.protocol.MessageDispatcher}
*
* @author WS Development Team
*/
public class XMLMessageDispatcher implements MessageDispatcher {
protected static final int MAX_THREAD_POOL_SIZE = 3;
protected static final long AWAIT_TERMINATION_TIME = 10L;
protected ExecutorService executorService = null;
/**
* Default constructor
*/
public XMLMessageDispatcher() {
}
/*
* Invokes doSendAsync method if the message exchange pattern is asynchronous, otherwise
* invokes doSend method.
*
* @see com.sun.pept.protocol.MessageDispatcher#send(com.sun.pept.ept.MessageInfo)
*/
public void send(MessageInfo messageInfo) {
if (isAsync(messageInfo)) {
doSendAsync(messageInfo);
} else {
doSend(messageInfo);
}
}
/**
* Orchestrates the sending of a synchronous request
*/
protected XMLMessage doSend(MessageInfo messageInfo) {
//change from LogicalEPTFactory to ContactInfoBase - should be changed back when we have things working
EPTFactory contactInfo = messageInfo.getEPTFactory();
XMLEncoder encoder = (XMLEncoder) contactInfo.getEncoder(messageInfo);
boolean handlerResult = true;
boolean isRequestResponse = (messageInfo.getMEP() == MessageStruct.REQUEST_RESPONSE_MEP);
DispatchContext dispatchContext = (DispatchContext) messageInfo.getMetaData(BindingProviderProperties.DISPATCH_CONTEXT);
if (!isHTTPMessageType(dispatchContext)) {
throw new WebServiceException("Mode not allowed with HTTP Binding. Must use other Service.mode");
}
XMLMessage xm = makeXMLMessage(messageInfo);
try {
HandlerChainCaller caller = getHandlerChainCaller(messageInfo);
if (caller.hasHandlers()) {
XMLHandlerContext handlerContext = new XMLHandlerContext(
messageInfo, null, xm);
updateMessageContext(messageInfo, handlerContext);
handlerResult = callHandlersOnRequest(handlerContext);
updateXMLMessage(handlerContext);
xm = handlerContext.getXMLMessage();
if (xm == null) {
xm = encoder.toXMLMessage(
handlerContext.getInternalMessage(), messageInfo);
}
// the only case where no message is sent
if (isRequestResponse && !handlerResult) {
return xm;
}
}
// Setting encoder here is necessary for calls to getBindingId()
// messageInfo.setEncoder(encoder);
Map<String, Object> context = processMetadata(messageInfo, xm);
// set the MIME headers on connection headers
Map<String, List<String>> ch = new HashMap<String, List<String>>();
for (Iterator iter = xm.getMimeHeaders().getAllHeaders(); iter.hasNext();)
{
List<String> h = new ArrayList<String>();
MimeHeader mh = (MimeHeader) iter.next();
h.clear();
h.add(mh.getValue());
ch.put(mh.getName(), h);
}
setConnection(messageInfo, context);
((WSConnection) messageInfo.getConnection()).setHeaders(ch);
if (!isAsync(messageInfo)) {
WSConnection connection = (WSConnection) messageInfo.getConnection();
//logRequestMessage(xm, messageInfo);
XMLConnectionUtil.sendResponse(connection, xm);
}
// if handlerResult is false, the receive has already happened
if (isRequestResponse && handlerResult) {
receive(messageInfo);
postReceiveHook(messageInfo);
}
} catch (Throwable e) {
setResponseType(e, messageInfo);
messageInfo.setResponse(e);
}
return xm;
}
/**
* Process and classify the metadata in MIME headers or message context. <String,String> data
* is copied into MIME headers and the remaining metadata is passed in message context to the
* transport layer.
*
* @param messageInfo
* @param xm
*/
protected Map<String, Object> processMetadata(MessageInfo messageInfo, XMLMessage xm) {
Map<String, Object> messageContext = new HashMap<String, Object>();
List<String> header = new ArrayList<String>();
ContextMap properties = (ContextMap)
messageInfo.getMetaData(JAXWS_CONTEXT_PROPERTY);
DispatchContext dcontext = (DispatchContext)
messageInfo.getMetaData(BindingProviderProperties.DISPATCH_CONTEXT);
if (isHTTPMessageType(dcontext)) {
setHTTPContext(messageContext, dcontext, properties);
}
if (messageInfo.getMEP() == MessageStruct.ONE_WAY_MEP)
messageContext.put(ONE_WAY_OPERATION, "true");
// process the properties
if (properties != null) {
for (Iterator names = properties.getPropertyNames(); names.hasNext();)
{
String propName = (String) names.next();
// consume PEPT-specific properties
if (propName.equals(ClientTransportFactory.class.getName())) {
messageContext.put(CLIENT_TRANSPORT_FACTORY, (ClientTransportFactory) properties.get(propName));
} else if (propName.equals(USERNAME_PROPERTY)) {
String credentials = (String) properties.get(USERNAME_PROPERTY);
if (credentials != null) {
credentials += ":";
String password = (String) properties.get(PASSWORD_PROPERTY);
if (password != null)
credentials += password;
try {
credentials = Base64Util.encode(credentials.getBytes());
} catch (Exception ex) {
throw new WebServiceException(ex);
}
xm.getMimeHeaders().addHeader("Authorization", "Basic " + credentials);
}
} else
if (propName.equals(BindingProvider.SESSION_MAINTAIN_PROPERTY))
{
Object maintainSession = properties.get(BindingProvider.SESSION_MAINTAIN_PROPERTY);
if (maintainSession != null && maintainSession.equals(Boolean.TRUE))
{
Object cookieJar = properties.get(HTTP_COOKIE_JAR);
if (cookieJar != null)
messageContext.put(HTTP_COOKIE_JAR, cookieJar);
}
} else {
messageContext.put(propName, properties.get(propName));
}
}
}
// Set accept header depending on content negotiation property
String contentNegotiation = (String)
messageInfo.getMetaData(CONTENT_NEGOTIATION_PROPERTY);
String bindingId = getBindingId(messageInfo);
if (bindingId.equals(SOAPBinding.SOAP12HTTP_BINDING)) {
xm.getMimeHeaders().addHeader(ACCEPT_PROPERTY,
contentNegotiation != "none" ? SOAP12_XML_FI_ACCEPT_VALUE : SOAP12_XML_ACCEPT_VALUE);
} else {
xm.getMimeHeaders().addHeader(ACCEPT_PROPERTY,
contentNegotiation != "none" ? XML_FI_ACCEPT_VALUE : XML_ACCEPT_VALUE);
}
//setRequestHeaders
Map<String, List<String>> requestHeaders = (Map)
properties.get(MessageContext.HTTP_REQUEST_HEADERS);
//requestHeaders.
setMimeHeaders(requestHeaders, xm);
messageContext.put(BINDING_ID_PROPERTY, bindingId);
// SOAPAction: MIME header
RuntimeContext runtimeContext = (RuntimeContext) messageInfo.getMetaData(JAXWS_RUNTIME_CONTEXT);
if (runtimeContext != null) {
JavaMethod javaMethod = runtimeContext.getModel().getJavaMethod(messageInfo.getMethod());
if (javaMethod != null) {
String soapAction = ((com.sun.xml.internal.ws.model.soap.SOAPBinding) javaMethod.getBinding()).getSOAPAction();
header.clear();
if (soapAction == null) {
xm.getMimeHeaders().addHeader("SOAPAction", "\"\"");
} else {
xm.getMimeHeaders().addHeader("SOAPAction", soapAction);
}
}
}
return messageContext;
}
protected void setConnection(MessageInfo messageInfo, Map<String, Object> context) {
ClientTransportFactory clientTransportFactory = (ClientTransportFactory) context.get(CLIENT_TRANSPORT_FACTORY);
WSConnection connection = null;
if (clientTransportFactory == null) {
clientTransportFactory = new HttpClientTransportFactory();
}
connection = clientTransportFactory.create(context);
messageInfo.setConnection(connection);
}
protected void setResponseType(Throwable e, MessageInfo messageInfo) {
//e.printStackTrace();
if (e instanceof RuntimeException) {
messageInfo.setResponseType(MessageStruct.UNCHECKED_EXCEPTION_RESPONSE);
if (e instanceof ClientTransportException) {
Throwable temp = e;
e = new WebServiceException(temp.getMessage(), temp);
}
} else {
messageInfo.setResponseType(MessageStruct.CHECKED_EXCEPTION_RESPONSE);
}
messageInfo.setResponse(e);
}
/*
* Orchestrates the receiving of a synchronous response
*
* @see com.sun.pept.protocol.MessageDispatcher#receive(com.sun.pept.ept.MessageInfo)
*
* todo: exception handling with possible saaj error below
*/
public void receive(MessageInfo messageInfo) {
// change from LogicalEPTFactory to ContactInfoBase - should be changed back when we have things working
EPTFactory contactInfo = messageInfo.getEPTFactory();
XMLMessage xm = getXMLMessage(messageInfo);
// Content negotiation logic
String contentNegotiation = (String) messageInfo.getMetaData(CONTENT_NEGOTIATION_PROPERTY);
// If XML request
if (contentNegotiation == "pessimistic") {
try {
if (xm.isFastInfoset()) {
Map requestContext = (Map) messageInfo.getMetaData(JAXWS_CONTEXT_PROPERTY);
// Further requests will be send using FI
requestContext.put(CONTENT_NEGOTIATION_PROPERTY, "optimistic");
}
}
catch (ClassCastException e) {
// Content negotiation fails
}
}
try {
//logResponseMessage(xm, messageInfo);
} catch (Exception ex) {
throw new WebServiceException(ex);
}
XMLHandlerContext handlerContext =
getInboundHandlerContext(messageInfo, xm);
HandlerChainCaller caller = getHandlerChainCaller(messageInfo);
if (caller.hasHandlers()) {
callHandlersOnResponse(handlerContext);
xm = handlerContext.getXMLMessage();
}
//set messageInfo response with appropriate result
//at same time sets ResponseContext
setResponse(messageInfo, xm, handlerContext);
}
private void setResponse(MessageInfo messageInfo, XMLMessage xm, HandlerContext handlerContext) {
Map<String, DataHandler> attachments = getAttachments(handlerContext, xm);
updateResponseContext(messageInfo, (XMLHandlerContext)handlerContext, attachments);
DispatchContext dispatchContext = (DispatchContext) messageInfo.getMetaData(BindingProviderProperties.DISPATCH_CONTEXT);
DispatchContext.MessageType msgtype = (DispatchContext.MessageType) dispatchContext.getProperty(DispatchContext.DISPATCH_MESSAGE);
if (msgtype != null) {
switch ((DispatchContext.MessageType) msgtype) {
case HTTP_SOURCE_MESSAGE:
messageInfo.setResponse(xm.getSource());
break;
case HTTP_SOURCE_PAYLOAD:
messageInfo.setResponse(xm.getSource());
break;
case HTTP_JAXB_PAYLOAD:
messageInfo.setResponse(xm.getPayload(getJAXBContext(messageInfo)));
break;
case HTTP_DATASOURCE_MESSAGE:
if (xm.getDataSource() != null)
messageInfo.setResponse(xm.getDataSource());
break;
default:
throw new WebServiceException("Unknown invocation return object ");
}
} else {
//tbd just assume source for now
throw new WebServiceException("Unknown invocation return object");
}
}
private Map<String, DataHandler> getAttachments(HandlerContext handlerContext, XMLMessage xm) {
//are there attachments on the MessageContext properties ? Handlers
Map<String, DataHandler> attmc = (Map<String, DataHandler>)
handlerContext.getMessageContext().get(MessageContext.INBOUND_MESSAGE_ATTACHMENTS);
//can we get it from XMLMessage as well?
Map<String, DataHandler> attxm = xm.getAttachments();
Map<String, DataHandler> attachments = new HashMap<String, DataHandler>();
if (attxm != null && attmc != null) {
attachments.putAll(attxm);
attachments.putAll(attmc);
} else if (attxm != null) {
attachments.putAll(attxm);
} else if (attmc != null)
attachments.putAll(attmc);
else {
attachments = null; //gc it
return null;
}
return attachments;
}
private XMLHandlerContext getInboundHandlerContext(
MessageInfo messageInfo, XMLMessage xm) {
XMLHandlerContext handlerContext = (XMLHandlerContext) messageInfo
.getMetaData(BindingProviderProperties.JAXWS_HANDLER_CONTEXT_PROPERTY);
if (handlerContext != null) {
handlerContext.setXMLMessage(xm);
handlerContext.setInternalMessage(null);
} else {
handlerContext = new XMLHandlerContext(messageInfo, null, xm);
}
return handlerContext;
}
/**
* Orchestrates the sending of an asynchronous request
*/
protected void doSendAsync(final MessageInfo messageInfo) {
try { // should have already been caught
preSendHook(messageInfo);
XMLMessage xm = doSend(messageInfo);
postSendHook(messageInfo);
//pass a copy of MessageInfo to the future task,so that no conflicts
//due to threading happens
Response r = sendAsyncReceive(MessageInfoBase.copy(messageInfo), xm);
if (executorService == null) {
executorService =
Executors.newFixedThreadPool(MAX_THREAD_POOL_SIZE, new DaemonThreadFactory());
}
AsyncHandlerService service = (AsyncHandlerService) messageInfo
.getMetaData(BindingProviderProperties.JAXWS_CLIENT_ASYNC_HANDLER);
WSFuture wsfuture = null;
if (service != null) {
wsfuture = service.setupAsyncCallback(r);
((ResponseImpl) r).setUID(service.getUID());
((ResponseImpl) r).setHandlerService(service);
}
executorService.execute((FutureTask) r);
if (service == null)
messageInfo.setResponse(r);
else
messageInfo.setResponse(wsfuture);
} catch (Throwable e) {
messageInfo.setResponse(e);
}
}
/**
* Orchestrates the receiving of an asynchronous response
*/
protected Response<Object> sendAsyncReceive(final MessageInfo messageInfo, final XMLMessage xm) {
final AsyncHandlerService handler = (AsyncHandlerService) messageInfo
.getMetaData(BindingProviderProperties.JAXWS_CLIENT_ASYNC_HANDLER);
final boolean callback = (messageInfo.getMEP() == MessageStruct.ASYNC_CALLBACK_MEP) ? true
: false;
if (callback && (handler == null))
throw new WebServiceException("Asynchronous callback invocation, but no handler - AsyncHandler required");
final Response r = new ResponseImpl<Object>(new Callable<Object>() {
public Object call() throws Exception {
// get connection and do http.invoke()
try {
final WSConnection connection = (WSConnection) messageInfo.getConnection();
//logRequestMessage(xm, messageInfo);
XMLConnectionUtil.sendResponse(connection, xm);
} catch (Throwable t) {
messageInfo.setResponse(t);
messageInfo.setResponseType(MessageStruct.UNCHECKED_EXCEPTION_RESPONSE);
}
// receive response
preReceiveHook(messageInfo);
try {
receive(messageInfo);
} catch (Exception ex) {
messageInfo.setResponse(ex);
}
postReceiveHook(messageInfo);
if (messageInfo.getResponse() instanceof Exception)
throw (Exception) messageInfo.getResponse();
return messageInfo.getResponse();
}
});
messageInfo.setMetaData(JAXWS_CLIENT_ASYNC_RESPONSE_CONTEXT, r);
return r;
}
protected boolean callHandlersOnRequest(XMLHandlerContext handlerContext) {
HandlerChainCaller caller = getHandlerChainCaller(
handlerContext.getMessageInfo());
boolean responseExpected = (handlerContext.getMessageInfo().getMEP() !=
MessageStruct.ONE_WAY_MEP);
try {
return caller.callHandlers(Direction.OUTBOUND,
RequestOrResponse.REQUEST, handlerContext, responseExpected);
} catch (ProtocolException pe) {
if (MessageContextUtil.ignoreFaultInMessage(
handlerContext.getMessageContext())) {
// Ignore fault in this case and use exception.
throw pe;
} else
return false;
} catch (WebServiceException wse) {
throw wse;
} catch (RuntimeException re) {
// handlers are expected to be able to throw RE
throw new WebServiceException(re);
}
}
/*
* User's handler can throw a RuntimeExceptions
* (e.g., a ProtocolException).
* Need to wrap any RuntimeException (other than WebServiceException) in
* WebServiceException.
*/
protected boolean callHandlersOnResponse(XMLHandlerContext handlerContext) {
HandlerChainCaller caller = getHandlerChainCaller(
handlerContext.getMessageInfo());
try {
return caller.callHandlers(Direction.INBOUND,
RequestOrResponse.RESPONSE, handlerContext, false);
} catch (WebServiceException wse) {
throw wse;
} catch (RuntimeException re) {
// handlers are expected to be able to throw RE
throw new WebServiceException(re);
}
}
protected Binding getBinding(MessageInfo messageInfo) {
ContextMap context = (ContextMap) ((MessageInfoBase) messageInfo)
.getMetaData(BindingProviderProperties.JAXWS_CONTEXT_PROPERTY);
BindingProvider provider = (BindingProvider) context
.get(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY);
return provider.getBinding();
}
protected HandlerChainCaller getHandlerChainCaller(MessageInfo messageInfo) {
BindingImpl binding = (BindingImpl) getBinding(messageInfo);
return binding.getHandlerChainCaller();
}
protected void updateMessageContext(MessageInfo messageInfo,
XMLHandlerContext context) {
MessageContext messageContext = context.getMessageContext();
messageInfo.setMetaData(
BindingProviderProperties.JAXWS_HANDLER_CONTEXT_PROPERTY, context);
RequestContext ctxt = (RequestContext) messageInfo
.getMetaData(BindingProviderProperties.JAXWS_CONTEXT_PROPERTY);
Iterator i = ctxt.copy().getPropertyNames();
while (i.hasNext()) {
String name = (String) i.next();
Object value = ctxt.get(name);
messageContext.put(name, value);
}
}
protected void updateResponseContext(MessageInfo messageInfo,
XMLHandlerContext context, Map<String, DataHandler> attachments) {
MessageContext messageContext = context.getMessageContext();
BindingProvider provider = (BindingProvider)
messageContext.get(JAXWS_CLIENT_HANDLE_PROPERTY);
ResponseContext responseContext = new ResponseContext(provider);
for (String name : messageContext.keySet()) {
MessageContext.Scope scope = messageContext.getScope(name);
if (MessageContext.Scope.APPLICATION == scope) {
Object value = messageContext.get(name);
responseContext.put(name, value);
}
}
//let's update status code
MessageContext mc = context.getMessageContext();
WSConnection con = messageInfo.getConnection();
Map<String, List<String>> headers = con.getHeaders();
responseContext.put(MessageContext.HTTP_RESPONSE_HEADERS, headers);
responseContext.put(MessageContext.HTTP_RESPONSE_CODE, con.getStatus());
//attachments for ResponseContext
if (attachments != null)
responseContext.put(MessageContext.INBOUND_MESSAGE_ATTACHMENTS, attachments);
ResponseImpl asyncResponse = (ResponseImpl) messageInfo.getMetaData(
JAXWS_CLIENT_ASYNC_RESPONSE_CONTEXT);
if (asyncResponse != null) {
asyncResponse.setResponseContext(responseContext.copy());
} else {
messageInfo.setMetaData(JAXWS_RESPONSE_CONTEXT_PROPERTY,
responseContext.copy());
}
}
/**
* @return true if message exchange pattern indicates asynchronous, otherwise returns false
*/
protected boolean isAsync(MessageInfo messageInfo) {
if ((messageInfo.getMEP() == MessageStruct.ASYNC_POLL_MEP)
|| (messageInfo.getMEP() == MessageStruct.ASYNC_CALLBACK_MEP)) {
return true;
}
return false;
}
private void preSendHook(MessageInfo messageInfo) {
}
private void preReceiveHook(MessageInfo messageInfo) {
}
private void postSendHook(MessageInfo messageInfo) {
if (messageInfo.getResponseType() != MessageStruct.NORMAL_RESPONSE) {
postReceiveHook(messageInfo);
throw (WebServiceException) messageInfo.getResponse();
}
}
private void postReceiveAndDecodeHook(MessageInfo messageInfo) {
}
private void postReceiveHook(MessageInfo messageInfo) {
if (messageInfo.getMEP() == MessageStruct.ONE_WAY_MEP)
return;
Object response = messageInfo.getResponse();
if (response instanceof StreamSource) {
InputStream is = ((StreamSource) response).getInputStream();
Transformer transformer = XmlUtil.newTransformer();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream(is.available());
if (out.size() > 0) {
transformer.transform((StreamSource) response,
new StreamResult(out));
byte[] bytes = out.toByteArray();
//could do to string
if (new String(bytes).indexOf("HTTPException") > -1)
throw new HTTPException(HttpURLConnection.HTTP_INTERNAL_ERROR);
else {
InputStream bis = new ByteArrayInputStream(bytes);
messageInfo.setResponse(new StreamSource(bis));
}
}
} catch (TransformerException e) {
throw new WebServiceException(e);
} catch (IOException e) {
throw new WebServiceException(e);
}
}
switch (messageInfo.getResponseType()) {
case MessageStruct.NORMAL_RESPONSE:
// not sure where this belongs yet - but for now-
return;
case MessageStruct.CHECKED_EXCEPTION_RESPONSE:
if (response instanceof Exception) {
throw new HTTPException(HttpURLConnection.HTTP_INTERNAL_ERROR);
}
return;
case MessageStruct.UNCHECKED_EXCEPTION_RESPONSE:
if (response instanceof ProtocolException) {
throw new HTTPException(HttpURLConnection.HTTP_INTERNAL_ERROR);
} else {
WebServiceException jex = null;
if (response instanceof Exception) {
throw new WebServiceException((Exception) response);
}
messageInfo.setResponse(response);
}
return;
default:
messageInfo.setResponse(response);
}
}
private void closeAllHandlers(XMLHandlerContext context) {
HandlerChainCaller caller = getHandlerChainCaller(
context.getMessageInfo());
if (caller != null && caller.hasHandlers()) {
caller.forceCloseHandlersOnClient(context);
}
}
/**
* This method is used to create the appropriate SOAPMessage (1.1 or 1.2 using SAAJ api).
*
* @return the BindingId associated with messageInfo
*/
protected String getBindingId(MessageInfo messageInfo) {
SOAPEncoder encoder = (SOAPEncoder) messageInfo.getEncoder();
if (encoder instanceof SOAPXMLEncoder)
return SOAPBinding.SOAP11HTTP_BINDING;
else if (encoder instanceof SOAP12XMLEncoder)
return SOAPBinding.SOAP12HTTP_BINDING;
else
return HTTPBinding.HTTP_BINDING;
}
/**
* Logs the SOAP request message
*/
protected void logRequestMessage(XMLMessage request, MessageInfo messageInfo)
throws IOException, MessagingException, TransformerException {
OutputStream out = ((WSConnection) messageInfo.getConnection()).getDebug();
if (out != null) {
String s = "******************\nRequest\n";
out.write(s.getBytes());
for (Iterator iter =
request.getMimeHeaders().getAllHeaders();
iter.hasNext();
) {
MimeHeader header = (MimeHeader) iter.next();
s = header.getName() + ": " + header.getValue() + "\n";
out.write(s.getBytes());
}
out.flush();
request.writeTo(out);
s = "\n";
out.write(s.getBytes());
out.flush();
}
}
/**
* Logs the SOAP response message
*/
protected void logResponseMessage(XMLMessage response, MessageInfo messageInfo)
throws IOException, MessagingException, TransformerException {
OutputStream out = ((WSConnection) messageInfo.getConnection()).getDebug();
if (out != null) {
String s = "Response\n";
out.write(s.getBytes());
s =
"Http Status Code: "
+ ((WSConnection) messageInfo.getConnection()).getStatus()
+ "\n\n";
out.write(s.getBytes());
for (Iterator iter =
response.getMimeHeaders().getAllHeaders();
iter.hasNext();
) {
MimeHeader header = (MimeHeader) iter.next();
s = header.getName() + ": " + header.getValue() + "\n";
out.write(s.getBytes());
}
out.flush();
response.writeTo(out);
s = "******************\n\n";
out.write(s.getBytes());
}
}
/*
* Gets XMLMessage from the connection
*/
private XMLMessage getXMLMessage(MessageInfo messageInfo) {
WSConnection con = (WSConnection) messageInfo.getConnection();
return XMLConnectionUtil.getXMLMessage(con, messageInfo);
}
protected JAXBContext getJAXBContext(MessageInfo messageInfo) {
JAXBContext jc = null;
RequestContext context = (RequestContext) messageInfo.getMetaData(BindingProviderProperties.JAXWS_CONTEXT_PROPERTY);
if (context != null)
jc = (JAXBContext) context.get(BindingProviderProperties.JAXB_CONTEXT_PROPERTY);
return jc;
}
public void setHTTPContext(Map<String, Object> messageContext, DispatchContext dispatchContext, Map requestContext) {
if (requestContext.get(MessageContext.HTTP_REQUEST_METHOD) != null)
messageContext.put(MessageContext.HTTP_REQUEST_METHOD, requestContext.get(MessageContext.HTTP_REQUEST_METHOD));
if (requestContext.get(MessageContext.HTTP_REQUEST_HEADERS) != null)
messageContext.put(MessageContext.HTTP_REQUEST_HEADERS, requestContext.get(MessageContext.HTTP_REQUEST_HEADERS));
//resolve endpoint look for query parameters, pathInfo
String origEndpoint = (String) requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
String pathInfo = null;
String queryString = null;
if (requestContext.get(MessageContext.PATH_INFO) != null) {
pathInfo = (String) requestContext.get(MessageContext.PATH_INFO);
}
if (requestContext.get(MessageContext.QUERY_STRING) != null) {
queryString = (String) requestContext.get(MessageContext.QUERY_STRING);
}
String resolvedEndpoint = null;
if (pathInfo != null || queryString != null) {
pathInfo = checkPath(pathInfo);
queryString = checkQuery(queryString);
if (origEndpoint != null) {
try {
URI endpointURI = new URI(origEndpoint);
resolvedEndpoint = resolveURI(endpointURI, pathInfo, queryString);
} catch (URISyntaxException e) {
resolvedEndpoint = origEndpoint;
}
}
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, resolvedEndpoint);
messageContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, resolvedEndpoint);
}
}
protected String resolveURI(URI endpointURI, String pathInfo, String queryString) {
String query = null;
String fragment = null;
if (queryString != null) {
URI result = endpointURI.resolve(queryString);
query = result.getQuery();
fragment = result.getFragment();
}
//String path = (pathInfo != null) ? endpointURI.getPath() + pathInfo : endpointURI.getPath();
String path = (pathInfo != null) ? pathInfo : endpointURI.getPath();
try {
URI temp = new URI(null, null, path, query, fragment);
return endpointURI.resolve(temp).toString();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return endpointURI.toString();
}
private String checkPath(String path) {
//does it begin with /
return (path == null || path.startsWith("/")) ? path : "/" + path;
}
private String checkQuery(String query) {
//does it begin with ?
return (query == null || query.startsWith("?")) ? query : "?" + query;
}
protected boolean isHTTPMessageType(DispatchContext dispatchContext) {
DispatchContext.MessageType type = (DispatchContext.MessageType)
dispatchContext.getProperty(DispatchContext.DISPATCH_MESSAGE);
if ((type == DispatchContext.MessageType.HTTP_DATASOURCE_MESSAGE) ||
//(type == DispatchContext.MessageType.HTTP_DATASOURCE_PAYLOAD) ||
(type == DispatchContext.MessageType.HTTP_SOURCE_MESSAGE) ||
(type == DispatchContext.MessageType.HTTP_SOURCE_PAYLOAD) ||
//(type == DispatchContext.MessageType.HTTP_JAXB_MESSAGE) ||
(type == DispatchContext.MessageType.HTTP_JAXB_PAYLOAD))
return true;
return false;
}
protected XMLMessage makeXMLMessage
(MessageInfo
messageInfo) {
XMLMessage xm = null;
Class clazz = (Class)
messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_CLASS);
Map<String, Object> context = (Map<String, Object>)
messageInfo.getMetaData(BindingProviderProperties.JAXWS_CONTEXT_PROPERTY);
Map<String, DataHandler> attachments = (context != null) ?
(Map<String, DataHandler> )context.get(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS) : null;
// Determine if Fast Infoset is to be used
boolean useFastInfoset =
(messageInfo.getMetaData(CONTENT_NEGOTIATION_PROPERTY) == "optimistic");
Object object = messageInfo.getData()[0];
if (clazz != null && clazz.isAssignableFrom(Source.class)) {
//xm = new XMLMessage((Source) object, useFastInfoset);
xm = new XMLMessage((Source) object, attachments, useFastInfoset);
} else if (clazz != null && clazz.isAssignableFrom(DataSource.class)) {
xm = new XMLMessage((DataSource) object, useFastInfoset);
} else {
xm = new XMLMessage(object, getJAXBContext(messageInfo), attachments, useFastInfoset);
//xm = new XMLMessage(object, getJAXBContext(messageInfo), useFastInfoset);
}
return xm;
}
private void setMimeHeaders(Map<String, List<String>> requestHeaders, XMLMessage xm) {
if ((requestHeaders != null) && (!requestHeaders.isEmpty())) {
Set<Map.Entry<String, List<String>>> headerSet = requestHeaders.entrySet();
Iterator<Map.Entry<String, List<String>>> iter = headerSet.iterator();
while (iter.hasNext()) {
Map.Entry<String,List<String>> entry =iter.next();
MimeHeaders headers = xm.getMimeHeaders();
String[] values = entry.getValue().toArray(new String[entry.getValue().size()] );;
StringBuffer buf = new StringBuffer(250);
if (values.length > 0)
buf.append(values[0]);
else break;
for (int i = 1; i < values.length - 1; i++){
buf.append(values[i]);
}
headers.addHeader(entry.getKey(), buf.toString());
}
}
}
private XMLMessage updateXMLMessage(XMLHandlerContext context) {
// Create a new XMLMessage from existing message and OUTBOUND attachments property
MessageContext msgCtxt = context.getMessageContext();
Map<String, DataHandler> atts = (Map<String, DataHandler>)msgCtxt.get(
MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS);
if (atts != null) {
XMLMessage xmlMessage = context.getXMLMessage();
if (xmlMessage != null) {
Map<String, DataHandler> allAtts = xmlMessage.getAttachments();
if (allAtts != null) {
allAtts.putAll(atts);
} else {
allAtts = atts;
}
context.setXMLMessage(new XMLMessage(xmlMessage.getSource(), allAtts,
xmlMessage.isFastInfoset()));
} else {
//can I make a message w/o src
}
}
return context.getXMLMessage();
}
class DaemonThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread daemonThread = new Thread(r);
daemonThread.setDaemon(Boolean.TRUE);
return daemonThread;
}
}
}