blob: 8256e7615f0a3053c21d9e1164b1ace772dbb2ba [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.util;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPConstants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPFault;
import org.apache.axiom.soap.SOAPFaultCode;
import org.apache.axiom.soap.SOAPFaultDetail;
import org.apache.axiom.soap.SOAPFaultReason;
import org.apache.axiom.soap.SOAPFaultSubCode;
import org.apache.axiom.soap.SOAPFaultValue;
import org.apache.axiom.soap.SOAPHeader;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.axiom.soap.SOAPProcessingException;
import org.apache.axiom.soap.SOAPFaultNode;
import org.apache.axiom.util.UIDGenerator;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.addressing.AddressingConstants.Final;
import org.apache.axis2.addressing.AddressingHelper;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.addressing.RelatesTo;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.description.*;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.namespace.QName;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;
public class MessageContextBuilder {
protected static final Log log = LogFactory.getLog(MessageContextBuilder.class);
/**
* Creates a new 'response' message context based on a 'request' message context
* Only deals with properties/fields that are the same for both 'normal' and fault responses.
*
* @param inMessageContext context for which the response will be created
* @return response message context for the given in message context
* @throws org.apache.axis2.AxisFault error in creating the response message context
*/
private static MessageContext createResponseMessageContext(MessageContext inMessageContext)
throws AxisFault {
MessageContext newmsgCtx =
inMessageContext.getConfigurationContext().createMessageContext();
newmsgCtx.setSessionContext(inMessageContext.getSessionContext());
newmsgCtx.setTransportIn(inMessageContext.getTransportIn());
newmsgCtx.setTransportOut(inMessageContext.getTransportOut());
newmsgCtx.setServerSide(inMessageContext.isServerSide());
newmsgCtx.setProperty(MessageContext.IN_MESSAGE_CONTEXT, inMessageContext);
// TODO: Should this be specifying (or defaulting to) the "response" relationshipType??
newmsgCtx.addRelatesTo(new RelatesTo(inMessageContext.getOptions().getMessageId()));
newmsgCtx.setProperty(AddressingConstants.WS_ADDRESSING_VERSION,
inMessageContext.getProperty(
AddressingConstants.WS_ADDRESSING_VERSION));
newmsgCtx.setProperty(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
inMessageContext.getProperty(
AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES));
newmsgCtx.setProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME,
inMessageContext.getProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME));
newmsgCtx.setProperty(Constants.AXIS_BINDING_OPERATION,
inMessageContext.getProperty(Constants.AXIS_BINDING_OPERATION));
// Setting the charater set encoding
newmsgCtx.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING,
inMessageContext.getProperty(
Constants.Configuration.CHARACTER_SET_ENCODING));
//Setting the message type property
newmsgCtx.setProperty(Constants.Configuration.MESSAGE_TYPE,
inMessageContext.getProperty(Constants.Configuration.MESSAGE_TYPE));
newmsgCtx.setDoingREST(inMessageContext.isDoingREST());
newmsgCtx.setOperationContext(inMessageContext.getOperationContext());
newmsgCtx.setProperty(MessageContext.TRANSPORT_OUT,
inMessageContext.getProperty(MessageContext.TRANSPORT_OUT));
newmsgCtx.setProperty(Constants.OUT_TRANSPORT_INFO,
inMessageContext.getProperty(Constants.OUT_TRANSPORT_INFO));
handleCorrelationID(inMessageContext,newmsgCtx);
return newmsgCtx;
}
/**
* Creates a MessageContext for use with a non-fault response based on an request MessageContext
*
* @param inMessageContext for the out message context to be created
* @return created out message context from the given in message context
* @throws org.apache.axis2.AxisFault error in creating the out message context
*/
public static MessageContext createOutMessageContext(MessageContext inMessageContext)
throws AxisFault {
// Create a basic response MessageContext with basic fields copied
MessageContext newmsgCtx = createResponseMessageContext(inMessageContext);
// Simple response so set To to value of inbound ReplyTo
newmsgCtx.setTo(inMessageContext.getReplyTo());
if (newmsgCtx.getTo() == null) {
newmsgCtx.setTo(new EndpointReference(AddressingConstants.Final.WSA_ANONYMOUS_URL));
}
// do Target Resolution
TargetResolver targetResolver =
newmsgCtx.getConfigurationContext().getAxisConfiguration().getTargetResolverChain();
if (targetResolver != null) {
targetResolver.resolveTarget(newmsgCtx);
}
// Determine ReplyTo for response message.
AxisService axisService = inMessageContext.getAxisService();
if (axisService != null && Constants.SCOPE_SOAP_SESSION.equals(axisService.getScope())) {
//If the wsa 2004/08 (submission) spec is in effect use the wsa anonymous URI as the default replyTo value.
//This is necessary because the wsa none URI is not available in that spec.
Object version = inMessageContext.getProperty(AddressingConstants.WS_ADDRESSING_VERSION);
if (AddressingConstants.Submission.WSA_NAMESPACE.equals(version)) {
newmsgCtx.setReplyTo(
new EndpointReference(AddressingConstants.Submission.WSA_ANONYMOUS_URL));
} else {
newmsgCtx.setReplyTo(new EndpointReference(AddressingConstants.Final.WSA_NONE_URI));
}
newmsgCtx.setMessageID(UIDGenerator.generateURNString());
// add the service group id as a reference parameter
String serviceGroupContextId = inMessageContext.getServiceGroupContextId();
if (serviceGroupContextId != null && !"".equals(serviceGroupContextId)) {
EndpointReference replyToEPR = newmsgCtx.getReplyTo();
replyToEPR.addReferenceParameter(new QName(Constants.AXIS2_NAMESPACE_URI,
Constants.SERVICE_GROUP_ID,
Constants.AXIS2_NAMESPACE_PREFIX),
serviceGroupContextId);
}
} else {
EndpointReference outboundToEPR = newmsgCtx.getTo();
Object version = newmsgCtx.getProperty(AddressingConstants.WS_ADDRESSING_VERSION);
if (AddressingConstants.Submission.WSA_NAMESPACE.equals(version) ||
(outboundToEPR != null && !outboundToEPR.hasAnonymousAddress())) {
newmsgCtx.setMessageID(UIDGenerator.generateURNString());
newmsgCtx.setReplyTo(new EndpointReference(AddressingConstants.Final.WSA_NONE_URI));
}
}
// Set wsa:Action for response message
// Use specified value if available
AxisOperation ao = inMessageContext.getAxisOperation();
if ((ao != null) && (ao.getOutputAction() != null)) {
newmsgCtx.setWSAAction(ao.getOutputAction());
} else { // If not, simply copy the request value. Almost always invalid.
newmsgCtx.setWSAAction(inMessageContext.getWSAAction());
}
if (ao != null){
newmsgCtx.setAxisMessage(ao.getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE));
}
// setting the out bound binding message
AxisBindingMessage inboundAxisBindingMessage
= (AxisBindingMessage)inMessageContext.getProperty(Constants.AXIS_BINDING_MESSAGE);
if (inboundAxisBindingMessage != null){
AxisBindingOperation axisBindingOperation = inboundAxisBindingMessage.getAxisBindingOperation();
newmsgCtx.setProperty(Constants.AXIS_BINDING_MESSAGE,
axisBindingOperation.getChild(WSDLConstants.MESSAGE_LABEL_OUT_VALUE));
}
newmsgCtx.setDoingMTOM(inMessageContext.isDoingMTOM());
newmsgCtx.setDoingSwA(inMessageContext.isDoingSwA());
newmsgCtx.setServiceGroupContextId(inMessageContext.getServiceGroupContextId());
// Ensure transport settings match the scheme for the To EPR
setupCorrectTransportOut(newmsgCtx);
return newmsgCtx;
}
/**
* Copies the correlation id (jms) from the in message ctx
* to the out message ctx. Currently this check is for jms
* only, but can be expanded to other transports if the need
* arises.
*/
private static void handleCorrelationID(MessageContext inMessageContext,MessageContext outMessageContext)
{
if (inMessageContext.getIncomingTransportName()!= null &&
inMessageContext.getIncomingTransportName().equals(Constants.TRANSPORT_JMS))
{
log.debug("Incoming Transport is JMS, lets check for JMS correlation id");
String correlationId =
(String) inMessageContext.getProperty(Constants.JMS_COORELATION_ID);
log.debug("Correlation id is " + correlationId);
if (correlationId != null && correlationId.length() > 0) {
outMessageContext.setProperty(Constants.JMS_COORELATION_ID, correlationId);
}
}
}
/**
* This method is called to handle any error that occurs at inflow or outflow. But if the
* method is called twice, it implies that sending the error handling has failed, in which case
* the method logs the error and exits.
*/
public static MessageContext createFaultMessageContext(MessageContext processingContext,
Throwable e)
throws AxisFault {
if (processingContext.isProcessingFault()) {
// We get the error file processing the fault. nothing we can do
throw new AxisFault(Messages.getMessage("errorwhileProcessingFault"));
}
// See if the throwable is an AxisFault and if it already contains the
// fault MessageContext
if (e instanceof AxisFault) {
MessageContext faultMessageContext = ((AxisFault) e).getFaultMessageContext();
if (faultMessageContext != null) {
// These may not have been set correctly when the original context
// was created -- an example of this is with the SimpleHTTPServer.
// I'm not sure if this is the correct thing to do, or if the
// code that created this context in the first place should
// expect that the transport out info was set correctly, as
// it may need to use that info at some point before we get to
// this code.
faultMessageContext.setProperty(MessageContext.TRANSPORT_OUT,
processingContext.getProperty(
MessageContext.TRANSPORT_OUT));
faultMessageContext.setProperty(Constants.OUT_TRANSPORT_INFO,
processingContext.getProperty(
Constants.OUT_TRANSPORT_INFO));
faultMessageContext.setProperty(MessageContext.IN_MESSAGE_CONTEXT, processingContext);
faultMessageContext.setProcessingFault(true);
return faultMessageContext;
}
}
// Create a basic response MessageContext with basic fields copied
MessageContext faultContext = createResponseMessageContext(processingContext);
// Register the fault message context
OperationContext operationContext = processingContext.getOperationContext();
if (operationContext != null) {
processingContext.getAxisOperation().addFaultMessageContext(faultContext,
operationContext);
}
faultContext.setProcessingFault(true);
// Set wsa:Action for response message
// Use specified value if available
String faultAction = (e instanceof AxisFault) ? ((AxisFault)e).getFaultAction() : null;
if (faultAction == null) {
AxisOperation op = processingContext.getAxisOperation();
if (op != null && op.getFaultAction() != null) {
// TODO: Should the op be able to pick a fault action based on the fault?
faultAction = op.getFaultAction();
} else { //If, for some reason there is no value set, should use a sensible action.
faultAction = Final.WSA_SOAP_FAULT_ACTION;
}
}
faultContext.setWSAAction(faultAction);
// there are some information that the fault thrower wants to pass to the fault path.
// Means that the fault is a ws-addressing one hence use the ws-addressing fault action.
Object faultInfoForHeaders =
processingContext.getLocalProperty(Constants.FAULT_INFORMATION_FOR_HEADERS);
if (faultInfoForHeaders != null) {
faultContext.setProperty(Constants.FAULT_INFORMATION_FOR_HEADERS, faultInfoForHeaders);
// Note that this overrides any action set above
faultContext.setWSAAction(Final.WSA_FAULT_ACTION);
}
// if the exception is due to a problem in the faultTo header itself, we can not use that
// fault information to send the error. Try to send using replyTo, else leave it to transport
boolean shouldSendFaultToFaultTo =
AddressingHelper.shouldSendFaultToFaultTo(processingContext);
EndpointReference faultTo = processingContext.getFaultTo();
if (faultTo != null && shouldSendFaultToFaultTo) {
faultContext.setTo(faultTo);
} else {
faultContext.setTo(processingContext.getReplyTo());
}
if (faultContext.getTo() == null) {
faultContext.setTo(new EndpointReference(AddressingConstants.Final.WSA_ANONYMOUS_URL));
}
// Not worth setting up the session information on a fault flow
EndpointReference outboundToEPR = faultContext.getTo();
Object version = faultContext.getProperty(AddressingConstants.WS_ADDRESSING_VERSION);
if (AddressingConstants.Submission.WSA_NAMESPACE.equals(version) ||
(outboundToEPR != null && !outboundToEPR.hasAnonymousAddress())) {
faultContext.setMessageID(UIDGenerator.generateURNString());
faultContext.setReplyTo(new EndpointReference(AddressingConstants.Final.WSA_NONE_URI));
}
// do Target Resolution
TargetResolver targetResolver = faultContext.getConfigurationContext()
.getAxisConfiguration().getTargetResolverChain();
if (targetResolver != null) {
targetResolver.resolveTarget(faultContext);
}
// Ensure transport settings match the scheme for the To EPR
setupCorrectTransportOut(faultContext);
SOAPEnvelope envelope = createFaultEnvelope(processingContext, e);
faultContext.setEnvelope(envelope);
//get the SOAP headers, user is trying to send in the fault
// TODO: Rationalize this mechanism a bit - maybe headers should live in the fault?
List soapHeadersList =
(List) processingContext.getProperty(SOAPConstants.HEADER_LOCAL_NAME);
if (soapHeadersList != null) {
SOAPHeader soapHeaderElement = envelope.getHeader();
for (Object aSoapHeadersList : soapHeadersList) {
OMElement soapHeaderBlock = (OMElement)aSoapHeadersList;
soapHeaderElement.addChild(soapHeaderBlock);
}
}
// TODO: Transport-specific stuff in here? Why? Is there a better way?
// now add HTTP Headers
faultContext.setProperty(HTTPConstants.HTTP_HEADERS,
processingContext.getProperty(HTTPConstants.HTTP_HEADERS));
//setting the out bound binding message
AxisBindingMessage inboundAxisBindingMessage
= (AxisBindingMessage)processingContext.getProperty(Constants.AXIS_BINDING_MESSAGE);
if (inboundAxisBindingMessage != null){
AxisBindingOperation axisBindingOperation = inboundAxisBindingMessage.getAxisBindingOperation();
faultContext.setProperty(Constants.AXIS_BINDING_MESSAGE,
axisBindingOperation.getChild(WSDLConstants.MESSAGE_LABEL_OUT_VALUE));
}
return faultContext;
}
/**
* Ensure that if the scheme of the To EPR for the response is different than the
* transport used for the request that the correct TransportOut is available
*/
private static void setupCorrectTransportOut(MessageContext context) throws AxisFault {
// Determine that we have the correct transport available.
TransportOutDescription transportOut = context.getTransportOut();
try {
EndpointReference responseEPR = context.getTo();
if (context.isServerSide() && responseEPR != null) {
if (!responseEPR.hasAnonymousAddress() && !responseEPR.hasNoneAddress()) {
URI uri = new URI(responseEPR.getAddress());
String scheme = uri.getScheme();
if ((transportOut == null) || !transportOut.getName().equals(scheme)) {
ConfigurationContext configurationContext =
context.getConfigurationContext();
transportOut = configurationContext.getAxisConfiguration()
.getTransportOut(scheme);
if (transportOut == null) {
throw new AxisFault("Can not find the transport sender : " + scheme);
}
context.setTransportOut(transportOut);
}
if (context.getOperationContext() != null) {
context.getOperationContext().setProperty(
Constants.DIFFERENT_EPR, Constants.VALUE_TRUE);
}
}
}
} catch (URISyntaxException urise) {
throw AxisFault.makeFault(urise);
}
}
/**
* Information to create the SOAPFault can be extracted from different places.
* 1. Those information may have been put in to the message context by some handler. When someone
* is putting like that, he must make sure the SOAPElements he is putting must be from the
* correct SOAP Version.
* 2. SOAPProcessingException is flexible enough to carry information about the fault. For example
* it has an attribute to store the fault code. The fault reason can be extracted from the
* message of the exception. I opted to put the stacktrace under the detail element.
* eg : <Detail>
* <Exception> stack trace goes here </Exception>
* <Detail>
* <p/>
* If those information can not be extracted from any of the above places, I default the soap
* fault values to following.
* <Fault>
* <Code>
* <Value>env:Receiver</Value>
* </Code>
* <Reason>
* <Text>unknown</Text>
* </Reason>
* <Role/>
* <Node/>
* <Detail/>
* </Fault>
* <p/>
* -- EC
*
* @param context
* @param e
*/
private static SOAPEnvelope createFaultEnvelope(MessageContext context, Throwable e) {
SOAPEnvelope envelope;
if(log.isDebugEnabled()){
log.debug("start createFaultEnvelope()");
}
if (context.isSOAP11()) {
envelope = OMAbstractFactory.getSOAP11Factory().getDefaultFaultEnvelope();
} else {
// Following will make SOAP 1.2 as the default, too.
envelope = OMAbstractFactory.getSOAP12Factory().getDefaultFaultEnvelope();
}
SOAPFault fault = envelope.getBody().getFault();
SOAPProcessingException soapException = null;
AxisFault axisFault = null;
if (e == null) return envelope;
if (e instanceof AxisFault) {
axisFault = (AxisFault) e;
} else if (e.getCause() instanceof AxisFault) {
axisFault = (AxisFault) e.getCause();
}
if (axisFault != null) {
Iterator iter = axisFault.headerIterator();
while (iter.hasNext()) {
SOAPHeaderBlock header = (SOAPHeaderBlock) iter.next();
envelope.getHeader().addChild(header);
}
}
if (e instanceof SOAPProcessingException) {
soapException = (SOAPProcessingException) e;
} else if (axisFault != null) {
if (axisFault.getCause() instanceof SOAPProcessingException) {
soapException = (SOAPProcessingException) axisFault.getCause();
}
}
// user can set the fault information to the message context or to the AxisFault itself.
// whatever user sets to the message context, supercedes eerything.
Object faultCode = context.getProperty(SOAP12Constants.SOAP_FAULT_CODE_LOCAL_NAME);
String soapFaultCode = "";
if (faultCode != null) {
if(log.isDebugEnabled()){
log.debug("faultCode != null");
}
fault.setCode((SOAPFaultCode) faultCode);
soapFaultCode = ((SOAPFaultCode) faultCode).getText();
} else if (soapException != null) {
if(log.isDebugEnabled()){
log.debug("soapException != null");
}
soapFaultCode = soapException.getFaultCode();
OMNamespace namespace = null;
if(envelope!=null){
if(log.isDebugEnabled()){
log.debug("envelope!=null");
}
namespace = envelope.getNamespace();
}
if (namespace != null){
String sfcLocalPart = soapFaultCode.substring(soapFaultCode.lastIndexOf(":")+1);
//If the fault code is one of the predefined ones that make sure the prefix
//matches that of the envelope NS
if (sfcLocalPart.equals(SOAPConstants.FAULT_CODE_VERSION_MISMATCH) ||
sfcLocalPart.equals(SOAPConstants.FAULT_CODE_MUST_UNDERSTAND) ||
sfcLocalPart.equals(SOAPConstants.FAULT_CODE_DATA_ENCODING_UNKNOWN) ||
sfcLocalPart.equals(SOAPConstants.FAULT_CODE_RECEIVER) ||
sfcLocalPart.equals(SOAPConstants.FAULT_CODE_SENDER)) {
if(log.isDebugEnabled()){
log.debug("SoapFaultCode local part= " +sfcLocalPart);
}
String prefix = namespace.getPrefix() + ":";
if (!soapFaultCode.contains(":")) {
soapFaultCode = prefix + soapFaultCode;
} else {
soapFaultCode = prefix + soapFaultCode.substring(soapFaultCode.indexOf(":")+1);
}
if(log.isDebugEnabled()){
log.debug("SoapFaultCode reset to " +soapFaultCode);
}
}
} else {
if(log.isDebugEnabled()){
log.debug("Namespace is null, cannot attach prefix to SOAPFaultCode");
}
}
if(log.isDebugEnabled()){
log.debug("SoapFaultCode ="+soapFaultCode);
}
} else if (axisFault != null) {
if(log.isDebugEnabled()){
log.debug("axisFault != null");
}
if (axisFault.getFaultCodeElement() != null) {
fault.setCode(axisFault.getFaultCodeElement());
soapFaultCode = axisFault.getFaultCodeElement().getText();
} else {
QName faultCodeQName = axisFault.getFaultCode();
if (faultCodeQName != null) {
if(log.isDebugEnabled()){
log.debug("prefix ="+faultCodeQName.getPrefix());
log.debug("Fault Code namespace ="+faultCodeQName.getNamespaceURI());
log.debug("Fault Code ="+faultCodeQName.getLocalPart());
}
if (faultCodeQName.getLocalPart().indexOf(":") == -1) {
if(log.isDebugEnabled()){
log.debug("faultCodeQName.getLocalPart().indexOf(\":\") == -1");
}
String prefix = faultCodeQName.getPrefix();
if(log.isDebugEnabled()){
log.debug("prefix = "+prefix);
}
String uri = faultCodeQName.getNamespaceURI();
// Get the specified uri
uri = uri == null || "" .equals(uri) ?
fault.getNamespace().getNamespaceURI() : uri;
// Make sure the prefix and uri are declared on the fault, and
// get the resulting prefix. If no prefix is defined, let declareNamespace
// generate one.
prefix = fault.declareNamespace(uri, prefix.length() == 0 ? null : prefix).getPrefix();
soapFaultCode = prefix + ":" + faultCodeQName.getLocalPart();
if(log.isDebugEnabled()){
log.debug("Altered soapFaultCode ="+soapFaultCode);
}
} else {
soapFaultCode = faultCodeQName.getLocalPart();
}
}
}
}
// defaulting to fault code Receiver, if no message is available
if (faultCode == null && context.getEnvelope() != null) {
soapFaultCode = ("".equals(soapFaultCode) || (soapFaultCode == null))
? SOAP12Constants.SOAP_DEFAULT_NAMESPACE_PREFIX + ":" +
context.getEnvelope().getVersion().getReceiverFaultCode().getLocalPart()
: soapFaultCode;
}
if (faultCode == null) {
if(log.isDebugEnabled()){
log.debug("faultCode == null");
}
if (context.isSOAP11()) {
if(log.isDebugEnabled()){
log.debug("context.isSOAP11() = true");
SOAPFaultCode code = (fault!=null)?fault.getCode():null;
SOAPFaultValue value = (code!=null)?code.getValue():null;
if(value !=null){
QName name = value.getQName();
log.debug("prefix ="+name.getPrefix());
log.debug("Fault Code namespace ="+name.getNamespaceURI());
log.debug("Fault Code ="+name.getLocalPart());
}
}
fault.getCode().setText(soapFaultCode);
} else {
if(log.isDebugEnabled()){
log.debug("context.isSOAP11() = false");
SOAPFaultCode code = (fault!=null)?fault.getCode():null;
SOAPFaultValue value = (code!=null)?code.getValue():null;
if(value !=null){
QName name = value.getQName();
log.debug("prefix ="+name.getPrefix());
log.debug("Fault Code namespace ="+name.getNamespaceURI());
log.debug("Fault Code ="+name.getLocalPart());
}
}
SOAPFaultValue value = fault.getCode().getValue();
if(log.isDebugEnabled()){
log.debug("soapFaultCode originally was set to : " + soapFaultCode);
}
OMNamespace namespace = value.getNamespace();
soapFaultCode = switchNamespacePrefix(soapFaultCode, namespace);
value.setText(soapFaultCode);
}
}
if (axisFault != null && !context.isSOAP11()) {
if (axisFault.getFaultSubCodes() != null) {
List faultSubCodes = axisFault.getFaultSubCodes();
QName faultSubCodeQName;
for (Object faultSubCode : faultSubCodes) {
faultSubCodeQName = (QName)faultSubCode;
SOAPFactory sf = (SOAPFactory)envelope.getOMFactory();
SOAPFaultSubCode soapFaultSubCode = sf.createSOAPFaultSubCode(fault.getCode());
SOAPFaultValue saopFaultValue = sf.createSOAPFaultValue(fault.getCode());
saopFaultValue.setText(faultSubCodeQName);
soapFaultSubCode.setValue(saopFaultValue);
fault.getCode().setSubCode(soapFaultSubCode);
}
}
}
SOAPFaultReason faultReason = (SOAPFaultReason)context.getProperty(
SOAP12Constants.SOAP_FAULT_REASON_LOCAL_NAME);
if (faultReason == null && axisFault != null) {
faultReason = axisFault.getFaultReasonElement();
}
if (faultReason != null) {
fault.setReason(faultReason);
} else {
String message = "";
if (soapException != null) {
message = soapException.getMessage();
} else if (axisFault != null) {
// Couldn't find FaultReasonElement, try reason string
message = axisFault.getReason();
}
if (message == null || "".equals(message)) {
message = getFaultReasonFromException(e, context);
}
if (message == null || "".equals(message)) message = "unknown";
if (context.isSOAP11()) {
fault.getReason().setText(message);
} else {
fault.getReason().getFirstSOAPText().setLang("en-US");
fault.getReason().getFirstSOAPText().setText(message);
}
}
Object faultRole = context.getProperty(SOAP12Constants.SOAP_FAULT_ROLE_LOCAL_NAME);
if (faultRole != null) {
fault.getRole().setText((String) faultRole);
} else if (axisFault != null) {
if (axisFault.getFaultRoleElement() != null) {
fault.setRole(axisFault.getFaultRoleElement());
}
}
Object faultNode = context.getProperty(SOAP12Constants.SOAP_FAULT_NODE_LOCAL_NAME);
if (faultNode != null) {
SOAPFaultNode soapFaultNode = fault.getNode();
if(soapFaultNode != null) {
soapFaultNode.setText((String) faultNode);
}
} else if (axisFault != null) {
if (axisFault.getFaultNodeElement() != null) {
fault.setNode(axisFault.getFaultNodeElement());
}
}
// Allow handlers to override the sendStacktraceDetailsWithFaults setting from the Configuration to allow
// WS-* protocol faults to not include the exception.
boolean sendStacktraceDetailsWithFaults = false;
OperationContext oc = context.getOperationContext();
Object flagFromContext = null;
if (oc != null) {
flagFromContext = context.getOperationContext()
.getProperty(Constants.Configuration.SEND_STACKTRACE_DETAILS_WITH_FAULTS);
}
if (flagFromContext != null) {
sendStacktraceDetailsWithFaults = JavaUtils.isTrue(flagFromContext);
} else {
Parameter param = context.getParameter(
Constants.Configuration.SEND_STACKTRACE_DETAILS_WITH_FAULTS);
if (param != null) {
sendStacktraceDetailsWithFaults = JavaUtils.isTrue(param.getValue());
}
}
Object faultDetail = context.getProperty(SOAP12Constants.SOAP_FAULT_DETAIL_LOCAL_NAME);
if (faultDetail != null) {
fault.setDetail((SOAPFaultDetail) faultDetail);
} else if (axisFault != null) {
if (axisFault.getFaultDetailElement() != null) {
fault.setDetail(axisFault.getFaultDetailElement());
} else {
OMElement detail = axisFault.getDetail();
if (detail != null) {
fault.getDetail().addDetailEntry(detail);
} else if (sendStacktraceDetailsWithFaults) {
fault.setException(axisFault);
}
}
} else if (fault.getException() == null && sendStacktraceDetailsWithFaults) {
if (e instanceof Exception) {
fault.setException((Exception) e);
} else {
fault.setException(new Exception(e));
}
}
if(log.isDebugEnabled())
log.debug("End createFaultEnvelope()");
return envelope;
}
/**
* Switch the namespace prefix in the soap fault code. It should match the prefix used
* by the outgoing soap envelope.
*
* @param soapFaultCode
* @param namespace
* @return
*/
public static String switchNamespacePrefix(String soapFaultCode, OMNamespace namespace) {
if(soapFaultCode != null &&
soapFaultCode.endsWith(":" + SOAPConstants.FAULT_CODE_VERSION_MISMATCH)) {
String prefix = namespace.getPrefix();
if(log.isDebugEnabled()){
log.debug("prefix being used in the outgoing soap envelope is : " + prefix);
}
// The following methods set the prefix of the incoming soap envelope in soapFaultCode
// validateSOAPVersion method in BuilderUtil or
// identifySOAPVersion method in StAXSOAPModelBuilder
// But the outgoing envelope may have a different prefix, if it does then
// we need to strip the prefix set by those methods and add the
// correct one.
if (!soapFaultCode.startsWith(prefix + ":")) {
if(log.isDebugEnabled()){
log.debug("stripping old prefix and adding the new one - " + prefix);
}
// Strip the original prefix
int index = soapFaultCode.indexOf(':') + 1;
soapFaultCode = soapFaultCode.substring(index);
// Use the correct prefix for the outgoing soap envelope namespace
soapFaultCode = prefix + ":" + soapFaultCode;
}
}
if(log.isDebugEnabled()){
log.debug("soapFaultCode is being set to : " + soapFaultCode);
}
return soapFaultCode;
}
/**
* By the time the exception comes here it can be wrapped by so many levels. This will crip down
* to the root cause and get the initial error depending on the property
*
* @param e exception to get the string representation
* @param context current message context for which the exception occurred
* @return generated fault reason as a string
*/
private static String getFaultReasonFromException(Throwable e, MessageContext context) {
Throwable throwable = e;
Parameter param = context.getParameter(
Constants.Configuration.DRILL_DOWN_TO_ROOT_CAUSE_FOR_FAULT_REASON);
boolean drillDownToRootCauseForFaultReason =
param != null && ((String) param.getValue()).equalsIgnoreCase("true");
if (drillDownToRootCauseForFaultReason) {
while (throwable.getCause() != null) {
throwable = throwable.getCause();
}
}
return throwable.getMessage();
}
}