All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.centurylink.mdw.hub.servlet.SoapServlet Maven / Gradle / Ivy

There is a newer version: 6.1.39
Show newest version
/*
 * Copyright (C) 2017 CenturyLink, Inc.
 *
 * 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
 *
 * 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 com.centurylink.mdw.hub.servlet;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.TransformerException;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.xmlbeans.XmlException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.centurylink.mdw.app.Compatibility;
import com.centurylink.mdw.bpm.MDWStatusMessageDocument;
import com.centurylink.mdw.bpm.MDWStatusMessageDocument.MDWStatusMessage;
import com.centurylink.mdw.cache.impl.AssetCache;
import com.centurylink.mdw.common.service.ServiceException;
import com.centurylink.mdw.config.PropertyManager;
import com.centurylink.mdw.listener.ListenerHelper;
import com.centurylink.mdw.model.asset.Asset;
import com.centurylink.mdw.model.listener.Listener;
import com.centurylink.mdw.model.workflow.Package;
import com.centurylink.mdw.util.log.LoggerUtil;
import com.centurylink.mdw.util.log.StandardLogger;
import com.centurylink.mdw.util.timer.CodeTimer;
import com.centurylink.mdw.xml.DomHelper;

/**
 * General SOAP listener servlet corresponding to mdw.wsdl. Request content is
 * pulled out of the SOAP envelope and forwarded to the MDW external event
 * handler mechanism.
 */
@WebServlet(urlPatterns={"/SOAP/*"}, loadOnStartup=1)
public class SoapServlet extends ServiceServlet {

    private static StandardLogger logger = LoggerUtil.getStandardLogger();

    private static Pattern tokenPattern = Pattern.compile("([\\$]\\{.*?\\})");
    private static String RPC_SERVICE_PATH = "/MDWWebService";

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        if (logger.isMdwDebugEnabled()) {
            logger.mdwDebug("SOAP Listener GET Request:\n" + request.getRequestURI()
                    + (request.getQueryString() == null ? "" : ("?" + request.getQueryString())));
        }

        if (request.getServletPath().endsWith(RPC_SERVICE_PATH)
                || RPC_SERVICE_PATH.equals(request.getPathInfo())) {
            Asset rpcWsdlAsset = AssetCache.getAsset(Package.MDW + "/MdwRpcWebService.wsdl", Asset.WSDL);
            response.setContentType("text/xml");
            response.getWriter().print(substituteRuntimeWsdl(rpcWsdlAsset.getStringContent()));
        }
        else if (request.getPathInfo() == null || request.getPathInfo().equalsIgnoreCase("mdw.wsdl")) {
            // forward to general wsdl
            RequestDispatcher requestDispatcher = request.getRequestDispatcher("/mdw.wsdl");
            requestDispatcher.forward(request, response);
        }
        else if (request.getPathInfo().toUpperCase().endsWith(Asset.WSDL)) {
            String wsdlAsset = request.getPathInfo().substring(1);
            Asset asset = AssetCache.getAsset(wsdlAsset, Asset.WSDL);
            if (asset == null) {
                // try trimming file extension
                wsdlAsset = wsdlAsset.substring(0, wsdlAsset.length() - 5);
                asset = AssetCache.getAsset(wsdlAsset, Asset.WSDL);
            }
            if (asset == null) {
                // try with lowercase extension
                wsdlAsset = wsdlAsset + ".wsdl";
                asset = AssetCache.getAsset(wsdlAsset, Asset.WSDL);
            }
            if (asset == null) {
                String message = "No WSDL resource found: " + request.getPathInfo().substring(1);
                logger.severe(message);
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.getWriter().print(message);
            }
            else {
                response.setContentType("text/xml");
                response.getWriter().print(substituteRuntimeWsdl(asset.getStringContent()));
            }
        }
        else {
            ServletException ex = new ServletException("HTTP GET not supported for URL: " + request.getRequestURL());
            logger.severeException(ex.getMessage(), ex);
            throw ex;
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        CodeTimer timer = new CodeTimer("SoapServlet.doPost()", true);

        InputStream reqInputStream = request.getInputStream();
        // read the POST request contents
        String requestString = getRequestString(request);
        if (logger.isMdwDebugEnabled()) {
            logger.mdwDebug("SOAP Listener POST Request:\n" + requestString);
        }

        Map metaInfo = buildMetaInfo(request);

        String responseString = null;
        MessageFactory factory = null;
        String soapVersion = SOAPConstants.SOAP_1_1_PROTOCOL;
        try {
            SOAPMessage message = null;
            SOAPBody body = null;
            try {
                // Intuitively guess which SOAP version is needed
                // factory = getMessageFactory(requestString, true);
                soapVersion = getSoapVersion(requestString, true);
                factory = getSoapMessageFactory(soapVersion);
                reqInputStream = new ByteArrayInputStream(requestString.getBytes());

                message = factory.createMessage(null, reqInputStream);
                body = message.getSOAPBody();
            }
            catch (SOAPException e) {
                // Unlikely, but just in case the SOAP version guessing
                // has guessed incorrectly, this catches any SOAP exception,
                // in which case try the other version
                if (logger.isMdwDebugEnabled()) {
                    logger.mdwDebug("SOAPListenerServlet failed to find correct Message Factory:"
                            + "\n" + e.getMessage());
                }
                // Try with the other unintuitive MessageFactory
                // factory = getMessageFactory(requestString, false);
                soapVersion = getSoapVersion(requestString, false);
                factory = getSoapMessageFactory(soapVersion);
                reqInputStream = new ByteArrayInputStream(requestString.getBytes());

                message = factory.createMessage(null, reqInputStream);
                body = message.getSOAPBody();
                // Only 2 versions, so let any exceptions bubble up
            }
            Node childElem = null;
            Iterator it = body.getChildElements();
            while (it.hasNext()) {
                Node node = (Node) it.next();
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    childElem = node;
                    break;
                }
            }
            if (childElem == null)
                throw new SOAPException("SOAP body child element not found");

            String requestXml = null;

            boolean oldStyleRpcRequest = false;
            if (request.getServletPath().endsWith(RPC_SERVICE_PATH)
                    || RPC_SERVICE_PATH.equals(request.getPathInfo())) {
                NodeList nodes = childElem.getChildNodes();
                for (int i = 0; i < nodes.getLength(); i++) {
                    if (StringUtils.isNotBlank(nodes.item(i).getNodeName())
                            && nodes.item(i).getNodeName().equals("RequestDetails")) {
                        oldStyleRpcRequest = true;
                        Node requestNode = nodes.item(i).getFirstChild();
                        if (requestNode.getNodeType() == Node.CDATA_SECTION_NODE) {
                            requestXml = requestNode.getTextContent();
                        }
                        else {
                            requestXml = DomHelper.toXml(requestNode);
                            if (requestXml.contains("<"))
                                requestXml = StringEscapeUtils.unescapeXml(requestXml);
                        }
                    }
                }
            }
            else {
                requestXml = DomHelper.toXml(childElem);
            }

            metaInfo = addSoapMetaInfo(metaInfo, message);
            ListenerHelper helper = new ListenerHelper();

            try {
               authenticate(request, metaInfo, requestXml);
               String handlerResponse = helper.processEvent(requestXml, metaInfo);

               try {
                   // standard response indicates a potential problem
                   MDWStatusMessageDocument responseDoc = MDWStatusMessageDocument.Factory
                           .parse(handlerResponse, Compatibility.namespaceOptions());
                   MDWStatusMessage responseMsg = responseDoc.getMDWStatusMessage();
                   if ("SUCCESS".equals(responseMsg.getStatusMessage()))
                       responseString = createSoapResponse(soapVersion, handlerResponse);
                   else
                       responseString = createSoapFaultResponse(soapVersion,
                               String.valueOf(responseMsg.getStatusCode()),
                               responseMsg.getStatusMessage());
               }
               catch (XmlException xex) {
                   if (Listener.METAINFO_ERROR_RESPONSE_VALUE
                           .equalsIgnoreCase(metaInfo.get(Listener.METAINFO_ERROR_RESPONSE))) {
                       // Support for custom error response
                       responseString = handlerResponse;
                   }
                   else {
                       // not parseable as standard response doc (a good thing)
                       if (oldStyleRpcRequest) {
                           responseString = createOldStyleSoapResponse(soapVersion,
                                   ""
                                           + StringEscapeUtils.escapeXml(handlerResponse)
                                           + "");
                       }
                       else {
                           responseString = createSoapResponse(soapVersion, handlerResponse);
                       }
                   }
               }
            }
            catch (ServiceException ex) {
                logger.severeException(ex.getMessage(), ex);
                responseString = createSoapFaultResponse(soapVersion, String.valueOf(ex.getCode()), ex.getMessage());
            }
        }
        catch (Exception ex) {
            logger.severeException(ex.getMessage(), ex);
            try {
                responseString = createSoapFaultResponse(soapVersion, null, ex.getMessage());
            }
            catch (Exception tex) {
                logger.severeException(tex.getMessage(), tex);
            }
        }

        if (logger.isMdwDebugEnabled()) {
            logger.mdwDebug("SOAP Listener Servlet POST Response:\n" + responseString);
        }

        if (metaInfo.get(Listener.METAINFO_CONTENT_TYPE) != null) {
            response.setContentType(metaInfo.get(Listener.METAINFO_CONTENT_TYPE));
        }
        else {
            if (soapVersion.equals(SOAPConstants.SOAP_1_1_PROTOCOL))
                response.setContentType(Listener.CONTENT_TYPE_XML);
            else
                response.setContentType("application/soap+xml");
        }

        response.getOutputStream().print(responseString);

        timer.stopAndLogTiming("");
    }

    /**
     * 

* Gives a hint as to which version of SOAP using the rudimentary check * below. If the hint fails, it'll try the other version anyway. *

*
    *
  • SOAP 1.1 : http://schemas.xmlsoap.org/soap/envelope/
  • *
  • SOAP 1.2 : http://www.w3.org/2003/05/soap-envelope
  • *
*

* This is on a per-request basis and can't be static since we need to * support SOAP 1.1 and 1.2 *

* * @param requestString * @param goodguess * @return SOAP version 1 or 2 * @throws IOException * @throws SOAPException */ private String getSoapVersion(String requestString, boolean goodguess) { String guessedVersion = SOAPConstants.SOAP_1_1_PROTOCOL; String otherVersion = SOAPConstants.SOAP_1_2_PROTOCOL; if (requestString.contains(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE)) { guessedVersion = SOAPConstants.SOAP_1_2_PROTOCOL; otherVersion = SOAPConstants.SOAP_1_1_PROTOCOL; } return goodguess ? guessedVersion : otherVersion; } private String getRequestString(HttpServletRequest request) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); StringBuffer requestBuffer = new StringBuffer(); String line = null; while ((line = reader.readLine()) != null) { requestBuffer.append(line).append('\n'); } return requestBuffer.toString(); } protected String substituteRuntimeWsdl(String wsdl) { StringBuffer substituted = new StringBuffer(wsdl.length()); Matcher matcher = tokenPattern.matcher(wsdl); int index = 0; while (matcher.find()) { String match = matcher.group(); substituted.append(wsdl.substring(index, matcher.start())); String propName = match.substring(2, match.length() - 1); String value = PropertyManager.getProperty(propName); if (value != null) substituted.append(value); index = matcher.end(); } substituted.append(wsdl.substring(index)); return substituted.toString(); } protected Map addSoapMetaInfo(Map metaInfo, SOAPMessage soapMessage) throws SOAPException { SOAPHeader soapHeader = soapMessage.getSOAPHeader(); if (soapHeader == null) { return metaInfo; } else { Map newMetaInfo = new HashMap(); newMetaInfo.putAll(metaInfo); Iterator iter = soapHeader.examineAllHeaderElements(); while (iter.hasNext()) { SOAPHeaderElement headerElem = (SOAPHeaderElement) iter.next(); if (!Listener.AUTHENTICATED_USER_HEADER.equals(headerElem.getNodeName())) newMetaInfo.put(headerElem.getNodeName(), headerElem.getTextContent()); } return newMetaInfo; } } /** * Original API (Defaults to using MessageFactory.newInstance(), i.e. SOAP * 1.1) * * @param message * @return Soap fault as string * @throws SOAPException * @throws TransformerException */ protected String createSoapFaultResponse(String message) throws SOAPException, TransformerException { return createSoapFaultResponse(SOAPConstants.SOAP_1_1_PROTOCOL, null, message); } /** * Original API (Defaults to using MessageFactory.newInstance(), i.e. SOAP * 1.1) * * @param code * @param message * @return Soap fault as string * @throws SOAPException * @throws TransformerException */ protected String createSoapFaultResponse(String code, String message) throws SOAPException, TransformerException { return createSoapFaultResponse(SOAPConstants.SOAP_1_1_PROTOCOL, code, message); } /** * Allow version specific factory passed in to support SOAP 1.1 and 1.2 * Important Faults are treated differently for 1.1 and 1.2 For 1.2 * you can't use the elementName otherwise it throws an exception * * @see http://docs.oracle.com/cd/E19159-01/819-3669/bnbip/index.html * * @param factory * @param code * @param message * @return Xml fault string * @throws SOAPException * @throws TransformerException */ protected String createSoapFaultResponse(String soapVersion, String code, String message) throws SOAPException, TransformerException { SOAPMessage soapMessage = getSoapMessageFactory(soapVersion).createMessage(); SOAPBody soapBody = soapMessage.getSOAPBody(); /** * Faults are treated differently for 1.1 and 1.2 For 1.2 you can't use * the elementName otherwise it throws an exception * * @see http://docs.oracle.com/cd/E19159-01/819-3669/bnbip/index.html */ SOAPFault fault = null; if (soapVersion.equals(SOAPConstants.SOAP_1_1_PROTOCOL)) { // existing 1.1 functionality fault = soapBody.addFault(soapMessage.getSOAPHeader().getElementName(), message); if (code != null) fault.setFaultCode(code); } else if (soapVersion.equals(SOAPConstants.SOAP_1_2_PROTOCOL)) { /** * For 1.2 there are only a set number of allowed codes, so we can't * just use any one like what we did in 1.1. The recommended one to * use is SOAPConstants.SOAP_RECEIVER_FAULT */ fault = soapBody.addFault(SOAPConstants.SOAP_RECEIVER_FAULT, code == null ? message : code + " : " + message); } return DomHelper.toXml(soapMessage.getSOAPPart().getDocumentElement()); } /** * Original API (Defaults to using MessageFactory.newInstance(), i.e. SOAP * 1.1) * * @param xml * @return * @throws SOAPException */ protected String createSoapResponse(String xml) throws SOAPException { return createSoapResponse(SOAPConstants.SOAP_1_1_PROTOCOL, xml); } /** * Allow version specific factory passed in TODO: allow specifying response * headers */ protected String createSoapResponse(String soapVersion, String xml) throws SOAPException { try { SOAPMessage soapMessage = getSoapMessageFactory(soapVersion).createMessage(); SOAPBody soapBody = soapMessage.getSOAPBody(); soapBody.addDocument(DomHelper.toDomDocument(xml)); return DomHelper.toXml(soapMessage.getSOAPPart().getDocumentElement()); } catch (Exception ex) { throw new SOAPException(ex.getMessage(), ex); } } protected String createOldStyleSoapResponse(String soapVersion, String xml) throws SOAPException { try { SOAPMessage soapMessage = getSoapMessageFactory(soapVersion).createMessage(); SOAPBody soapBody = soapMessage.getSOAPBody(); soapBody.addDocument(DomHelper.toDomDocument(xml)); return DomHelper.toXmlNoWhiteSpace(soapMessage.getSOAPPart()); } catch (Exception ex) { throw new SOAPException(ex.getMessage(), ex); } } protected MessageFactory getSoapMessageFactory(String soapVersion) throws SOAPException { return MessageFactory.newInstance(soapVersion); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy