/******************************************************************************* * 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.common.impl.protocolprocessor.soap; import java.net.HttpURLConnection; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import org.apache.axiom.om.OMConstants; import org.apache.axiom.om.impl.util.OMSerializerUtil; import org.apache.axiom.soap.SOAP11Constants; import org.apache.axiom.soap.SOAP12Constants; import org.apache.axiom.soap.SOAPBody; import org.apache.axiom.soap.SOAPConstants; import org.apache.axiom.soap.SOAPEnvelope; import org.apache.axiom.soap.SOAPHeader; import org.apache.axis2.AxisFault; import org.apache.axis2.Constants; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.ebayopensource.turmeric.runtime.binding.BindingConstants; import org.ebayopensource.turmeric.runtime.binding.objectnode.ObjectNode; import org.ebayopensource.turmeric.runtime.binding.utils.XMLStreamReaderUtils; import org.ebayopensource.turmeric.runtime.binding.utils.XMLStreamReaderUtilsException; 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.axis2.SOAConfigurator; import org.ebayopensource.turmeric.runtime.common.impl.utils.HTTPCommonUtils; import org.ebayopensource.turmeric.runtime.common.pipeline.InboundMessage; import org.ebayopensource.turmeric.runtime.common.pipeline.Message; import org.ebayopensource.turmeric.runtime.common.pipeline.MessageContext; import org.ebayopensource.turmeric.runtime.common.pipeline.OutboundMessage; import org.ebayopensource.turmeric.runtime.common.pipeline.ProtocolProcessor; import org.ebayopensource.turmeric.runtime.common.types.SOAConstants; import org.ebayopensource.turmeric.runtime.errorlibrary.ErrorConstants; /** * Title: BaseSOAPProtocolProcessor.java * Description: * Copyright: Copyright (c) 2007 * Company: eBay * @author Gary Yue * @version 1.0 * * Abstract class for SOAP Protocol Processor. Contains shared codes that can be used by child classes */ public abstract class BaseSOAPProtocolProcessor implements ProtocolProcessor { private static final Logger LOG = Logger.getLogger(BaseSOAPProtocolProcessor.class.getName()); protected ConfigurationContext m_configContext; protected String m_messageProtocolName = null; // Default Error Response Indicator Code for SOAP is HTTP_INTERNAL_ERROR (500) private static int m_defaultTransportErrorResponseIndicationCode = HttpURLConnection.HTTP_INTERNAL_ERROR; // Alternate Error Response Indicator Code for SOAP is HTTP_OK (200) private static int m_alternateTransportErrorResponseIndicationCode = HttpURLConnection.HTTP_OK; public static final String AXIS_IN_CONTEXT = "AXIS_IN_CONTEXT"; public static final String AXIS_OUT_CONTEXT = "AXIS_OUT_CONTEXT"; public static final String SOAP_FAULT_OBJECT = "SOAP_FAULT_OBJECT"; private static Collection<String> s_supportedDataFormats; static { // initialize the static supported data format list s_supportedDataFormats = new ArrayList<String>(); s_supportedDataFormats.add(BindingConstants.PAYLOAD_XML); } public void init(InitContext ctx) throws ServiceException { LOG.fine("Initializing SOAPProtocolProcessor..."); //KEEPME try { m_messageProtocolName = ctx.getName(); // SOAP11 or SOAP12 m_configContext = ConfigurationContextFactory.createConfigurationContext(new SOAConfigurator()); } catch (AxisFault e) { LOG.log(Level.WARNING, "Unable to initialize " + BaseSOAPProtocolProcessor.class.getName(), e); e.printStackTrace(); throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_INIT_ERROR, ErrorConstants.ERRORDOMAIN, new Object[]{getMessageProtocol(), e.toString()})); } m_configContext.setProperty(Constants.CONTAINER_MANAGED, Constants.VALUE_TRUE); } public void postDeserialize(InboundMessage msg) throws ServiceException { //System.out.println("BasedSOAPProtocolProcessor: postDeserialize() -- consume ending Envelope tag!"); XMLStreamReader reader = msg.getXMLStreamReader(); try { // get env from context org.apache.axis2.context.MessageContext axis2InContext = (org.apache.axis2.context.MessageContext) msg.getContext().getProperty(AXIS_IN_CONTEXT); if (axis2InContext == null) { throw new IllegalStateException("Attempt to post-deserialize without going " + "through before-pipeline event first"); } SOAPEnvelope env = axis2InContext.getEnvelope(); // handler fault case on inbound response if (!msg.getContext().getProcessingStage().isRequestDirection() && msg.isErrorMessage()) { // consume the end detail tag String endFaultDetailTag = (SOAPUtils.isSOAP12Envelope(env) ? SOAP12Constants.SOAP_FAULT_DETAIL_LOCAL_NAME : SOAP11Constants.SOAP_FAULT_DETAIL_LOCAL_NAME); XMLStreamReaderUtils.consumeEndElement(reader, endFaultDetailTag); // consume the end Fault tag XMLStreamReaderUtils.consumeEndElement(reader, SOAPConstants.SOAPFAULT_LOCAL_NAME); } // consume the end Body tag XMLStreamReaderUtils.consumeEndElement(reader, SOAPConstants.BODY_LOCAL_NAME); // consume end Envelope tag XMLStreamReaderUtils.consumeEndElement(reader, SOAPConstants.SOAPENVELOPE_LOCAL_NAME); // should be at the end of the doc int type = reader.getEventType(); if (type == XMLStreamConstants.END_DOCUMENT) { try { reader.close(); } catch (XMLStreamException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_DATA_READ_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } } else { //System.out.println("current pos: " + reader.getLocation().getCharacterOffset()); // ERROR: SHOULD NOT REACH HERE!!! throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_DATA_DESERIALIZATION_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), "Error: Contain XML element after ending SOAP Envelope tag"})); } // SOA 2.1 Addition MessageContext ctx = msg.getContext(); Object soapFault = ctx.getProperty(SOAP_FAULT_OBJECT); if (soapFault != null) { Object detail = msg.getErrorResponseInternal(); if (SOAPUtils.isSOAP12Envelope(env)) { ((SOAP12Fault)soapFault).setDetail(detail); } else { ((SOAP11Fault)soapFault).setDetail(detail); } msg.setErrorResponse(soapFault); } } catch(XMLStreamException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_DATA_READ_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } catch(ServiceException e) { throw e; }catch(XMLStreamReaderUtilsException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_DATA_DESERIALIZATION_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } catch (Exception e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_INBOUND_SYSTEM_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } } public void preSerialize(OutboundMessage msg, XMLStreamWriter writer) throws ServiceException { //System.out.println("BasedSOAPProtocolProcessor: preSerialize -- write start envelope/header/body!"); // get axis2 out Context org.apache.axis2.context.MessageContext axis2OutContext = (org.apache.axis2.context.MessageContext) msg.getContext().getProperty(AXIS_OUT_CONTEXT); SOAPEnvelope env = axis2OutContext.getEnvelope(); try { // write start xml declaration writer.writeStartDocument(OMConstants.DEFAULT_CHAR_SET_ENCODING, "1.0"); // write the start envelope tag OMSerializerUtil.serializeStartpart(env, writer); // write header block // SOAPHeader header = env.getHeader(); // header.serialize(writer); // write header block SOAPHeader header = env.getHeader(); //header.serialize(writer); // write the start header tag OMSerializerUtil.serializeStartpart(header, writer); // write the header content msg.serializeHeader(writer); // write the end header tag OMSerializerUtil.serializeEndpart(writer); // write start body SOAPBody body = env.getBody(); // normal response: just serialize the start body tag. JAXB will handler the body serialization OMSerializerUtil.serializeStartpart(body, writer); // check if the body has fault. If so, emit the fault information up to the detail tag if (body.hasFault()) { // fault case: serialize the fault info up to the detail tag SOAPUtils.serializeSOAPFault(body.getFault(), writer); } } catch (XMLStreamException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_DATA_WRITE_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } catch (Exception e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_OUTBOUND_SYSTEM_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } } public void postSerialize(OutboundMessage msg, XMLStreamWriter writer) throws ServiceException { //System.out.println("BasedSOAPProtocolProcessor: postSerialize -- write end envelope/body tag!"); try { // complete the end tags writer.writeEndDocument(); } catch (XMLStreamException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_DATA_WRITE_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } catch (Exception e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_PROTOCOLPROCESSOR_OUTBOUND_SYSTEM_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {getMessageProtocol(), e.toString()}), e); } } public String getMessageProtocol() { return m_messageProtocolName; } public boolean supportsHeaders() { return true; } @SuppressWarnings("unused") private static final String SOAP_ENVELOPE_NAME = "Envelope"; private static final String SOAP_HEADER_NAME = "Header"; private static final String SOAP_BODY_NAME = "Body"; public static final String SOAP_FAULT_NAME = "Fault"; public static final String SOAP_FAULT_ACTOR_NAME = "faultactor"; public static final String SOAP_FAULT_ROLE_NAME = "Role"; public Collection<ObjectNode> getMessageHeaders(ObjectNode root) throws ServiceException { try { ObjectNode envelope = getSoapEnvelope(root); if (null == envelope) { return null; } Iterator<ObjectNode> children = envelope.getChildrenIterator(); if (!children.hasNext()) { return null; } ObjectNode header = (ObjectNode) children.next(); if (SOAP_HEADER_NAME.equalsIgnoreCase(header.getNodeName().getLocalPart())) { return header.getChildNodes(); } return null; } catch (XMLStreamException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_DATA_READ_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {e.toString()}), e); } } public ObjectNode getMessageBody(ObjectNode root) throws ServiceException { try { ObjectNode envelope = getSoapEnvelope(root); if (null == envelope) { return null; } Iterator<ObjectNode> children = envelope.getChildrenIterator(); if (!children.hasNext()) { return null; } ObjectNode body = children.next(); if (SOAP_BODY_NAME.equalsIgnoreCase(body.getNodeName().getLocalPart())) { return body; } if (!children.hasNext()) { return null; } body = children.next(); if (SOAP_BODY_NAME.equalsIgnoreCase(body.getNodeName().getLocalPart())) { return body; } return null; } catch (XMLStreamException e) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_DATA_READ_ERROR, ErrorConstants.ERRORDOMAIN, new Object[] {e.toString()}), e); } } public Collection<String> getSupportedDataFormats() { return s_supportedDataFormats; } private ObjectNode getSoapEnvelope(ObjectNode root) throws XMLStreamException { Iterator<ObjectNode> childNodes = root.getChildrenIterator(); if (childNodes.hasNext()) { return childNodes.next(); } return null; } public ConfigurationContext getConfigurationContext() { return m_configContext; } public void setSOAP12ContentType(Message msg) throws ServiceException { String mimeType = SOAP12Constants.SOAP_12_CONTENT_TYPE; Charset charset = msg.getG11nOptions().getCharset(); String contentType = HTTPCommonUtils.formatContentType(mimeType, charset); msg.setTransportHeader(SOAConstants.HTTP_HEADER_CONTENT_TYPE, contentType); } public int getTransportErrorResponseIndicationCode() { return m_defaultTransportErrorResponseIndicationCode; } public int getAlternateTransportErrorResponseIndicationCode() { return m_alternateTransportErrorResponseIndicationCode; } public boolean isExpectedMessageProtocol(Message msg) throws ServiceException { String contentType = msg .getTransportHeader(SOAConstants.HTTP_HEADER_CONTENT_TYPE); if (contentType == null) return false; // Content-Type is not case sensitive according to rfc: // http://www.w3.org/Protocols/rfc1341/4_Content-Type.html contentType = contentType.toLowerCase(); String soapAction = msg .getTransportHeader(SOAConstants.HTTP_HEADER_SOAP11_SOAPACTION); // Check for SOAP11 if (contentType.indexOf(SOAP11Constants.SOAP_11_CONTENT_TYPE .toLowerCase()) > -1 && soapAction != null && SOAConstants.MSG_PROTOCOL_SOAP_11 .equals(m_messageProtocolName)) { return true; }// Check for SOAP12 else if (contentType.indexOf(SOAP12Constants.SOAP_12_CONTENT_TYPE .toLowerCase()) > -1 && SOAConstants.MSG_PROTOCOL_SOAP_12 .equals(m_messageProtocolName)) { return true; } return false; } /* public boolean isExpectedMessageProtocol(ObjectNode root) throws ServiceException { if (root != null) { try { ObjectNode envelope = getSoapEnvelope(root); if (envelope != null && SOAP_ENVELOPE_NAME.equalsIgnoreCase(envelope.getNodeName().getLocalPart())) { String nsURI = envelope.getNodeName().getNamespaceURI(); if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI) && SOAConstants.MSG_PROTOCOL_SOAP_11.equals(m_messageProtocolName)) { return true; } else if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI) && SOAConstants.MSG_PROTOCOL_SOAP_12.equals(m_messageProtocolName)) { return true; } } } catch (Exception e) { throw new ServiceException( ErrorDataFactory.createErrorData(ErrorConstants.SVC_DATA_READ_ERROR, ErrorConstants.ERRORDOMAIN),e); } } return false; }*/ }