blob: 9e1b9600245e087b033157afa5f97921dd9723ab [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.soap.client;
import com.sun.xml.internal.messaging.saaj.soap.MessageImpl;
import com.sun.xml.internal.ws.binding.BindingImpl;
import com.sun.xml.internal.ws.client.AsyncHandlerService;
import com.sun.xml.internal.ws.client.ContextMap;
import com.sun.xml.internal.ws.client.BindingProviderProperties;
import static com.sun.xml.internal.ws.client.BindingProviderProperties.*;
import com.sun.xml.internal.ws.client.EndpointIFInvocationHandler;
import com.sun.xml.internal.ws.client.EndpointIFContext;
import com.sun.xml.internal.ws.client.RequestContext;
import com.sun.xml.internal.ws.client.ResponseContext;
import com.sun.xml.internal.ws.client.WSFuture;
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.JAXWSAttachmentMarshaller;
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.SOAPXMLDecoder;
import com.sun.xml.internal.ws.encoding.soap.client.SOAPXMLEncoder;
import com.sun.xml.internal.ws.encoding.soap.internal.InternalMessage;
import com.sun.xml.internal.ws.encoding.soap.internal.MessageInfoBase;
import com.sun.xml.internal.ws.encoding.soap.message.SOAPFaultInfo;
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.SOAPHandlerContext;
import com.sun.xml.internal.ws.model.JavaMethod;
import com.sun.xml.internal.ws.model.RuntimeModel;
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.SystemHandlerDelegate;
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.FastInfosetUtil;
import com.sun.xml.internal.ws.util.MessageInfoUtil;
import com.sun.xml.internal.ws.util.SOAPConnectionUtil;
import com.sun.xml.internal.ws.util.xml.XmlUtil;
import com.sun.xml.internal.ws.wsdl.parser.BindingOperation;
import javax.activation.DataHandler;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.ProtocolException;
import javax.xml.ws.Service;
import javax.xml.ws.Response;
import javax.xml.ws.WebServiceException;
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.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Client-side SOAP protocol-specific {@link com.sun.pept.protocol.MessageDispatcher}
*
* @author WS Development Team
*/
public class SOAPMessageDispatcher implements MessageDispatcher {
protected static final int MAX_THREAD_POOL_SIZE = 3;
protected static final long AWAIT_TERMINATION_TIME = 10L;
protected ExecutorService executorService;
private final static String MUST_UNDERSTAND_FAULT_MESSAGE_STRING = "SOAP must understand error";
/**
* Default constructor
*/
public SOAPMessageDispatcher() {
}
/*
* 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 SOAPMessage doSend(MessageInfo messageInfo) {
//change from LogicalEPTFactory to ContactInfoBase - should be changed back when we have things working
EPTFactory contactInfo = messageInfo.getEPTFactory();
SOAPXMLEncoder encoder = (SOAPXMLEncoder) contactInfo.getEncoder(messageInfo);
SOAPMessage sm = null;
boolean handlerResult = true;
boolean isRequestResponse = (messageInfo.getMEP() == MessageStruct.REQUEST_RESPONSE_MEP);
try {
if (messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.MESSAGE)
{
sm = (SOAPMessage) messageInfo.getData()[0];
// Ensure supplied message is encoded according to conneg
FastInfosetUtil.ensureCorrectEncoding(messageInfo, sm);
}
SOAPHandlerContext handlerContext = null;
InternalMessage im = encoder.toInternalMessage(messageInfo);
HandlerChainCaller caller = getHandlerChainCaller(messageInfo);
if (caller.hasHandlers()) {
im = preHandlerOutboundHook(sm, im);
handlerContext = new SOAPHandlerContext(messageInfo, im, sm);
//this is needed so that attachments are compied from RESPONSE_MESSAGE_ATTACHMEMTN PROPERTY
handlerContext.getMessageContext().put(
MessageContext.MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE);
encoder.setAttachmentsMap(messageInfo, im);
updateMessageContext(messageInfo, handlerContext);
//now that the MESSAGE_OUTBOUND_PROPERTY is set so populate the attachemnts
handlerContext.populateAttachmentMap();
JAXWSAttachmentMarshaller am = MessageInfoUtil.getAttachmentMarshaller(messageInfo);
boolean isXopped = false;
//there are handlers so disable Xop encoding if enabled, so that they dont
// see xop:Include reference
if ((am != null) && am.isXOPPackage()) {
isXopped = am.isXOPPackage();
am.setXOPPackage(false);
}
handlerResult = callHandlersOnRequest(handlerContext);
// now put back the old value
if ((am != null)) {
am.setXOPPackage(isXopped);
}
sm = handlerContext.getSOAPMessage();
postHandlerOutboundHook(messageInfo, handlerContext, sm);
if (sm == null) {
sm = encoder.toSOAPMessage(handlerContext.getInternalMessage(), messageInfo);
}
// the only case where no message is sent
if (isRequestResponse && !handlerResult) {
SOAPXMLDecoder decoder = (SOAPXMLDecoder) contactInfo.getDecoder(messageInfo);
im = decoder.toInternalMessage(sm, messageInfo);
decoder.toMessageInfo(im, messageInfo);
return sm;
}
}
// Setting encoder here is necessary for calls to getBindingId()
messageInfo.setEncoder(encoder);
SystemHandlerDelegate systemHandlerDelegate =
((com.sun.xml.internal.ws.spi.runtime.Binding) getBinding(messageInfo)).
getSystemHandlerDelegate();
if (systemHandlerDelegate != null) {
if (handlerContext == null) {
handlerContext = new SOAPHandlerContext(messageInfo, im, sm);
//this is needed so that attachments are compied from RESPONSE_MESSAGE_ATTACHMEMTN PROPERTY
handlerContext.getMessageContext().put(
MessageContext.MESSAGE_OUTBOUND_PROPERTY, Boolean.TRUE);
//now that the MESSAGE_OUTBOUND_PROPERTY is set so populate the attachemnts
handlerContext.populateAttachmentMap();
updateMessageContext(messageInfo, handlerContext);
}
encoder.setAttachmentsMap(messageInfo, im);
//already used im, we can set that to null
if ((sm != null) && (im != null))
handlerContext.setInternalMessage(null);
handlerContext.getBindingId();
systemHandlerDelegate.processRequest(
handlerContext.getSHDSOAPMessageContext());
sm = handlerContext.getSOAPMessage();
}
if (sm == null){
sm = encoder.toSOAPMessage(im, messageInfo);
if (handlerContext == null)
handlerContext = new SOAPHandlerContext(messageInfo, im, sm);
updateMessageContext(messageInfo, handlerContext);
}
Map<String, Object> context = processMetadata(messageInfo, sm);
setConnection(messageInfo, context);
if (!isAsync(messageInfo)) {
WSConnection connection = (WSConnection) messageInfo.getConnection();
logRequestMessage(sm, messageInfo);
SOAPConnectionUtil.sendResponse(connection, sm);
}
if (isRequestResponse) {
receive(messageInfo);
} else if (isOneway(messageInfo)) {
checkReturnStatus(messageInfo);
}
} catch (WebServiceException wse) {
setResponseType(wse, messageInfo);
messageInfo.setResponse(wse);
} catch (Throwable e) {
RuntimeException ex = (RuntimeException) e;
setResponseType(ex, messageInfo);
messageInfo.setResponse(ex);
}
return sm;
}
private boolean isOneway(MessageInfo messageInfo) {
return messageInfo.getMEP() == MessageStruct.ONE_WAY_MEP ? true : false;
}
/**
* 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 soapMessage
*/
protected Map<String, Object> processMetadata(MessageInfo messageInfo, SOAPMessage soapMessage) {
Map<String, Object> messageContext = new HashMap<String, Object>();
List<String> header = new ArrayList<String>();
ContextMap properties = (ContextMap) messageInfo.getMetaData(JAXWS_CONTEXT_PROPERTY);
if (messageInfo.getMEP() == MessageStruct.ONE_WAY_MEP)
messageContext.put(ONE_WAY_OPERATION, "true");
String soapAction = null;
boolean useSoapAction = false;
// 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);
}
soapMessage.getMimeHeaders().addHeader("Authorization", "Basic " + credentials);
}
} else
if (propName.equals(BindingProvider.SOAPACTION_USE_PROPERTY)) {
useSoapAction = ((Boolean)
properties.get(BindingProvider.SOAPACTION_USE_PROPERTY)).booleanValue();
if (useSoapAction)
soapAction = (String)
properties.get(BindingProvider.SOAPACTION_URI_PROPERTY);
} 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) || bindingId.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING))
{
soapMessage.getMimeHeaders().setHeader(ACCEPT_PROPERTY,
contentNegotiation != "none" ? SOAP12_XML_FI_ACCEPT_VALUE : SOAP12_XML_ACCEPT_VALUE);
} else {
soapMessage.getMimeHeaders().setHeader(ACCEPT_PROPERTY,
contentNegotiation != "none" ? XML_FI_ACCEPT_VALUE : XML_ACCEPT_VALUE);
}
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) {
soapAction = ((com.sun.xml.internal.ws.model.soap.SOAPBinding) javaMethod.getBinding()).getSOAPAction();
header.clear();
if (bindingId.equals(SOAPBinding.SOAP12HTTP_BINDING) || bindingId.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING))
{
if ((soapAction != null) && (soapAction.length() > 0)) {
((MessageImpl) soapMessage).setAction(soapAction);
}
} else {
if (soapAction == null) {
soapMessage.getMimeHeaders().addHeader("SOAPAction", "\"\"");
} else {
soapMessage.getMimeHeaders().addHeader("SOAPAction", "\"" + soapAction + "\"");
}
}
}
} else
if (messageInfo.getMetaData(BindingProviderProperties.DISPATCH_CONTEXT) != null)
{
//bug fix 6344358
header.clear();
if (bindingId.equals(SOAPBinding.SOAP12HTTP_BINDING) || bindingId.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING))
{
if ((soapAction != null) && (soapAction.length() > 0)) {
((MessageImpl) soapMessage).setAction(soapAction);
}
} else {
if (soapAction == null) {
soapMessage.getMimeHeaders().addHeader("SOAPAction", "\"\"");
} else {
soapMessage.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();
context.put(CLIENT_TRANSPORT_FACTORY, clientTransportFactory);
}
connection = clientTransportFactory.create(context);
messageInfo.setConnection(connection);
}
protected void setResponseType(Throwable e, MessageInfo messageInfo) {
if (e instanceof RuntimeException) {
messageInfo.setResponseType(MessageStruct.UNCHECKED_EXCEPTION_RESPONSE);
} else {
messageInfo.setResponseType(MessageStruct.CHECKED_EXCEPTION_RESPONSE);
}
messageInfo.setResponse(e);
}
public void checkReturnStatus(MessageInfo messageInfo) {
WSConnection connection = (WSConnection) messageInfo.getConnection();
Map<String, List<String>> headers = connection.getHeaders();
if (connection.getStatus() != 202 && connection.getStatus() != 200) {
Logger.getAnonymousLogger().log(Level.SEVERE, "HTTP status code for oneway: expected 202 or 200, got " + connection.getStatus());
// System.out.println("status: "+connection.getStatus());
}
}
/*
* 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();
//LogicalEPTFactory contactInfo = (LogicalEPTFactory) messageInfo.getEPTFactory();
SOAPXMLDecoder decoder = (SOAPXMLDecoder) contactInfo.getDecoder(messageInfo);
SOAPMessage sm = null;
try {
sm = decoder.toSOAPMessage(messageInfo);
} catch (RuntimeException e) {
//if there is a transport error HTTP status code and response Headers
//need to be populated into messageContext and requestContext
//bug 6373688
setContexts(messageInfo, sm);
throw e;
}
// Content negotiation logic
String contentNegotiationType = (String) messageInfo.getMetaData(CONTENT_NEGOTIATION_PROPERTY);
// If XML request
if (contentNegotiationType == "pessimistic") {
try {
if (((com.sun.xml.internal.messaging.saaj.soap.MessageImpl) sm).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(sm, messageInfo);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
SOAPHandlerContext handlerContext = getInboundHandlerContext(messageInfo, sm);
WSConnection con = (WSConnection) messageInfo.getConnection();
MessageContextUtil.setHttpStatusCode(handlerContext.getMessageContext(),
con.getStatus());
MessageContextUtil.setHttpResponseHeaders(handlerContext.getMessageContext(),
con.getHeaders());
//set the handlerContext to RuntimeContext
RuntimeContext rtContext = MessageInfoUtil.getRuntimeContext(messageInfo);
if (rtContext != null)
rtContext.setHandlerContext(handlerContext);
handlerContext.getMessageContext().put(
MessageContext.MESSAGE_OUTBOUND_PROPERTY, Boolean.FALSE);
//set MESSAGE_ATTACHMENTS property
MessageContext msgCtxt = MessageInfoUtil.getMessageContext(messageInfo);
if (msgCtxt != null) {
try {
//clear the attMap on this messageContext, its from request
Map<String, DataHandler> attMap = (Map<String, DataHandler>) msgCtxt.get(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS);
if (attMap != null)
attMap.clear();
MessageContextUtil.copyInboundMessageAttachments(msgCtxt, sm.getAttachments());
} catch (SOAPException e) {
throw new RuntimeException(e);
}
}
SystemHandlerDelegate systemHandlerDelegate =
((com.sun.xml.internal.ws.spi.runtime.Binding) getBinding(messageInfo)).
getSystemHandlerDelegate();
if (systemHandlerDelegate != null) {
// handlerContext.getMessageContext().put(
// MessageContext.MESSAGE_OUTBOUND_PROPERTY, Boolean.FALSE);
try {
systemHandlerDelegate.processResponse(handlerContext.getSHDSOAPMessageContext());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
try {
MessageInfoUtil.setHandlerChainCaller(messageInfo,
getHandlerChainCaller(messageInfo));
decoder.doMustUnderstandProcessing(sm, messageInfo, handlerContext, false);
} catch (SOAPException se) { // unusual saaj error
throw new RuntimeException(se);
} catch (IOException ie) { // unusual saaj error
throw new RuntimeException(ie);
} catch (SOAPFaultException sfe) {
closeAllHandlers(handlerContext);
throw sfe;
}
HandlerChainCaller caller = getHandlerChainCaller(messageInfo);
if (caller.hasHandlers()) {
callHandlersOnResponse(handlerContext);
postHandlerInboundHook(messageInfo, handlerContext, sm);
}
SOAPXMLEncoder encoder = (SOAPXMLEncoder) contactInfo.getEncoder(messageInfo);
InternalMessage im = handlerContext.getInternalMessage();
if (messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.MESSAGE)
im = null;
if (im == null) {
im = decoder.toInternalMessage(sm, messageInfo);
} else {
im = decoder.toInternalMessage(sm, im, messageInfo);
}
decoder.toMessageInfo(im, messageInfo);
updateResponseContext(messageInfo, handlerContext);
if (messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.MESSAGE)
{
messageInfo.setResponse(sm);
postReceiveAndDecodeHook(messageInfo);
}
}
private void setContexts(MessageInfo messageInfo, SOAPMessage sm) {
WSConnection con = (WSConnection) messageInfo.getConnection();
SOAPHandlerContext handlerContext = getInboundHandlerContext(messageInfo, sm);
MessageContextUtil.setHttpStatusCode(handlerContext.getMessageContext(),
con.getStatus());
updateResponseContext(messageInfo, handlerContext);
}
private SOAPHandlerContext getInboundHandlerContext(MessageInfo messageInfo, SOAPMessage sm) {
SOAPHandlerContext handlerContext = (SOAPHandlerContext) messageInfo
.getMetaData(BindingProviderProperties.JAXWS_HANDLER_CONTEXT_PROPERTY);
if (handlerContext != null) {
handlerContext.setSOAPMessage(sm);
handlerContext.setInternalMessage(null);
} else
handlerContext = new SOAPHandlerContext(messageInfo, null, sm);
return handlerContext;
}
/**
* Orchestrates the sending of an asynchronous request
*/
protected void doSendAsync(final MessageInfo messageInfo) {
try { // should have already been caught
preSendHook(messageInfo);
SOAPMessage sm = 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), sm);
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 SOAPMessage sm) {
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(sm, messageInfo);
SOAPConnectionUtil.sendResponse(connection, sm);
} 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(SOAPHandlerContext handlerContext) {
try {
HandlerChainCaller caller = getHandlerChainCaller(handlerContext.getMessageInfo());
boolean responseExpected = (handlerContext.getMessageInfo().getMEP() != MessageStruct.ONE_WAY_MEP);
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 RuntimeExceptions
* (e.g., a ProtocolException).
* Need to wrap any RuntimeException (other than WebServiceException) in
* WebServiceException.
*/
protected boolean callHandlersOnResponse(SOAPHandlerContext handlerContext) {
HandlerChainCaller caller =
getHandlerChainCaller(handlerContext.getMessageInfo());
try {
int httpResponseCode = (Integer) handlerContext.getMessageContext().get(
MessageContext.HTTP_RESPONSE_CODE);
if(httpResponseCode != 200 && httpResponseCode != 202) {
//Check if it is a fault message
SOAPMessage sm = handlerContext.getSOAPMessage();
if((sm != null) && sm.getSOAPBody().hasFault())
return caller.callHandleFaultOnClient(handlerContext);
}
return caller.callHandlers(Direction.INBOUND,
RequestOrResponse.RESPONSE, handlerContext, false);
} catch (SOAPException se) {
throw new WebServiceException(se);
} 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(JAXWS_CLIENT_HANDLE_PROPERTY);
return provider.getBinding();
}
protected HandlerChainCaller getHandlerChainCaller(MessageInfo messageInfo) {
BindingImpl binding = (BindingImpl) getBinding(messageInfo);
return binding.getHandlerChainCaller();
}
private void updateSOAPMessage(Object value, SOAPMessage sm) {
try {
if (value instanceof Source) {
SOAPBody sb = sm.getSOAPPart().getEnvelope().getBody();
sb.removeContents();
XmlUtil.newTransformer().transform((Source) value, new DOMResult(sb));
sm.saveChanges();
}
} catch (SOAPException e) {
throw new RuntimeException(e);
} catch (TransformerException e) {
throw new RuntimeException(e);
}
}
protected void updateMessageContext(MessageInfo messageInfo, SOAPHandlerContext context) {
SOAPMessageContext messageContext = context.getSOAPMessageContext();
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);
}
BindingProvider provider = (BindingProvider) context.getMessageContext()
.get(JAXWS_CLIENT_HANDLE_PROPERTY);
QName portTypeQName = null;
if (provider != null) {
if (Proxy.isProxyClass(provider.getClass())) {
EndpointIFInvocationHandler invocationHandler = (EndpointIFInvocationHandler) Proxy.getInvocationHandler(provider);
EndpointIFContext endpointContext = invocationHandler.getEndpointContext();
portTypeQName = invocationHandler.getWSDLPortTypeQName();
messageContext.put(MessageContext.WSDL_SERVICE, invocationHandler.getServiceQName());
messageContext.put(MessageContext.WSDL_PORT, endpointContext.getPortName());
context.setBindingId(endpointContext.getBindingID().toString());
RuntimeContext rtContext = (RuntimeContext) messageInfo.getMetaData(BindingProviderProperties.JAXWS_RUNTIME_CONTEXT);
if (rtContext != null) { //should never be
RuntimeModel model = rtContext.getModel();
JavaMethod javaMethod = model.getJavaMethod(messageInfo.getMethod());
String opname = javaMethod.getOperationName();
if (portTypeQName != null) {
String tns = portTypeQName.getNamespaceURI();
messageContext.put(MessageContext.WSDL_OPERATION, new QName(tns,opname));
}
}
//set handlerContext
rtContext.setHandlerContext(context);
}
}
//now get value for ContentNegotiation
Object prop = messageInfo.getMetaData(CONTENT_NEGOTIATION_PROPERTY);
if (prop != null) {
messageContext.put(CONTENT_NEGOTIATION_PROPERTY, prop);
}
}
protected void updateResponseContext(MessageInfo messageInfo,
SOAPHandlerContext context) {
SOAPMessageContext messageContext = context.getSOAPMessageContext();
RequestContext rc = (RequestContext) messageInfo.getMetaData(JAXWS_CONTEXT_PROPERTY);
BindingProvider provider = (BindingProvider) rc.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);
}
}
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) {
DispatchContext dispatchContext = (DispatchContext) messageInfo
.getMetaData(BindingProviderProperties.DISPATCH_CONTEXT);
if ((messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.MESSAGE)
&& (dispatchContext.getProperty(DispatchContext.DISPATCH_MESSAGE) == DispatchContext.MessageType.SOURCE_MESSAGE))
{
Object response = messageInfo.getResponse();
if (response instanceof SOAPMessage) {
SOAPPart part = ((SOAPMessage) response).getSOAPPart();
try {
messageInfo.setResponse(part.getContent());
} catch (SOAPException e) {
throw new RuntimeException(e);
}
}
}
}
private void postReceiveHook(MessageInfo messageInfo) {
// postReceiveHook exaimines the result for an exception
// or SOAPFaultInfo - it will set appropriate
// asynchronous exceptions
Object response = messageInfo.getResponse();
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 SOAPFaultInfo) {
SOAPFaultInfo soapFaultInfo = (SOAPFaultInfo) response;
JAXBException jbe = null;
if (soapFaultInfo.getString().contains("javax.xml.bind")) {
jbe = new JAXBException(soapFaultInfo.getString());
// do I need to put this in a jaxws exception
}
SOAPFaultException sfe = new SOAPFaultException(soapFaultInfo.getSOAPFault());
if (jbe != null)
sfe.initCause(jbe);
messageInfo.setResponse((SOAPFaultException) sfe);
}
return;
case MessageStruct.UNCHECKED_EXCEPTION_RESPONSE:
if (response instanceof SOAPFaultException) {
messageInfo.setResponse((SOAPFaultException) response);
} else {
if (response instanceof Exception) {
RuntimeException jex = (RuntimeException) response;
messageInfo.setResponse(jex);
}
}
return;
default:
messageInfo.setResponse(response);
}
}
private InternalMessage preHandlerOutboundHook(SOAPMessage sm, InternalMessage im) {
if ((sm != null) && (im != null))
im = null;
return im;
}
private void postHandlerOutboundHook(MessageInfo messageInfo, SOAPHandlerContext handlerContext, SOAPMessage sm) {
if (messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.MESSAGE)
{
InternalMessage im = handlerContext.getInternalMessage();
if (im != null) {
Object value = im.getBody().getValue();
updateSOAPMessage(value, sm);
im = null;
} else
try {
sm.saveChanges();
} catch (SOAPException e) {
throw new RuntimeException(e);
}
}
}
private void postHandlerInboundHook(MessageInfo messageInfo, SOAPHandlerContext handlerContext, SOAPMessage sm) {
if ((messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.MESSAGE) ||
(messageInfo.getMetaData(DispatchContext.DISPATCH_MESSAGE_MODE) == Service.Mode.PAYLOAD))
{
InternalMessage im = handlerContext.getInternalMessage();
if (im != null) {
Object value = im.getBody().getValue();
updateSOAPMessage(value, sm);
im = null;
} else
try {
sm.saveChanges();
} catch (SOAPException e) {
throw new RuntimeException(e);
}
}
}
private void closeAllHandlers(SOAPHandlerContext 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 SOAP12XMLEncoder)
return SOAPBinding.SOAP12HTTP_BINDING;
else
return SOAPBinding.SOAP11HTTP_BINDING;
}
/**
* Logs the SOAP request message
*/
protected void logRequestMessage(SOAPMessage soapMessage, MessageInfo messageInfo)
throws IOException, SOAPException {
OutputStream out = ((WSConnection) messageInfo.getConnection()).getDebug();
if (out != null) {
String s = "******************\nRequest\n";
out.write(s.getBytes());
for (Iterator iter =
soapMessage.getMimeHeaders().getAllHeaders();
iter.hasNext();
) {
MimeHeader header = (MimeHeader) iter.next();
s = header.getName() + ": " + header.getValue() + "\n";
out.write(s.getBytes());
}
out.flush();
soapMessage.writeTo(out);
s = "\n";
out.write(s.getBytes());
out.flush();
}
}
/**
* Logs the SOAP response message
*/
protected void logResponseMessage(SOAPMessage response, MessageInfo messageInfo)
throws IOException, SOAPException {
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());
}
}
class DaemonThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread daemonThread = new Thread(r);
daemonThread.setDaemon(Boolean.TRUE);
return daemonThread;
}
}
}