/*
 * 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.kernel;

import org.apache.axiom.attachments.Attachments;
import org.apache.axiom.attachments.CachedFileDataSource;
import org.apache.axiom.attachments.lifecycle.LifecycleManager;
import org.apache.axiom.mime.ContentType;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.om.OMXMLParserWrapper;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPModelBuilder;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.builder.Builder;
import org.apache.axis2.builder.BuilderUtil;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.deployment.DeploymentConstants;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.kernel.http.HTTPConstants;
import org.apache.axis2.util.JavaUtils;
import org.apache.axis2.util.MessageProcessorSelector;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import jakarta.activation.DataSource;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.util.List;
import java.util.Optional;

public class TransportUtils {

    private static final Log log = LogFactory.getLog(TransportUtils.class);

    public static SOAPEnvelope createSOAPMessage(MessageContext msgContext) throws AxisFault {
        return createSOAPMessage(msgContext, false);
    }

    /**
     * This method will create a SOAPEnvelope based on the InputStream stored on
     * the MessageContext. The 'detach' parameter controls whether or not the
     * underlying DetachableInputStream is detached at the end of the method. Note,
     * detaching the DetachableInputStream closes the underlying InputStream that
     * is stored on the MessageContext.
     */
    public static SOAPEnvelope createSOAPMessage(MessageContext msgContext,
                                                 boolean detach) throws AxisFault {
//        final SOAPEnvelope envelope = msgContext.getEnvelope();
//        if (envelope != null) {
//            if (envelope.isComplete())
//                return envelope;
//        }
        try {
            InputStream inStream = (InputStream) msgContext
                    .getProperty(MessageContext.TRANSPORT_IN);
            msgContext.setProperty(MessageContext.TRANSPORT_IN, null);

            // this inputstram is set by the TransportSender represents a two
            // way transport or a Transport Recevier
            if (inStream == null) {
                throw new AxisFault(Messages.getMessage("inputstreamNull"));
            }

            String contentType = (String) msgContext
                    .getProperty(Constants.Configuration.CONTENT_TYPE);

            // get the type of char encoding
            String charSetEnc = (String) msgContext
                    .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
            if (charSetEnc == null && contentType != null) {
                charSetEnc = BuilderUtil.getCharSetEncoding(contentType);
            } else if (charSetEnc == null) {
                charSetEnc = MessageContext.DEFAULT_CHAR_SET_ENCODING;
            }
            msgContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING, charSetEnc);

            SOAPEnvelope env = createSOAPMessage(msgContext, inStream, contentType);

            if(detach) {
                detachInputStream(msgContext);
            }
            return env;
        } catch (Exception e) {
            throw AxisFault.makeFault(e);
        }
    }

    /**
     * Objective of this method is to capture the SOAPEnvelope creation logic
     * and make it a common for all the transports and to in/out flows.
     *
     * @param msgContext message context
     * @param inStream input stream
     * @param contentType content type of the message
     * @return the SOAPEnvelope
     * @throws AxisFault if an error occurs
     * @throws OMException if the xml is invalid
     * @throws XMLStreamException if the stream is invalid
     * @throws FactoryConfigurationError
     */
    public static SOAPEnvelope createSOAPMessage(MessageContext msgContext,
                                                 InputStream inStream,
                                                 String contentType)
            throws AxisFault, OMException, XMLStreamException,
            FactoryConfigurationError {
        OMElement documentElement = createDocumentElement(contentType, msgContext, inStream);
        return createSOAPEnvelope(documentElement);
    }

    /**
     * Objective of this method is to capture the SOAPEnvelope creation logic
     * and make it a common for all the transports and to in/out flows.
     *
     * @param msgContext message context
     * @param inStream input stream
     * @param contentType content type of the message
     * @param builder the builder to be used
     * @return the SOAPEnvelope
     * @throws AxisFault if an error occurs
     * @throws OMException if the xml is invalid
     * @throws XMLStreamException if the stream is invalid
     * @throws FactoryConfigurationError
     */
    public static SOAPEnvelope createSOAPMessage(MessageContext msgContext,
                                                 InputStream inStream,
                                                 String contentType,
                                                 Builder builder)
            throws AxisFault, OMException, XMLStreamException, FactoryConfigurationError {
        OMElement documentElement = createDocumentElement(contentType, builder,
                msgContext, inStream);
        return createSOAPEnvelope(documentElement);
    }

    public static SOAPEnvelope createSOAPEnvelope(OMElement documentElement) {
        SOAPEnvelope envelope;
        // Check whether we have received a SOAPEnvelope or not
        if (documentElement instanceof SOAPEnvelope) {
            envelope = (SOAPEnvelope) documentElement;
        } else {
            // If it is not a SOAPEnvelope we wrap that with a fake
            // SOAPEnvelope.
            SOAPFactory soapFactory = OMAbstractFactory.getSOAP11Factory();
            envelope = soapFactory.getDefaultEnvelope();
            if (documentElement != null) {
                envelope.getBody().addChild(documentElement);
            }
        }
        return envelope;
    }

    public static OMElement createDocumentElement(String contentType,
                                                  MessageContext msgContext,
                                                  InputStream inStream)
            throws AxisFault, XMLStreamException {
        OMElement documentElement = null;
        String type = null;
        if (contentType != null) {
            type = getContentType(contentType, msgContext);
            Builder builder = MessageProcessorSelector.getMessageBuilder(type, msgContext);
            if (builder != null) {
                if (log.isDebugEnabled()) {
                    log.debug("createSOAPEnvelope using Builder (" +
                              builder.getClass() + ") selected from type (" + type);
                }
                documentElement = builder.processDocument(inStream, contentType, msgContext);
            }
        }
        if (documentElement == null) {
            documentElement = createDefaultDocumentElement(msgContext, inStream, type);
        }
        return documentElement;
    }

    private static OMElement createDefaultDocumentElement(MessageContext msgContext,
                                                          InputStream inStream, String type) {
        OMElement documentElement;
        if (msgContext.isDoingREST()) {
            if (log.isDebugEnabled()) {
                log.debug("Could not find a Builder for type (" + type + ").  Using REST.");
            }
            OMXMLParserWrapper builder = BuilderUtil.createPOXBuilder(inStream, null);
            documentElement = builder.getDocumentElement();
        } else {
            // FIXME making soap defualt for the moment..might effect the
            // performance
            if (log.isDebugEnabled()) {
                log.debug("Could not find a Builder for type (" + type + ").  Using SOAP.");
            }
            String charSetEnc = (String) msgContext
                    .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
            SOAPModelBuilder builder = BuilderUtil.createSOAPModelBuilder(inStream, charSetEnc);
            documentElement = builder.getDocumentElement();
        }
        return documentElement;
    }

    public static OMElement createDocumentElement(String contentType, Builder builder,
                                                  MessageContext msgContext,
                                                  InputStream inStream)
            throws AxisFault, XMLStreamException {
        OMElement documentElement = null;
        String type = null;
        if (contentType != null) {
            type = getContentType(contentType, msgContext);
            if (builder != null) {
                if (log.isDebugEnabled()) {
                    log.debug("createSOAPEnvelope using Builder (" +
                              builder.getClass() + ") selected from type (" + type +")");
                }
                documentElement = builder.processDocument(inStream, contentType, msgContext);
            }
        }

        if (documentElement == null) {
            documentElement = createDefaultDocumentElement(msgContext, inStream, type);
        }
        return documentElement;
    }

    public static String getContentType(String contentType, MessageContext msgContext) {
        String type;
        int index = contentType.indexOf(';');
        if (index > 0) {
            type = contentType.substring(0, index);
        } else {
            type = contentType;
        }
        // Some services send REST responces as text/xml. We should convert it to
        // application/xml if its a REST response, if not it will try to use the SOAPMessageBuilder.
        // isDoingREST should already be properly set by HTTPTransportUtils.initializeMessageContext
        if (msgContext.isDoingREST() && HTTPConstants.MEDIA_TYPE_TEXT_XML.equals(type)) {
            if (msgContext.isServerSide()) {
                if (msgContext.getSoapAction() == null) {
                    // TODO - remove this logic. 
                    //type = HTTPConstants.MEDIA_TYPE_APPLICATION_XML;
                }
            } else if (!msgContext.isPropertyTrue(Constants.Configuration.SOAP_RESPONSE_MEP)) {
                type = HTTPConstants.MEDIA_TYPE_APPLICATION_XML;
            }
        }
        return type;
    }

    /**
     * Extracts and returns the character set encoding from the
     * Content-type header
     * Example:
     * Content-Type: text/xml; charset=utf-8
     *
     * @param contentType
     */
    public static String getCharSetEncoding(String contentType) {
        if (log.isDebugEnabled()) {
            log.debug("Input contentType (" + contentType + ")");
        }
        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 void writeMessage(MessageContext msgContext, OutputStream out) throws AxisFault {
        SOAPEnvelope envelope = msgContext.getEnvelope();
        OMElement outputMessage = envelope;

        if ((envelope != null) && msgContext.isDoingREST()) {
            outputMessage = envelope.getBody().getFirstElement();
        }

        if (outputMessage != null) {
            try {
                OMOutputFormat format = new OMOutputFormat();

                // Pick the char set encoding from the msgContext
                String charSetEnc =
                        (String) msgContext
                                .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);

                format.setDoOptimize(false);
                format.setDoingSWA(false);
                format.setCharSetEncoding(charSetEnc);
                outputMessage.serializeAndConsume(out, format);
                out.flush();
            } catch (Exception e) {
                throw AxisFault.makeFault(e);
            }
        } else {
            throw new AxisFault(Messages.getMessage("outMessageNull"));
        }
    }




    /**
     * @param contentType          The contentType of the incoming message.  It may be null
     * @param defaultSOAPNamespace Usually set the version that is expected.  This a fallback if the contentType is unavailable or
     *                             does not match our expectations
     * @return null or the soap namespace.  A null indicates that the message will be interpretted as a non-SOAP (i.e. REST) message
     */
    private static String getSOAPNamespaceFromContentType(String contentType,
                                                          String defaultSOAPNamespace) {

        String returnNS = defaultSOAPNamespace;
        // Discriminate using the content Type
        if (contentType != null) {

            /*
            * SOAP11 content-type is "text/xml"
            * SOAP12 content-type is "application/soap+xml"
            *
            * What about other content-types?
            *
            * TODO: I'm not fully convinced this method is complete, given the media types
            * listed in HTTPConstants.  Should we assume all application/* is SOAP12?
            * Should we assume all text/* is SOAP11?
            *
            * So, we'll follow this pattern:
            * 1)  find the content-type main setting
            * 2)  if (1) not understood, find the "type=" param
            * Thilina: I merged (1) & (2)
            */

            if (JavaUtils.indexOfIgnoreCase(contentType, SOAP12Constants.SOAP_12_CONTENT_TYPE) > -1)
            {
                returnNS = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
            }
            // search for "type=text/xml"
            else
            if (JavaUtils.indexOfIgnoreCase(contentType, SOAP11Constants.SOAP_11_CONTENT_TYPE) > -1)
            {
                returnNS = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
            }
        }

        if (returnNS == null) {
            if (log.isDebugEnabled()) {
                log.debug("No content-type or \"type=\" parameter was found in the content-type " +
                        "header and no default was specified, thus defaulting to SOAP 1.1.");
            }
            returnNS = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
        }

        if (log.isDebugEnabled()) {
            log.debug("content-type: " + contentType);
            log.debug("defaultSOAPNamespace: " + defaultSOAPNamespace);
            log.debug("Returned namespace: " + returnNS);
        }
        return returnNS;

    }

    public static void processContentTypeForAction(String contentType, MessageContext msgContext) {
        //Check for action header and set it in as soapAction in MessageContext
        try {
            ContentType ct = new ContentType(contentType);
            String startInfo = ct.getParameter("start-info");
            if (startInfo != null) {
                Optional.ofNullable(new ContentType(startInfo).getParameter("action"))
                        .ifPresent(msgContext::setSoapAction);
            }
            Optional.ofNullable(ct.getParameter("action"))
                    .ifPresent(msgContext::setSoapAction);
        } catch (ParseException e) {
            if (log.isDebugEnabled()) {
                log.debug("Failed to parse Content-Type Header: " + e.getMessage(), e);
            }
        }
    }

    /**
     * This is a helper method to get the response written flag from the RequestResponseTransport
     * instance.
     */
    public static boolean isResponseWritten(MessageContext messageContext) {
        RequestResponseTransport reqResTransport = getRequestResponseTransport(messageContext);
        if (reqResTransport != null) {
            if (log.isDebugEnabled()) {
                log.debug("Found RequestResponseTransport returning isResponseWritten()");
            }
            return reqResTransport.isResponseWritten();
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Did not find RequestResponseTransport returning false from get"
                        + "ResponseWritten()");
            }
            return false;
        }
    }

    /**
     * This is a helper method to set the response written flag on the RequestResponseTransport
     * instance.
     */
    public static void setResponseWritten(MessageContext messageContext, boolean responseWritten) {
        RequestResponseTransport reqResTransport = getRequestResponseTransport(messageContext);
        if (reqResTransport != null) {
            if (log.isDebugEnabled()) {
                log.debug("Found RequestResponseTransport setting response written");
            }
            reqResTransport.setResponseWritten(responseWritten);
        } else {
            if (log.isDebugEnabled()) {
               log.debug("Did not find RequestResponseTransport cannot set response written");
            }
        }
    }

    /**
     * This is an internal helper method to retrieve the RequestResponseTransport instance
     * from the MessageContext object. The MessageContext may be the response MessageContext so
     * in that case we will have to retrieve the request MessageContext from the OperationContext.
     */
    private static RequestResponseTransport getRequestResponseTransport(MessageContext messageContext) {
        try {
            // If this is the request MessageContext we should find it directly by the getProperty()
            // method
            RequestResponseTransport transportControl = (RequestResponseTransport)
                    messageContext.getProperty(RequestResponseTransport.TRANSPORT_CONTROL);
            
            if (transportControl != null) {
                return transportControl;
            }
            // If this is the response MessageContext we need to look for the request MessageContext
            else if (messageContext.getOperationContext() != null
                    && messageContext.getOperationContext().getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE) != null) {
                return (RequestResponseTransport) messageContext.getOperationContext().getMessageContext(
                        WSDLConstants.MESSAGE_LABEL_IN_VALUE).getProperty(RequestResponseTransport.TRANSPORT_CONTROL);
            }
            else {
                return null;
            }
        }
        catch(AxisFault af) {
            // probably should not be fatal, so just log the message
            String msg = Messages.getMessage("getMessageContextError", af.toString());
            log.debug(msg);
            return null;
        }
    }

    /**
     * Clean up cached attachment file
     * @param msgContext
     */
    public static void deleteAttachments(MessageContext msgContext) {
        if (log.isDebugEnabled()) {
            log.debug("Entering deleteAttachments()");
        }

        // Check if enableJSONOnly is true - if so, skip attachment cleanup to avoid loading Axiom
        AxisService axisService = msgContext.getAxisService();
        if (axisService != null) {
            String enableJSONOnly = (String) axisService.getParameterValue("enableJSONOnly");
            if (enableJSONOnly != null && enableJSONOnly.equalsIgnoreCase("true")) {
                if (log.isDebugEnabled()) {
                    log.debug("Skipping deleteAttachments() due to enableJSONOnly=true");
                }
                return;
            }
        }

        Attachments attachments = msgContext.getAttachmentMap();

        if (attachments != null) {
            // Get the list of Content IDs for the attachments...but does not try to pull the stream for new attachments.
            // (Pulling the stream for new attachments will probably fail...the stream is probably closed)
            List keys = attachments.getContentIDList();
            if (keys != null && keys.size() > 0) {
                String key = null;
                File file = null;
                LifecycleManager lcm = (LifecycleManager)msgContext.getRootContext().getAxisConfiguration().getParameterValue(DeploymentConstants.ATTACHMENTS_LIFECYCLE_MANAGER);                       
                DataSource dataSource = null;
                for (int i = 0; i < keys.size(); i++) {
                    try {
                        key = (String) keys.get(i);
                        dataSource = attachments.getDataHandler(key).getDataSource();
                        if(dataSource instanceof CachedFileDataSource){
                            file = ((CachedFileDataSource)dataSource).getFile();
                            if (log.isDebugEnabled()) {
                                log.debug("Delete cache attachment file: "+file.getName());
                            }
                            if(lcm!=null){
                                if(log.isDebugEnabled()){
                                    log.debug("deleting file using lifecyclemanager");
                                }
                                lcm.delete(file);
                            }else{
                                file.delete();
                            }
                        }
                    }
                    catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug("Delete cache attachment file failed"+ e.getMessage());
                        }

                        if (file != null) {
                            if(lcm!=null){
                                try{
                                    lcm.deleteOnExit(file);
                                }catch(Exception ex){
                                    file.deleteOnExit();
                                }
                            }
                            else{
                                file.deleteOnExit();
                            }
                        }
                    }
                }
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("Exiting deleteAttachments()");
        }
    }

    /**
     * Prepare the message in the given message context so that the underlying input stream can be
     * closed.
     * 
     * @param msgContext
     */
    public static void detachInputStream(MessageContext msgContext) throws AxisFault {
        if (msgContext != null) {
            OMXMLParserWrapper builder = (OMXMLParserWrapper)msgContext.getProperty(Constants.BUILDER);
            if (builder != null) {
                builder.detach();
            } else {
                Attachments attachments = msgContext.getAttachmentMap(false);
                if (attachments != null) {
                    attachments.getAllContentIDs();
                } else {
                    SOAPEnvelope envelope = msgContext.getEnvelope();
                    if (envelope != null) {
                        envelope.build();
                    }
                }
            }
        }
    }

    /**
     * <p>
     * Checks whether MTOM needs to be enabled for the message represented by
     * the msgContext. We check value assigned to the "enableMTOM" property
     * either using the config files (axis2.xml, services.xml) or
     * programatically. Programatic configuration is given priority. If the
     * given value is "optional", MTOM will be enabled only if the incoming
     * message was an MTOM message.
     * </p>
     *
     * @param msgContext the active MessageContext
     * @return true if SwA needs to be enabled
     */
    public static boolean doWriteMTOM(MessageContext msgContext) {
        boolean enableMTOM;
        Object enableMTOMObject = null;
        // First check the whether MTOM is enabled by the configuration
        // (Eg:Axis2.xml, services.xml)
        Parameter parameter = msgContext.getParameter(Constants.Configuration.ENABLE_MTOM);
        if (parameter != null) {
            enableMTOMObject = parameter.getValue();
        }
        // Check whether the configuration is overridden programatically..
        // Priority given to programatically setting of the value
        Object property = msgContext.getProperty(Constants.Configuration.ENABLE_MTOM);
        if (property != null) {
            enableMTOMObject = property;
        }
        enableMTOM = JavaUtils.isTrueExplicitly(enableMTOMObject);
        // Handle the optional value for enableMTOM
        // If the value for 'enableMTOM' is given as optional and if the request
        // message was a MTOM message we sent out MTOM
        if (!enableMTOM && msgContext.isDoingMTOM() && (enableMTOMObject instanceof String)) {
            if (((String) enableMTOMObject).equalsIgnoreCase(Constants.VALUE_OPTIONAL)) {
                //In server side, we check whether request was MTOM
                if (msgContext.isServerSide()) {
                    if (msgContext.isDoingMTOM()) {
                        enableMTOM = true;
                    }
                    // in the client side, we enable MTOM if it is optional
                } else {
                    enableMTOM = true;
                }
            }
        }
        return enableMTOM;
    }

    /**
     * <p>
     * Checks whether SOAP With Attachments (SwA) needs to be enabled for the
     * message represented by the msgContext. We check value assigned to the
     * "enableSwA" property either using the config files (axis2.xml,
     * services.xml) or programatically. Programatic configuration is given
     * priority. If the given value is "optional", SwA will be enabled only if
     * the incoming message was SwA type.
     * </p>
     *
     * @param msgContext the active MessageContext
     * @return true if SwA needs to be enabled
     */
    public static boolean doWriteSwA(MessageContext msgContext) {
        boolean enableSwA;
        Object enableSwAObject = null;
        // First check the whether SwA is enabled by the configuration
        // (Eg:Axis2.xml, services.xml)
        Parameter parameter = msgContext.getParameter(Constants.Configuration.ENABLE_SWA);
        if (parameter != null) {
            enableSwAObject = parameter.getValue();
        }
        // Check whether the configuration is overridden programatically..
        // Priority given to programatically setting of the value
        Object property = msgContext.getProperty(Constants.Configuration.ENABLE_SWA);
        if (property != null) {
            enableSwAObject = property;
        }
        enableSwA = JavaUtils.isTrueExplicitly(enableSwAObject);
        // Handle the optional value for enableSwA
        // If the value for 'enableSwA' is given as optional and if the request
        // message was a SwA message we sent out SwA
        if (!enableSwA && msgContext.isDoingSwA() && (enableSwAObject instanceof String)) {
            if (((String) enableSwAObject).equalsIgnoreCase(Constants.VALUE_OPTIONAL)) {
                enableSwA = true;
            }
        }
        return enableSwA;
    }

    public static boolean isDoingREST(MessageContext msgContext) {
        boolean enableREST = false;

        // check whether isDoingRest is already true in the message context
        if (msgContext.isDoingREST()) {
            return true;
        }

        Object enableRESTProperty = msgContext.getProperty(Constants.Configuration.ENABLE_REST);
        if (enableRESTProperty != null) {
            enableREST = JavaUtils.isTrueExplicitly(enableRESTProperty);
        }

        msgContext.setDoingREST(enableREST);

        return enableREST;
    }

    /**
     * Utility method to query CharSetEncoding. First look in the
     * MessageContext. If it's not there look in the OpContext. Use the defualt,
     * if it's not given in either contexts.
     *
     * @param msgContext the active MessageContext
     * @return String the CharSetEncoding
     */
    public static String getCharSetEncoding(MessageContext msgContext) {
        String charSetEnc = (String) msgContext
            .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);

        if (charSetEnc == null) {
            OperationContext opctx = msgContext.getOperationContext();
            if (opctx != null) {
                charSetEnc = (String) opctx
                    .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
            }
            /**
             * If the char set enc is still not found use the default
             */
            if (charSetEnc == null) {
                charSetEnc = MessageContext.DEFAULT_CHAR_SET_ENCODING;
            }
        }
        return charSetEnc;
    }

}
