/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* Licensed 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
*******************************************************************************/
package org.ebayopensource.turmeric.runtime.spf.impl.protocolprocessor.soap;
import java.util.logging.Logger;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.axis2.engine.AxisEngine;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.util.MessageContextBuilder;
import org.ebayopensource.turmeric.runtime.common.exceptions.ErrorDataFactory;
import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException;
import org.ebayopensource.turmeric.runtime.common.impl.protocolprocessor.soap.Axis2Utils;
import org.ebayopensource.turmeric.runtime.common.impl.protocolprocessor.soap.BaseSOAPProtocolProcessor;
import org.ebayopensource.turmeric.runtime.common.impl.protocolprocessor.soap.SOAPUtils;
import org.ebayopensource.turmeric.runtime.common.pipeline.InboundMessage;
import org.ebayopensource.turmeric.runtime.common.pipeline.MessageContext;
import org.ebayopensource.turmeric.runtime.errorlibrary.ErrorConstants;
/**
* Title: ServerSOAPProtocolProcessor.java
* Description:
* Copyright: Copyright (c) 2007
* Company: eBay
* @author Gary Yue
* @version 1.0
*
* Axis2 Protocol Processor implementation for server
*/
public class ServerSOAPProtocolProcessor extends BaseSOAPProtocolProcessor {
private static final Logger LOG = Logger.getLogger(ServerSOAPProtocolProcessor.class.getName());
/**
* Execute Axis2 inbound pipeline here
*/
public void beforeRequestPipeline(MessageContext ctx) throws ServiceException
{
//System.out.println("ServerSOAPProtocolProcessor: beforeRequestPipeline -- calling Axis Inbound pipeline!");
try {
// get transport headers
String contentType = ctx.getRequestMessage().getTransportHeader(HTTPConstants.HEADER_CONTENT_TYPE.toUpperCase());
String soapAction = ctx.getRequestMessage().getTransportHeader(HTTPConstants.HEADER_SOAP_ACTION.toUpperCase());
InboundMessage requestMsg = (InboundMessage) ctx.getRequestMessage();
String requestURL = null;
// obtain the request URL
if (ctx.getServiceAddress().getServiceUrl() != null) {
requestURL = ctx.getServiceAddress().getServiceUrl().toString();
}
// create Axis2 context from Ebay context, and attached it to Ebay Context
// NOTE: this axis inbound context is REQUIRED in the system for sending proper outbound SOAP fault!!!
org.apache.axis2.context.MessageContext axis2Context = Axis2Utils.createInboundAxis2Context(ctx, m_configContext);
ctx.setProperty(AXIS_IN_CONTEXT, axis2Context);
// if error has happened prior to the inbound flow, we have safely exit, since no additional processing is required.
if (ctx.hasErrors()) {
return;
}
Exception exceptionWhileProcessing = null;
// ok.. we need to see if there was an exception while processing the header or body since a tag may be wrong
// e.g.. <bodyBAD> (check the tests :) In the older version of axis (and code), this exception would have been ignored here and
// would have been rethrown from the Axis2Utils and everything was peachy. But that would not be the right thing to do here
// and in the newer version, the envelope processing goes on anyways for our purposes (getting the child), and it cleanly skips the
// bad tag. So, this issue is not caught in the Axis2Utils codepath either.
// So now we catch this exception while parsing, save it and then throw it AFTER the Axis2Utils.processHTTPPostRequest call.
// why do we need that? Well.. that does the whole soap envelope setting, namespaces etc. If that doesnt happen like this,
// a client could make a soap12 call but get back a soap11 fault response since the Axis2Utils codepath didnt get executed.
try {
// this is called to trigger the deserialization of the headers, and stored them in memory, prior to axis deserialization
requestMsg.getMessageHeadersAsJavaObject();
requestMsg.getMessageBody();
} catch(Exception e) {
exceptionWhileProcessing = e;
}
LOG.info("request msg: " + requestMsg);
LOG.info("xml stream reader: " + requestMsg.getXMLStreamReader());
/*** ENTERING AXIS2 PIPELINE ***/
Axis2Utils.processHTTPPostRequest(axis2Context, requestMsg.getXMLStreamReader(), contentType, soapAction, requestURL);
/*** EXITING AXIS2 PIPELINE ***/
// went thru Axis2 pipline successfully...
if(exceptionWhileProcessing!=null){
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_INBOUND_SYSTEM_ERROR,
ErrorConstants.ERRORDOMAIN, new Object[]{getMessageProtocol(), "Payload Body or Header could not be parsed."}), exceptionWhileProcessing);
}
} catch (AxisFault e) {
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_INBOUND_SYSTEM_ERROR,
ErrorConstants.ERRORDOMAIN, new Object[]{getMessageProtocol(), e.getMessage()}), e);
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_INBOUND_SYSTEM_ERROR,
ErrorConstants.ERRORDOMAIN, new Object[]{getMessageProtocol(), e.getMessage()}), e);
}
}
public void beforeRequestDispatch(MessageContext ctx) throws ServiceException
{
// NOOP
}
public void beforeResponsePipeline(MessageContext ctx) throws ServiceException
{
// NOOP
}
/**
* Execute Axis2 outbound pipeline here
*/
public void beforeResponseDispatch(MessageContext ctx) throws ServiceException
{
//System.out.println("ServerSOAPProtocolProcessor: beforeResponseDispatch -- calling Axis Outbound pipeline!");
// get axis2 Context
org.apache.axis2.context.MessageContext axis2InContext =
(org.apache.axis2.context.MessageContext) ctx.getProperty(AXIS_IN_CONTEXT);
if (axis2InContext == null ) {
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_OUTBOUND_SYSTEM_ERROR,
ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), "Inbound axis2 context not found from message context"}));
}
try {
// overwrite the content-type here if it's not SOAP1.1 (which means it's SOAP1.2)
if (!axis2InContext.isSOAP11()) {
setSOAP12ContentType( ctx.getResponseMessage());
}
if (ctx.hasErrors()) {
// error flow
// heck: to bypass a nullpointer
//axis2InContext.getAxisOperation().addParameter(new Parameter(Constants.Configuration.SEND_STACKTRACE_DETAILS_WITH_FAULTS, Boolean.FALSE));
//axis2InContext.getOperationContext().setProperty(Constants.Configuration.SEND_STACKTRACE_DETAILS_WITH_FAULTS, Boolean.FALSE);
// Convert the exception to a Axis fault, so that axis can create a proper SOAP Fault message from it
org.apache.axis2.context.MessageContext faultContext = createSOAPFaultContext(ctx.getErrorList().get(0), axis2InContext);
ctx.setProperty(AXIS_OUT_CONTEXT, faultContext);
// go thru axis2 pipeline
AxisEngine.sendFault(faultContext);
} else {
// normal flow
// Create Axis2 Out context from In context
org.apache.axis2.context.MessageContext axis2OutMsgContext =
Axis2Utils.createOutboundAxis2ContextFromInbound(axis2InContext);
ctx.setProperty(AXIS_OUT_CONTEXT, axis2OutMsgContext);
// Create an empty envelope
SOAPEnvelope envelope = SOAPUtils.createSOAPEnvelope((OMElement)null, axis2InContext.getEnvelope().getNamespace().getNamespaceURI());
axis2OutMsgContext.setEnvelope(envelope);
// go thru axis2 pipeline
AxisEngine.send(axis2OutMsgContext);
}
} catch (AxisFault e) {
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_OUTBOUND_SYSTEM_ERROR,
ErrorConstants.ERRORDOMAIN, new Object[]{getMessageProtocol(), e.getMessage()}), e);
} catch (Exception e) {
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_OUTBOUND_SYSTEM_ERROR,
ErrorConstants.ERRORDOMAIN, new Object[]{getMessageProtocol(), e.getMessage()}), e);
}
}
private org.apache.axis2.context.MessageContext createSOAPFaultContext( Throwable throwable,
org.apache.axis2.context.MessageContext axis2InContext) throws AxisFault {
// convert the exception to an Axis Fault
AxisFault axisFault = createAxisFaultFromException(throwable);
// populate axisFault (fault code, fault reason, etc...)
populateAxisFault(axisFault, axis2InContext);
// Create Axis2 Fault Out Context from In context
org.apache.axis2.context.MessageContext faultContext =
MessageContextBuilder.createFaultMessageContext(axis2InContext, axisFault);
return faultContext;
}
// takes the exception and maps it to a soap fault
private AxisFault createAxisFaultFromException(Throwable throwable) {
if (throwable instanceof ServiceException) {
// handle service exception case
ServiceException ex = (ServiceException)throwable;
if (ex.getCause() != null && ex.getCause() instanceof AxisFault) {
// if there is a nested soap fault, use this as the soap fault
return (AxisFault) ex.getCause();
}
// otherwise, create a new soap fault
return new AxisFault(ex.getMessage(), ex);
}
return new AxisFault(throwable.getMessage(), throwable);
}
private void populateAxisFault(AxisFault axisFault, org.apache.axis2.context.MessageContext axis2InContext) {
if (axis2InContext.getEnvelope() == null) {
// default: SOAP11
if (axis2InContext.isSOAP11()) {
axisFault.setFaultCode(SOAP11Constants.QNAME_RECEIVER_FAULTCODE);
} else {
axisFault.setFaultCode(SOAP12Constants.QNAME_RECEIVER_FAULTCODE);
}
} else {
String envNamespaceURI = axis2InContext.getEnvelope().getNamespace().getNamespaceURI();
// map fault code
if (envNamespaceURI.equals(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
axisFault.setFaultCode(SOAP12Constants.QNAME_RECEIVER_FAULTCODE);
} else {
axisFault.setFaultCode(SOAP11Constants.QNAME_RECEIVER_FAULTCODE);
}
}
}
}