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

org.apache.axis2.builder.BuilderUtil Maven / Gradle / Ivy

There is a newer version: 5.0.22
Show newest version
/*
 * 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.builder;

import org.apache.axiom.attachments.Attachments;
import org.apache.axiom.attachments.lifecycle.LifecycleManager;
import org.apache.axiom.attachments.lifecycle.impl.LifecycleManagerImpl;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.OMXMLBuilderFactory;
import org.apache.axiom.om.OMXMLParserWrapper;
import org.apache.axiom.om.util.StAXParserConfiguration;
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.SOAPFactory;
import org.apache.axiom.soap.SOAPModelBuilder;
import org.apache.axiom.soap.SOAPProcessingException;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.deployment.DeploymentConstants;
import org.apache.axis2.description.AxisMessage;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.java.security.AccessController;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.util.JavaUtils;
import org.apache.axis2.util.MessageProcessorSelector;
import org.apache.axis2.util.MultipleEntryHashMap;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.commons.schema.*;

import javax.activation.DataHandler;
import javax.xml.namespace.QName;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Map;

public class BuilderUtil {
    private static final Log log = LogFactory.getLog(BuilderUtil.class);

    /**
     * @deprecated
     */
    public static final int BOM_SIZE = 4;

    public static SOAPEnvelope buildsoapMessage(MessageContext messageContext,
                                                MultipleEntryHashMap requestParameterMap,
                                                SOAPFactory soapFactory) throws AxisFault {

        SOAPEnvelope soapEnvelope = soapFactory.getDefaultEnvelope();
        SOAPBody body = soapEnvelope.getBody();
        XmlSchemaElement xmlSchemaElement;
        AxisOperation axisOperation = messageContext.getAxisOperation();
        if (axisOperation != null) {
            AxisMessage axisMessage =
                    axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
            xmlSchemaElement = axisMessage.getSchemaElement();

            if (xmlSchemaElement == null) {
                OMElement bodyFirstChild =
                        soapFactory
                                .createOMElement(messageContext.getAxisOperation().getName(), body);

                // if there is no schema its piece of cake !! add these to the soap body in any order you like.
                // Note : if there are parameters in the path of the URL, there is no way this can add them
                // to the message.
                createSOAPMessageWithoutSchema(soapFactory, bodyFirstChild, requestParameterMap);
            } else {

                // first get the target namespace from the schema and the wrapping element.
                // create an OMElement out of those information. We are going to extract parameters from
                // url, create OMElements and add them as children to this wrapping element.
                String targetNamespace = xmlSchemaElement.getQName().getNamespaceURI();
                QName bodyFirstChildQName;
                if (targetNamespace != null && !"".equals(targetNamespace)) {
                    bodyFirstChildQName = new QName(targetNamespace, xmlSchemaElement.getName());
                } else {
                    bodyFirstChildQName = new QName(xmlSchemaElement.getName());
                }
                OMElement bodyFirstChild = soapFactory.createOMElement(bodyFirstChildQName, body);

                // Schema should adhere to the IRI style in this. So assume IRI style and dive in to
                // schema
                XmlSchemaType schemaType = xmlSchemaElement.getSchemaType();
                if (schemaType instanceof XmlSchemaComplexType) {
                    XmlSchemaComplexType complexType = ((XmlSchemaComplexType)schemaType);
                    XmlSchemaParticle particle = complexType.getParticle();
                    if (particle instanceof XmlSchemaSequence || particle instanceof XmlSchemaAll) {

                        if (particle instanceof XmlSchemaSequence) {
                            XmlSchemaSequence sequence = (XmlSchemaSequence) particle;
                            // now we need to know some information from the binding operation.

                            for (XmlSchemaSequenceMember sequenceMember : sequence.getItems()) {

                                XmlSchemaElement innerElement = (XmlSchemaElement) sequenceMember;
                                QName qName = innerElement.getQName();
                                // ignoring the elements without proper type and minoccurs zero
                                if ((innerElement.getSchemaTypeName() == null) &&
                                    (innerElement.getMinOccurs() == 0)) {
                                    continue;
                                }
                                if (qName == null && innerElement.getSchemaTypeName()
                                        .equals(org.apache.ws.commons.schema.constants.Constants.XSD_ANYTYPE)) {
                                    createSOAPMessageWithoutSchema(soapFactory, bodyFirstChild,
                                                                   requestParameterMap);
                                    break;
                                }
                                checkMinOccurs(innerElement, qName, soapFactory, requestParameterMap,
                                               bodyFirstChild);
                            }
                        } else {
                            XmlSchemaAll sequence = (XmlSchemaAll) particle;
                            // now we need to know some information from the binding operation.

                            for (XmlSchemaAllMember sequenceMember : sequence.getItems()) {

                                XmlSchemaElement innerElement = (XmlSchemaElement) sequenceMember;
                                QName qName = innerElement.getQName();
                                // ignoring the elements without proper type and minoccurs zero
                                if ((innerElement.getSchemaTypeName() == null) &&
                                    (innerElement.getMinOccurs() == 0)) {
                                    continue;
                                }
                                if (qName == null && innerElement.getSchemaTypeName()
                                        .equals(org.apache.ws.commons.schema.constants.Constants.XSD_ANYTYPE)) {
                                    createSOAPMessageWithoutSchema(soapFactory, bodyFirstChild,
                                                                   requestParameterMap);
                                    break;
                                }
                                checkMinOccurs(innerElement, qName, soapFactory, requestParameterMap,
                                               bodyFirstChild);
                            }
                        }
                    }
                }else {
                    throw new AxisFault(xmlSchemaElement.getName() + " message element in schema should follow the " +
                            "(Internationalized Resource Identifier)IRI ) style to process request in REST style");
                }
            }
        }
        return soapEnvelope;
    }

    private static void checkMinOccurs(XmlSchemaElement innerElement, QName qName,
                                       SOAPFactory soapFactory,
                                       MultipleEntryHashMap requestParameterMap,
                                       OMElement bodyFirstChild)
            throws AxisFault {
        long minOccurs = innerElement.getMinOccurs();
        boolean nillable = innerElement.isNillable();
        String name =
                qName != null ? qName.getLocalPart() : innerElement.getName();
        Object value;
        OMNamespace ns = (qName == null ||
                          qName.getNamespaceURI() == null
                          || qName.getNamespaceURI().length() == 0) ?
                         null : soapFactory.createOMNamespace(
                qName.getNamespaceURI(), null);

        // FIXME changed
        while ((value = requestParameterMap.get(name)) != null) {
            addRequestParameter(soapFactory,
                                bodyFirstChild, ns, name, value);
            minOccurs--;
        }
        if (minOccurs > 0) {
            if (nillable) {

                OMNamespace xsi = soapFactory.createOMNamespace(
                        Constants.URI_DEFAULT_SCHEMA_XSI,
                        Constants.NS_PREFIX_SCHEMA_XSI);
                OMAttribute omAttribute =
                        soapFactory.createOMAttribute("nil", xsi, "true");
                soapFactory.createOMElement(name, ns,
                                            bodyFirstChild)
                        .addAttribute(omAttribute);

            } else {
                throw new AxisFault("Required element " + qName +
                                    " defined in the schema can not be" +
                                    " found in the request");
            }
        }
    }

    public static void createSOAPMessageWithoutSchema(SOAPFactory soapFactory,
                                                       OMElement bodyFirstChild,
                                                       MultipleEntryHashMap requestParameterMap) {

        // first add the parameters in the URL
        if (requestParameterMap != null) {
            for (Object o : requestParameterMap.keySet()) {
                String key = (String) o;
                Object value;
                while ((value = requestParameterMap.get(key)) != null) {
                    addRequestParameter(soapFactory, bodyFirstChild, null, key, value);
                }
            }
        }
    }

    private static void addRequestParameter(SOAPFactory soapFactory,
                                            OMElement bodyFirstChild,
                                            OMNamespace ns,
                                            String key,
                                            Object parameter) {
        if (parameter instanceof DataHandler) {
            DataHandler dataHandler = (DataHandler)parameter;
            OMText dataText = bodyFirstChild.getOMFactory().createOMText(
                    dataHandler, true);
            soapFactory.createOMElement(key, ns, bodyFirstChild).addChild(
                    dataText);
        } else {
            String textValue = parameter.toString();
            soapFactory.createOMElement(key, ns, bodyFirstChild).setText(
                    textValue);
        }
    }

    /**
     * Create a builder suitable for an XML message. This method uses
     * {@link StAXParserConfiguration#SOAP} to disallow document type declarations (that potentially
     * reference external entities).
     * 
     * @param in
     *            the input stream containing the plain XML message
     * @param encoding
     *            the charset encoding of the message or null if the parser should
     *            determine the charset encoding
     * @return the builder
     */
    public static OMXMLParserWrapper createPOXBuilder(InputStream in, String encoding) {
        return OMXMLBuilderFactory.createOMBuilder(StAXParserConfiguration.SOAP, in, encoding);
    }

    /**
     * @deprecated Instead of using this method, you should probably pass the {@link InputStream}
     *             directly to the XML parser. If the stream is not XML, you shouldn't be using this
     *             method anyway.
     */
    public static Reader getReader(final InputStream is, final String charSetEncoding)
            throws IOException {
        final PushbackInputStream is2 = getPushbackInputStream(is);
        final String encoding = getCharSetEncoding(is2, charSetEncoding);
        InputStreamReader inputStreamReader;
        try {
            inputStreamReader = (InputStreamReader)AccessController.doPrivileged(
                    new PrivilegedExceptionAction() {
                        public Object run() throws UnsupportedEncodingException {
                            return new InputStreamReader(is2, encoding);
                        }
                    }
            );
        } catch (PrivilegedActionException e) {
            throw (UnsupportedEncodingException)e.getException();
        }
        return new BufferedReader(inputStreamReader);
    }

    /**
     * @deprecated If you need a {@link PushbackInputStream} just construct one (with the
     *             appropriate size).
     */
    public static PushbackInputStream getPushbackInputStream(InputStream is) {
        return new PushbackInputStream(is, BOM_SIZE);
    }

    /**
     * @deprecated It's the role of the XML parser to determine the charset encoding and/or byte
     *             order using the algorithm described in the "Autodetection of Character Encodings"
     *             appendix of the XML spec. If you need this method, then something is wrong:
     *             probably you are using a {@link Reader} where you should use an
     *             {@link InputStream}.
     */
    public static String getCharSetEncoding(PushbackInputStream is2, String defaultEncoding)
            throws IOException {
        String encoding;
        byte bom[] = new byte[BOM_SIZE];
        int n, unread;

        n = is2.read(bom, 0, bom.length);

        if ((bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB) && (bom[2] == (byte)0xBF)) {
            encoding = "UTF-8";
            if (log.isDebugEnabled()) {
                log.debug("char set encoding set from BOM =" + encoding);
            }
            unread = n - 3;
        } else if ((bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF)) {
            encoding = "UTF-16BE";
            if (log.isDebugEnabled()) {
                log.debug("char set encoding set from BOM =" + encoding);
            }
            unread = n - 2;
        } else if ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE)) {
            encoding = "UTF-16LE";
            if (log.isDebugEnabled()) {
                log.debug("char set encoding set from BOM =" + encoding);
            }
            unread = n - 2;
        } else if ((bom[0] == (byte)0x00) && (bom[1] == (byte)0x00) && (bom[2] == (byte)0xFE)
                   && (bom[3] == (byte)0xFF)) {
            encoding = "UTF-32BE";
            if (log.isDebugEnabled()) {
                log.debug("char set encoding set from BOM =" + encoding);
            }
            unread = n - 4;
        } else if ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) && (bom[2] == (byte)0x00)
                   && (bom[3] == (byte)0x00)) {
            encoding = "UTF-32LE";
            if (log.isDebugEnabled()) {
                log.debug("char set encoding set from BOM =" + encoding);
            }
            unread = n - 4;
        } else {

            // Unicode BOM mark not found, unread all bytes
            encoding = defaultEncoding;
            if (log.isDebugEnabled()) {
                log.debug("char set encoding set from default =" + encoding);
            }
            unread = n;
        }

        if (unread > 0) {
            is2.unread(bom, (n - unread), unread);
        }
        return encoding;
    }


    public static String getEnvelopeNamespace(String contentType) {
        String soapNS = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
        if (contentType != null) {
            if (contentType.indexOf(SOAP12Constants.SOAP_12_CONTENT_TYPE) > -1) {
                // it is SOAP 1.2
                soapNS = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
            } else if (contentType.indexOf(SOAP11Constants.SOAP_11_CONTENT_TYPE) > -1) {
                // SOAP 1.1
                soapNS = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
            }
        }
        return soapNS;
    }

    /**
     * Extracts and returns the character set encoding from the Content-type header
     * 

* Example: "Content-Type: text/xml; charset=utf-8" would return "utf-8" * * @param contentType a content-type (from HTTP or MIME, for instance) * @return the character set encoding if found, or MessageContext.DEFAULT_CHAR_SET_ENCODING */ public static String getCharSetEncoding(String contentType) { if (log.isDebugEnabled()) { log.debug("Input contentType (" + contentType + ")"); } if (contentType == null) { // Using the default UTF-8 if (log.isDebugEnabled()) { log.debug("CharSetEncoding defaulted (" + MessageContext.DEFAULT_CHAR_SET_ENCODING + ")"); } return MessageContext.DEFAULT_CHAR_SET_ENCODING; } int index = contentType.indexOf(HTTPConstants.CHAR_SET_ENCODING); if (index == -1) { // Charset encoding not found in the content-type header // Using the default UTF-8 if (log.isDebugEnabled()) { log.debug("CharSetEncoding defaulted (" + MessageContext.DEFAULT_CHAR_SET_ENCODING + ")"); } return MessageContext.DEFAULT_CHAR_SET_ENCODING; } // If there are spaces around the '=' sign int indexOfEq = contentType.indexOf("=", index); // There can be situations where "charset" is not the last parameter of the Content-Type header int indexOfSemiColon = contentType.indexOf(";", indexOfEq); String value; if (indexOfSemiColon > 0) { value = (contentType.substring(indexOfEq + 1, indexOfSemiColon)); } else { value = (contentType.substring(indexOfEq + 1, contentType.length())).trim(); } // There might be "" around the value - if so remove them if (value.indexOf('\"') != -1) { value = value.replaceAll("\"", ""); } value = value.trim(); if (log.isDebugEnabled()) { log.debug("CharSetEncoding from content-type (" + value + ")"); } return value; } public static Attachments createAttachmentsMap(MessageContext msgContext, InputStream inStream, String contentTypeString) { boolean fileCacheForAttachments = isAttachmentsCacheEnabled(msgContext); String attachmentRepoDir = null; String attachmentSizeThreshold = null; if (fileCacheForAttachments) { Object attachmentRepoDirProperty = msgContext .getProperty(Constants.Configuration.ATTACHMENT_TEMP_DIR); if (attachmentRepoDirProperty != null) { attachmentRepoDir = (String)attachmentRepoDirProperty; } else { Parameter attachmentRepoDirParameter = msgContext .getParameter(Constants.Configuration.ATTACHMENT_TEMP_DIR); attachmentRepoDir = (attachmentRepoDirParameter != null) ? (String)attachmentRepoDirParameter .getValue() : null; } Object attachmentSizeThresholdProperty = msgContext .getProperty(Constants.Configuration.FILE_SIZE_THRESHOLD); if (attachmentSizeThresholdProperty != null && attachmentSizeThresholdProperty instanceof String) { attachmentSizeThreshold = (String)attachmentSizeThresholdProperty; } else { Parameter attachmentSizeThresholdParameter = msgContext .getParameter(Constants.Configuration.FILE_SIZE_THRESHOLD); attachmentSizeThreshold = attachmentSizeThresholdParameter != null ? attachmentSizeThresholdParameter.getValue().toString() : null; } } // Get the content-length if it is available int contentLength = 0; Map headers = (Map)msgContext.getProperty(MessageContext.TRANSPORT_HEADERS); if (headers != null) { String contentLengthValue = (String)headers.get(HTTPConstants.HEADER_CONTENT_LENGTH); if (contentLengthValue != null) { try { contentLength = new Integer(contentLengthValue); } catch (NumberFormatException e) { if (log.isDebugEnabled()) { log.debug( "Content-Length is not a valid number. Will assume it is not set:" + e); } } } } if (log.isDebugEnabled()) { if (contentLength > 0) { log.debug("Creating an Attachments map. The content-length is" + contentLength); } else { log.debug("Creating an Attachments map."); } } return createAttachments(msgContext, inStream, contentTypeString, fileCacheForAttachments, attachmentRepoDir, attachmentSizeThreshold, contentLength); } public static boolean isAttachmentsCacheEnabled(MessageContext msgContext) { Object cacheAttachmentProperty = msgContext .getProperty(Constants.Configuration.CACHE_ATTACHMENTS); String cacheAttachmentString; boolean fileCacheForAttachments; if (cacheAttachmentProperty != null && cacheAttachmentProperty instanceof String) { cacheAttachmentString = (String)cacheAttachmentProperty; } else { Parameter parameter_cache_attachment = msgContext.getParameter(Constants.Configuration.CACHE_ATTACHMENTS); cacheAttachmentString = (parameter_cache_attachment != null) ? (String)parameter_cache_attachment.getValue() : null; } fileCacheForAttachments = (Constants.VALUE_TRUE.equals(cacheAttachmentString)); return fileCacheForAttachments; } public static Attachments createAttachments(MessageContext msgContext, InputStream inStream, String contentTypeString, boolean fileCacheForAttachments, String attachmentRepoDir, String attachmentSizeThreshold, int contentLength) { LifecycleManager manager = null; try { AxisConfiguration configuration = msgContext.getRootContext().getAxisConfiguration(); manager = (LifecycleManager)configuration .getParameterValue(DeploymentConstants.ATTACHMENTS_LIFECYCLE_MANAGER); if (manager == null) { manager = new LifecycleManagerImpl(); configuration.addParameter(DeploymentConstants.ATTACHMENTS_LIFECYCLE_MANAGER, manager); } } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Exception getting Attachments LifecycleManager", e); } } return new Attachments(manager, inStream, contentTypeString, fileCacheForAttachments, attachmentRepoDir, attachmentSizeThreshold, contentLength); } /** * Create a SOAP model builder. This method delegates to * {@link OMXMLBuilderFactory#createSOAPModelBuilder(InputStream, String)} but generates * additional logging if an error occurs. * * @param in * the input stream containing the SOAP message * @param encoding * the charset encoding of the SOAP message or null if the parser should * determine the charset encoding * @return the builder */ public static SOAPModelBuilder createSOAPModelBuilder(InputStream in, String encoding) { try { return OMXMLBuilderFactory.createSOAPModelBuilder(in, encoding); } catch (OMException e) { log.info("OMException in getSOAPBuilder", e); try { log.info("Remaining input stream :[" + new String(IOUtils.toByteArray(in), encoding) + "]"); } catch (IOException e1) { // Nothing here? } throw e; } } /** * @deprecated Use {@link MessageProcessorSelector#getMessageBuilder(String, MessageContext)}. */ public static Builder getBuilderFromSelector(String type, MessageContext msgContext) throws AxisFault { return MessageProcessorSelector.getMessageBuilder(type, msgContext); } public static void validateSOAPVersion(String soapNamespaceURIFromTransport, SOAPEnvelope envelope) { if (soapNamespaceURIFromTransport != null) { OMNamespace envelopeNamespace = envelope.getNamespace(); String namespaceName = envelopeNamespace.getNamespaceURI(); if (!(soapNamespaceURIFromTransport.equals(namespaceName))) { throw new SOAPProcessingException( "Transport level information does not match with SOAP" + " Message namespace URI", envelopeNamespace.getPrefix() + ":" + SOAPConstants.FAULT_CODE_VERSION_MISMATCH); } } } public static void validateCharSetEncoding(String charsetEncodingFromTransport, String charsetEncodingFromXML, String soapNamespaceURI) throws AxisFault { if ((charsetEncodingFromXML != null) && !"".equals(charsetEncodingFromXML) && (charsetEncodingFromTransport != null) && !charsetEncodingFromXML.equalsIgnoreCase(charsetEncodingFromTransport) && !compatibleEncodings(charsetEncodingFromXML, charsetEncodingFromTransport)) { /** * WS-BP Rule 1019 requires toleration if the character sets mismatch * I am changing this to simply a debug statement. String faultCode; if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(soapNamespaceURI)) { faultCode = SOAP12Constants.FAULT_CODE_SENDER; } else { faultCode = SOAP11Constants.FAULT_CODE_SENDER; } throw new AxisFault("Character Set Encoding from " + "transport information [" + charsetEncodingFromTransport + "] does not match with " + "character set encoding in the received SOAP message [" + charsetEncodingFromXML + "]", faultCode); **/ if (log.isDebugEnabled()) { log.debug("Character Set Encoding from " + "transport information [" + charsetEncodingFromTransport + "] does not match with " + "character set encoding in the received SOAP message [" + charsetEncodingFromXML + "]"); } } } /** * check if the pair is [UTF-16,UTF-16LE] [UTF-32, UTF-32LE],[UTF-16,UTF-16BE] [UTF-32, * UTF-32BE] etc. * * @param enc1 encoding style * @param enc2 encoding style * @return true if the encoding styles are compatible, or false otherwise */ private static boolean compatibleEncodings(String enc1, String enc2) { enc1 = enc1.toLowerCase(); enc2 = enc2.toLowerCase(); if (enc1.endsWith("be") || enc1.endsWith("le")) { enc1 = enc1.substring(0, enc1.length() - 2); } if (enc2.endsWith("be") || enc2.endsWith("le")) { enc2 = enc2.substring(0, enc2.length() - 2); } return enc1.equals(enc2); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy