001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.util;
021:
022: import org.apache.axiom.om.OMAbstractFactory;
023: import org.apache.axiom.om.OMElement;
024: import org.apache.axiom.om.OMNamespace;
025: import org.apache.axiom.om.util.UUIDGenerator;
026: import org.apache.axiom.soap.SOAP11Constants;
027: import org.apache.axiom.soap.SOAP12Constants;
028: import org.apache.axiom.soap.SOAPConstants;
029: import org.apache.axiom.soap.SOAPEnvelope;
030: import org.apache.axiom.soap.SOAPFault;
031: import org.apache.axiom.soap.SOAPFaultCode;
032: import org.apache.axiom.soap.SOAPFaultDetail;
033: import org.apache.axiom.soap.SOAPFaultReason;
034: import org.apache.axiom.soap.SOAPHeader;
035: import org.apache.axiom.soap.SOAPHeaderBlock;
036: import org.apache.axiom.soap.SOAPProcessingException;
037: import org.apache.axis2.AxisFault;
038: import org.apache.axis2.Constants;
039: import org.apache.axis2.addressing.AddressingConstants;
040: import org.apache.axis2.addressing.AddressingConstants.Final;
041: import org.apache.axis2.addressing.AddressingHelper;
042: import org.apache.axis2.addressing.EndpointReference;
043: import org.apache.axis2.addressing.RelatesTo;
044: import org.apache.axis2.context.ConfigurationContext;
045: import org.apache.axis2.context.MessageContext;
046: import org.apache.axis2.context.OperationContext;
047: import org.apache.axis2.context.ServiceContext;
048: import org.apache.axis2.description.AxisOperation;
049: import org.apache.axis2.description.AxisService;
050: import org.apache.axis2.description.Parameter;
051: import org.apache.axis2.description.TransportOutDescription;
052: import org.apache.axis2.description.WSDL2Constants;
053: import org.apache.axis2.i18n.Messages;
054: import org.apache.axis2.transport.http.HTTPConstants;
055: import org.apache.axis2.transport.jms.JMSConstants;
056: import org.apache.axis2.wsdl.WSDLConstants;
057: import org.apache.commons.logging.Log;
058: import org.apache.commons.logging.LogFactory;
059:
060: import javax.xml.namespace.QName;
061: import java.net.URI;
062: import java.net.URISyntaxException;
063: import java.util.Iterator;
064: import java.util.List;
065:
066: public class MessageContextBuilder {
067:
068: protected static final Log log = LogFactory
069: .getLog(MessageContextBuilder.class);
070:
071: /**
072: * Creates a new 'response' message context based on a 'request' message context
073: * Only deals with properties/fields that are the same for both 'normal' and fault responses.
074: */
075: private static MessageContext createResponseMessageContext(
076: MessageContext inMessageContext) throws AxisFault {
077: MessageContext newmsgCtx = inMessageContext
078: .getConfigurationContext().createMessageContext();
079:
080: newmsgCtx.setSessionContext(inMessageContext
081: .getSessionContext());
082: newmsgCtx.setTransportIn(inMessageContext.getTransportIn());
083: newmsgCtx.setTransportOut(inMessageContext.getTransportOut());
084: newmsgCtx.setServerSide(inMessageContext.isServerSide());
085:
086: // TODO: Should this be specifying (or defaulting to) the "response" relationshipType??
087: newmsgCtx.addRelatesTo(new RelatesTo(inMessageContext
088: .getOptions().getMessageId()));
089:
090: newmsgCtx
091: .setProperty(
092: AddressingConstants.WS_ADDRESSING_VERSION,
093: inMessageContext
094: .getProperty(AddressingConstants.WS_ADDRESSING_VERSION));
095: newmsgCtx
096: .setProperty(
097: AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
098: inMessageContext
099: .getProperty(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES));
100:
101: newmsgCtx
102: .setProperty(
103: WSDL2Constants.ENDPOINT_LOCAL_NAME,
104: inMessageContext
105: .getProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME));
106: newmsgCtx.setProperty(Constants.AXIS_BINDING_OPERATION,
107: inMessageContext
108: .getProperty(Constants.AXIS_BINDING_OPERATION));
109:
110: // Setting the charater set encoding
111: newmsgCtx
112: .setProperty(
113: Constants.Configuration.CHARACTER_SET_ENCODING,
114: inMessageContext
115: .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING));
116: //Setting the message type property
117: newmsgCtx
118: .setProperty(
119: Constants.Configuration.MESSAGE_TYPE,
120: inMessageContext
121: .getProperty(Constants.Configuration.MESSAGE_TYPE));
122: newmsgCtx.setDoingREST(inMessageContext.isDoingREST());
123:
124: newmsgCtx.setOperationContext(inMessageContext
125: .getOperationContext());
126:
127: newmsgCtx.setProperty(MessageContext.TRANSPORT_OUT,
128: inMessageContext
129: .getProperty(MessageContext.TRANSPORT_OUT));
130: newmsgCtx.setProperty(Constants.OUT_TRANSPORT_INFO,
131: inMessageContext
132: .getProperty(Constants.OUT_TRANSPORT_INFO));
133:
134: handleCorrelationID(inMessageContext, newmsgCtx);
135: return newmsgCtx;
136: }
137:
138: /**
139: * Creates a MessageContext for use with a non-fault response based on an request MessageContext
140: */
141: public static MessageContext createOutMessageContext(
142: MessageContext inMessageContext) throws AxisFault {
143:
144: // Create a basic response MessageContext with basic fields copied
145: MessageContext newmsgCtx = createResponseMessageContext(inMessageContext);
146:
147: // Simple response so set To to value of inbound ReplyTo
148: newmsgCtx.setTo(inMessageContext.getReplyTo());
149: if (newmsgCtx.getTo() == null) {
150: newmsgCtx.setTo(new EndpointReference(
151: AddressingConstants.Final.WSA_ANONYMOUS_URL));
152: }
153:
154: // do Target Resolution
155: TargetResolver targetResolver = newmsgCtx
156: .getConfigurationContext().getAxisConfiguration()
157: .getTargetResolverChain();
158: if (targetResolver != null) {
159: targetResolver.resolveTarget(newmsgCtx);
160: }
161:
162: // Determine ReplyTo for response message.
163: AxisService axisService = inMessageContext.getAxisService();
164: if (axisService != null
165: && Constants.SCOPE_SOAP_SESSION.equals(axisService
166: .getScope())) {
167: //If the wsa 2004/08 (submission) spec is in effect use the wsa anonymous URI as the default replyTo value.
168: //This is necessary because the wsa none URI is not available in that spec.
169: Object version = inMessageContext
170: .getProperty(AddressingConstants.WS_ADDRESSING_VERSION);
171: if (AddressingConstants.Submission.WSA_NAMESPACE
172: .equals(version)) {
173: newmsgCtx
174: .setReplyTo(new EndpointReference(
175: AddressingConstants.Submission.WSA_ANONYMOUS_URL));
176: } else {
177: newmsgCtx.setReplyTo(new EndpointReference(
178: AddressingConstants.Final.WSA_NONE_URI));
179: }
180:
181: newmsgCtx.setMessageID(UUIDGenerator.getUUID());
182:
183: // add the service group id as a reference parameter
184: String serviceGroupContextId = inMessageContext
185: .getServiceGroupContextId();
186: if (serviceGroupContextId != null
187: && !"".equals(serviceGroupContextId)) {
188: EndpointReference replyToEPR = newmsgCtx.getReplyTo();
189: replyToEPR.addReferenceParameter(new QName(
190: Constants.AXIS2_NAMESPACE_URI,
191: Constants.SERVICE_GROUP_ID,
192: Constants.AXIS2_NAMESPACE_PREFIX),
193: serviceGroupContextId);
194: }
195: } else {
196: EndpointReference outboundToEPR = newmsgCtx.getTo();
197: Object version = newmsgCtx
198: .getProperty(AddressingConstants.WS_ADDRESSING_VERSION);
199: if (AddressingConstants.Submission.WSA_NAMESPACE
200: .equals(version)
201: || (outboundToEPR != null && !outboundToEPR
202: .hasAnonymousAddress())) {
203: newmsgCtx.setMessageID(UUIDGenerator.getUUID());
204: newmsgCtx.setReplyTo(new EndpointReference(
205: AddressingConstants.Final.WSA_NONE_URI));
206: }
207: }
208:
209: // Set wsa:Action for response message
210: // Use specified value if available
211: AxisOperation ao = inMessageContext.getAxisOperation();
212: if ((ao != null) && (ao.getOutputAction() != null)) {
213: newmsgCtx.setWSAAction(ao.getOutputAction());
214: } else { // If not, simply copy the request value. Almost always invalid.
215: newmsgCtx.setWSAAction(inMessageContext.getWSAAction());
216: }
217:
218: if (ao != null)
219: newmsgCtx.setAxisMessage(ao
220: .getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE));
221:
222: newmsgCtx.setDoingMTOM(inMessageContext.isDoingMTOM());
223: newmsgCtx.setDoingSwA(inMessageContext.isDoingSwA());
224: newmsgCtx.setServiceGroupContextId(inMessageContext
225: .getServiceGroupContextId());
226:
227: // Ensure transport settings match the scheme for the To EPR
228: setupCorrectTransportOut(newmsgCtx);
229: return newmsgCtx;
230: }
231:
232: /**
233: * Copies the correlation id (jms) from the in message ctx
234: * to the out message ctx. Currently this check is for jms
235: * only, but can be expanded to other transports if the need
236: * arises.
237: */
238: private static void handleCorrelationID(
239: MessageContext inMessageContext,
240: MessageContext outMessageContext) {
241: if (inMessageContext.getIncomingTransportName() != null
242: && inMessageContext.getIncomingTransportName().equals(
243: Constants.TRANSPORT_JMS)) {
244: log
245: .debug("Incoming Transport is JMS, lets check for JMS correlation id");
246:
247: String correlationId = (String) inMessageContext
248: .getProperty(JMSConstants.JMS_COORELATION_ID);
249: log.debug("Correlation id is " + correlationId);
250: if (correlationId != null && correlationId.length() > 0) {
251: outMessageContext.setProperty(
252: JMSConstants.JMS_COORELATION_ID, correlationId);
253: }
254: }
255: }
256:
257: /**
258: * This method is called to handle any error that occurs at inflow or outflow. But if the
259: * method is called twice, it implies that sending the error handling has failed, in which case
260: * the method logs the error and exits.
261: */
262: public static MessageContext createFaultMessageContext(
263: MessageContext processingContext, Throwable e)
264: throws AxisFault {
265: if (processingContext.isProcessingFault()) {
266: // We get the error file processing the fault. nothing we can do
267: throw new AxisFault(Messages
268: .getMessage("errorwhileProcessingFault"));
269: }
270:
271: // See if the throwable is an AxisFault and if it already contains the
272: // fault MessageContext
273: if (e instanceof AxisFault) {
274: MessageContext faultMessageContext = ((AxisFault) e)
275: .getFaultMessageContext();
276: if (faultMessageContext != null) {
277: // These may not have been set correctly when the original context
278: // was created -- an example of this is with the SimpleHTTPServer.
279: // I'm not sure if this is the correct thing to do, or if the
280: // code that created this context in the first place should
281: // expect that the transport out info was set correctly, as
282: // it may need to use that info at some point before we get to
283: // this code.
284: faultMessageContext
285: .setProperty(
286: MessageContext.TRANSPORT_OUT,
287: processingContext
288: .getProperty(MessageContext.TRANSPORT_OUT));
289: faultMessageContext
290: .setProperty(
291: Constants.OUT_TRANSPORT_INFO,
292: processingContext
293: .getProperty(Constants.OUT_TRANSPORT_INFO));
294: faultMessageContext.setProcessingFault(true);
295: return faultMessageContext;
296: }
297: }
298:
299: // Create a basic response MessageContext with basic fields copied
300: MessageContext faultContext = createResponseMessageContext(processingContext);
301:
302: // Register the fault message context
303: OperationContext operationContext = processingContext
304: .getOperationContext();
305: if (operationContext != null) {
306: processingContext.getAxisOperation()
307: .addFaultMessageContext(faultContext,
308: operationContext);
309: }
310:
311: faultContext.setProcessingFault(true);
312:
313: // Set wsa:Action for response message
314:
315: // Use specified value if available
316:
317: String faultAction = (e instanceof AxisFault) ? ((AxisFault) e)
318: .getFaultAction() : null;
319:
320: if (faultAction == null) {
321: AxisOperation op = processingContext.getAxisOperation();
322: if (op != null && op.getFaultAction() != null) {
323: // TODO: Should the op be able to pick a fault action based on the fault?
324: faultAction = op.getFaultAction();
325: } else { //If, for some reason there is no value set, should use a sensible action.
326: faultAction = Final.WSA_SOAP_FAULT_ACTION;
327: }
328: }
329:
330: faultContext.setWSAAction(faultAction);
331:
332: // there are some information that the fault thrower wants to pass to the fault path.
333: // Means that the fault is a ws-addressing one hence use the ws-addressing fault action.
334: Object faultInfoForHeaders = processingContext
335: .getProperty(Constants.FAULT_INFORMATION_FOR_HEADERS);
336: if (faultInfoForHeaders != null) {
337: faultContext.setProperty(
338: Constants.FAULT_INFORMATION_FOR_HEADERS,
339: faultInfoForHeaders);
340:
341: // Note that this overrides any action set above
342: faultContext.setWSAAction(Final.WSA_FAULT_ACTION);
343: }
344:
345: // if the exception is due to a problem in the faultTo header itself, we can not use that
346: // fault information to send the error. Try to send using replyTo, else leave it to transport
347: boolean shouldSendFaultToFaultTo = AddressingHelper
348: .shouldSendFaultToFaultTo(processingContext);
349: EndpointReference faultTo = processingContext.getFaultTo();
350: if (faultTo != null && shouldSendFaultToFaultTo) {
351: faultContext.setTo(faultTo);
352: } else {
353: faultContext.setTo(processingContext.getReplyTo());
354: }
355:
356: if (faultContext.getTo() == null) {
357: faultContext.setTo(new EndpointReference(
358: AddressingConstants.Final.WSA_ANONYMOUS_URL));
359: }
360:
361: // Not worth setting up the session information on a fault flow
362: EndpointReference outboundToEPR = faultContext.getTo();
363: Object version = faultContext
364: .getProperty(AddressingConstants.WS_ADDRESSING_VERSION);
365: if (AddressingConstants.Submission.WSA_NAMESPACE
366: .equals(version)
367: || (outboundToEPR != null && !outboundToEPR
368: .hasAnonymousAddress())) {
369: faultContext.setMessageID(UUIDGenerator.getUUID());
370: faultContext.setReplyTo(new EndpointReference(
371: AddressingConstants.Final.WSA_NONE_URI));
372: }
373:
374: // do Target Resolution
375: TargetResolver targetResolver = faultContext
376: .getConfigurationContext().getAxisConfiguration()
377: .getTargetResolverChain();
378: if (targetResolver != null) {
379: targetResolver.resolveTarget(faultContext);
380: }
381:
382: // Ensure transport settings match the scheme for the To EPR
383: setupCorrectTransportOut(faultContext);
384:
385: SOAPEnvelope envelope = createFaultEnvelope(processingContext,
386: e);
387: faultContext.setEnvelope(envelope);
388:
389: //get the SOAP headers, user is trying to send in the fault
390: // TODO: Rationalize this mechanism a bit - maybe headers should live in the fault?
391: List soapHeadersList = (List) processingContext
392: .getProperty(SOAPConstants.HEADER_LOCAL_NAME);
393: if (soapHeadersList != null) {
394: SOAPHeader soapHeaderElement = envelope.getHeader();
395: for (int i = 0; i < soapHeadersList.size(); i++) {
396: OMElement soapHeaderBlock = (OMElement) soapHeadersList
397: .get(i);
398: soapHeaderElement.addChild(soapHeaderBlock);
399: }
400: }
401:
402: // TODO: Transport-specific stuff in here? Why? Is there a better way?
403: // now add HTTP Headers
404: faultContext.setProperty(HTTPConstants.HTTP_HEADERS,
405: processingContext
406: .getProperty(HTTPConstants.HTTP_HEADERS));
407:
408: return faultContext;
409: }
410:
411: /**
412: * Ensure that if the scheme of the To EPR for the response is different than the
413: * transport used for the request that the correct TransportOut is available
414: */
415: private static void setupCorrectTransportOut(MessageContext context)
416: throws AxisFault {
417: // Determine that we have the correct transport available.
418: TransportOutDescription transportOut = context
419: .getTransportOut();
420:
421: try {
422: EndpointReference responseEPR = context.getTo();
423: if (context.isServerSide() && responseEPR != null) {
424: if (!responseEPR.hasAnonymousAddress()
425: && !responseEPR.hasNoneAddress()) {
426: URI uri = new URI(responseEPR.getAddress());
427: String scheme = uri.getScheme();
428: if (!transportOut.getName().equals(scheme)) {
429: ConfigurationContext configurationContext = context
430: .getConfigurationContext();
431: transportOut = configurationContext
432: .getAxisConfiguration()
433: .getTransportOut(scheme);
434: if (transportOut == null) {
435: throw new AxisFault(
436: "Can not find the transport sender : "
437: + scheme);
438: }
439: context.setTransportOut(transportOut);
440: }
441: if (context.getOperationContext() != null) {
442: context.getOperationContext().setProperty(
443: Constants.DIFFERENT_EPR,
444: Constants.VALUE_TRUE);
445: }
446: }
447: }
448: } catch (URISyntaxException urise) {
449: throw AxisFault.makeFault(urise);
450: }
451: }
452:
453: /**
454: * Information to create the SOAPFault can be extracted from different places.
455: * 1. Those information may have been put in to the message context by some handler. When someone
456: * is putting like that, he must make sure the SOAPElements he is putting must be from the
457: * correct SOAP Version.
458: * 2. SOAPProcessingException is flexible enough to carry information about the fault. For example
459: * it has an attribute to store the fault code. The fault reason can be extracted from the
460: * message of the exception. I opted to put the stacktrace under the detail element.
461: * eg : <Detail>
462: * <Exception> stack trace goes here </Exception>
463: * <Detail>
464: * <p/>
465: * If those information can not be extracted from any of the above places, I default the soap
466: * fault values to following.
467: * <Fault>
468: * <Code>
469: * <Value>env:Receiver</Value>
470: * </Code>
471: * <Reason>
472: * <Text>unknown</Text>
473: * </Reason>
474: * <Role/>
475: * <Node/>
476: * <Detail/>
477: * </Fault>
478: * <p/>
479: * -- EC
480: *
481: * @param context
482: * @param e
483: */
484: private static SOAPEnvelope createFaultEnvelope(
485: MessageContext context, Throwable e) {
486: SOAPEnvelope envelope;
487:
488: if (context.isSOAP11()) {
489: envelope = OMAbstractFactory.getSOAP11Factory()
490: .getDefaultFaultEnvelope();
491: } else {
492: // Following will make SOAP 1.2 as the default, too.
493: envelope = OMAbstractFactory.getSOAP12Factory()
494: .getDefaultFaultEnvelope();
495: }
496: SOAPFault fault = envelope.getBody().getFault();
497:
498: SOAPProcessingException soapException = null;
499: AxisFault axisFault = null;
500:
501: if (e == null)
502: return envelope;
503:
504: if (e instanceof AxisFault) {
505: axisFault = (AxisFault) e;
506: } else if (e.getCause() instanceof AxisFault) {
507: axisFault = (AxisFault) e.getCause();
508: }
509:
510: if (axisFault != null) {
511: Iterator iter = axisFault.headerIterator();
512: while (iter.hasNext()) {
513: SOAPHeaderBlock header = (SOAPHeaderBlock) iter.next();
514: envelope.getHeader().addChild(header);
515: }
516: }
517:
518: if (e instanceof SOAPProcessingException) {
519: soapException = (SOAPProcessingException) e;
520: } else if (axisFault != null) {
521: if (axisFault.getCause() instanceof SOAPProcessingException) {
522: soapException = (SOAPProcessingException) axisFault
523: .getCause();
524: }
525: }
526:
527: // user can set the fault information to the message context or to the AxisFault itself.
528: // whatever user sets to the message context, supercedes eerything.
529:
530: Object faultCode = context
531: .getProperty(SOAP12Constants.SOAP_FAULT_CODE_LOCAL_NAME);
532: String soapFaultCode = "";
533:
534: if (faultCode != null) {
535: fault.setCode((SOAPFaultCode) faultCode);
536: } else if (soapException != null) {
537: soapFaultCode = soapException.getFaultCode();
538: } else if (axisFault != null) {
539: if (axisFault.getFaultCodeElement() != null) {
540: fault.setCode(axisFault.getFaultCodeElement());
541: } else {
542: QName faultCodeQName = axisFault.getFaultCode();
543: if (faultCodeQName != null) {
544: if (faultCodeQName.getLocalPart().indexOf(":") == -1) {
545: String prefix = faultCodeQName.getPrefix();
546: String uri = faultCodeQName.getNamespaceURI();
547: prefix = prefix == null || "".equals(prefix) ? fault
548: .getNamespace().getPrefix()
549: : prefix;
550: uri = uri == null || "".equals(uri) ? fault
551: .getNamespace().getNamespaceURI() : uri;
552: soapFaultCode = prefix + ":"
553: + faultCodeQName.getLocalPart();
554: fault.declareNamespace(uri, prefix);
555: } else {
556: soapFaultCode = faultCodeQName.getLocalPart();
557: }
558: }
559: }
560: }
561:
562: // defaulting to fault code Receiver, if no message is available
563: if (faultCode == null && context.getEnvelope() != null) {
564: soapFaultCode = ("".equals(soapFaultCode) || (soapFaultCode == null)) ? SOAP12Constants.SOAP_DEFAULT_NAMESPACE_PREFIX
565: + ":"
566: + context.getEnvelope().getVersion()
567: .getReceiverFaultCode().getLocalPart()
568: : soapFaultCode;
569: }
570:
571: if (faultCode == null) {
572: if (context.isSOAP11()) {
573: fault.getCode().setText(soapFaultCode);
574: } else {
575: fault.getCode().getValue().setText(soapFaultCode);
576: }
577: }
578:
579: SOAPFaultReason faultReason = (SOAPFaultReason) context
580: .getProperty(SOAP12Constants.SOAP_FAULT_REASON_LOCAL_NAME);
581:
582: if (faultReason == null && axisFault != null) {
583: faultReason = axisFault.getFaultReasonElement();
584: }
585: if (faultReason != null) {
586: fault.setReason(faultReason);
587: } else {
588: String message = "";
589: if (soapException != null) {
590: message = soapException.getMessage();
591: } else if (axisFault != null) {
592: // Couldn't find FaultReasonElement, try reason string
593: message = axisFault.getReason();
594: }
595:
596: if (message == null || "".equals(message)) {
597: message = getFaultReasonFromException(e, context);
598: }
599:
600: if (message == null || "".equals(message))
601: message = "unknown";
602:
603: if (context.isSOAP11()) {
604: fault.getReason().setText(message);
605: } else {
606: fault.getReason().getFirstSOAPText().setLang("en-US");
607: fault.getReason().getFirstSOAPText().setText(message);
608: }
609: }
610:
611: Object faultRole = context
612: .getProperty(SOAP12Constants.SOAP_FAULT_ROLE_LOCAL_NAME);
613: if (faultRole != null) {
614: fault.getRole().setText((String) faultRole);
615: } else if (axisFault != null) {
616: if (axisFault.getFaultRoleElement() != null) {
617: fault.setRole(axisFault.getFaultRoleElement());
618: }
619: }
620:
621: Object faultNode = context
622: .getProperty(SOAP12Constants.SOAP_FAULT_NODE_LOCAL_NAME);
623: if (faultNode != null) {
624: fault.getNode().setText((String) faultNode);
625: } else if (axisFault != null) {
626: if (axisFault.getFaultNodeElement() != null) {
627: fault.setNode(axisFault.getFaultNodeElement());
628: }
629: }
630:
631: // Allow handlers to override the sendStacktraceDetailsWithFaults setting from the Configuration to allow
632: // WS-* protocol faults to not include the exception.
633: boolean sendStacktraceDetailsWithFaults = false;
634: OperationContext oc = context.getOperationContext();
635: Object flagFromContext = null;
636: if (oc != null) {
637: flagFromContext = context
638: .getOperationContext()
639: .getProperty(
640: Constants.Configuration.SEND_STACKTRACE_DETAILS_WITH_FAULTS);
641: }
642: if (flagFromContext != null) {
643: sendStacktraceDetailsWithFaults = JavaUtils
644: .isTrue(flagFromContext);
645: } else {
646: Parameter param = context
647: .getParameter(Constants.Configuration.SEND_STACKTRACE_DETAILS_WITH_FAULTS);
648: if (param != null) {
649: sendStacktraceDetailsWithFaults = JavaUtils
650: .isTrue(param.getValue());
651: }
652: }
653:
654: Object faultDetail = context
655: .getProperty(SOAP12Constants.SOAP_FAULT_DETAIL_LOCAL_NAME);
656: if (faultDetail != null) {
657: fault.setDetail((SOAPFaultDetail) faultDetail);
658: } else if (axisFault != null) {
659: if (axisFault.getFaultDetailElement() != null) {
660: fault.setDetail(axisFault.getFaultDetailElement());
661: } else {
662: OMElement detail = axisFault.getDetail();
663: if (detail != null) {
664: fault.getDetail().addDetailEntry(detail);
665: } else if (sendStacktraceDetailsWithFaults) {
666: fault.setException(axisFault);
667: }
668: }
669: } else if (fault.getException() == null
670: && sendStacktraceDetailsWithFaults) {
671: if (e instanceof Exception) {
672: fault.setException((Exception) e);
673: } else {
674: fault.setException(new Exception(e));
675: }
676: }
677:
678: return envelope;
679: }
680:
681: /**
682: * By the time the exception comes here it can be wrapped by so many levels. This will crip down
683: * to the root cause and get the initial error depending on the property
684: *
685: * @param e
686: */
687: private static String getFaultReasonFromException(Throwable e,
688: MessageContext context) {
689: Throwable throwable = e;
690: Parameter param = context
691: .getParameter(Constants.Configuration.DRILL_DOWN_TO_ROOT_CAUSE_FOR_FAULT_REASON);
692: boolean drillDownToRootCauseForFaultReason = param != null
693: && ((String) param.getValue()).equalsIgnoreCase("true");
694: if (drillDownToRootCauseForFaultReason) {
695: while (throwable.getCause() != null) {
696: throwable = throwable.getCause();
697: }
698: }
699: return throwable.getMessage();
700: }
701:
702: private static String getSenderFaultCode(OMNamespace soapNamespace) {
703: return SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI
704: .equals(soapNamespace.getNamespaceURI()) ? SOAP12Constants.SOAP_DEFAULT_NAMESPACE_PREFIX
705: + ":" + SOAP12Constants.FAULT_CODE_SENDER
706: : SOAP12Constants.SOAP_DEFAULT_NAMESPACE_PREFIX + ":"
707: + SOAP11Constants.FAULT_CODE_SENDER;
708: }
709: }
|