org.wso2.carbon.core.multitenancy.MultitenantMessageReceiver.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.core.multitenancy.MultitenantMessageReceiver.java

Source

/*                                                                             
 * Copyright 2004,2005 The Apache Software Foundation.                         
 *                                                                             
 * 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 org.wso2.carbon.core.multitenancy;

import org.apache.axiom.attachments.Attachments;
import org.apache.axiom.om.util.UUIDGenerator;
import org.apache.axiom.util.UIDGenerator;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.builder.BuilderUtil;
import org.apache.axis2.client.Options;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.description.AxisBindingOperation;
import org.apache.axis2.description.AxisEndpoint;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.TransportInDescription;
import org.apache.axis2.description.TransportOutDescription;
import org.apache.axis2.description.WSDL2Constants;
import org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher;
import org.apache.axis2.dispatchers.RequestURIBasedDispatcher;
import org.apache.axis2.dispatchers.RequestURIOperationDispatcher;
import org.apache.axis2.engine.AxisEngine;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.engine.MessageReceiver;
import org.apache.axis2.transport.RequestResponseTransport;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.util.MessageContextBuilder;
import org.apache.axis2.util.Utils;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.multitenancy.utils.TenantAxisUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;

/**
 * This MessageReceiver will try to locate the tenant specific AxisConfiguration and dispatch the
 * request to that AxisConfiguration. Dispatching to the actual service & operation will happen
 * within the tenant specific AxisConfiguration.
 */
public class MultitenantMessageReceiver implements MessageReceiver {

    private static final String TENANT_DELIMITER = "/t/";
    private static final Log log = LogFactory.getLog(MultitenantMessageReceiver.class);

    public void receive(MessageContext mainInMsgContext) throws AxisFault {

        EndpointReference toEpr = getDestinationEPR(mainInMsgContext);
        if (toEpr != null) {
            // this is a request coming in to the multitenant environment
            processRequest(mainInMsgContext);
        } else {
            // this is a response coming from a dual channel invocation or a
            // non blocking transport like esb
            processResponse(mainInMsgContext);
        }
    }

    /**
     * Process a response message coming in the multitenant environment
     *
     * @param mainInMsgContext supertenant MessageContext
     * @throws AxisFault if an error occurs
     */
    private void processResponse(MessageContext mainInMsgContext) throws AxisFault {
        MessageContext requestMsgCtx = mainInMsgContext.getOperationContext()
                .getMessageContext(WSDL2Constants.MESSAGE_LABEL_IN);
        if (requestMsgCtx != null) {
            MessageContext tenantRequestMsgCtx = (MessageContext) requestMsgCtx
                    .getProperty(MultitenantConstants.TENANT_REQUEST_MSG_CTX);

            if (tenantRequestMsgCtx != null) {
                MessageContext tenantResponseMsgCtx = tenantRequestMsgCtx.getOperationContext()
                        .getMessageContext(WSDL2Constants.MESSAGE_LABEL_IN);
                String tenantDomain;
                if (tenantRequestMsgCtx.getProperty(MultitenantConstants.TENANT_DOMAIN) != null) {
                    tenantDomain = (String) tenantRequestMsgCtx.getProperty(MultitenantConstants.TENANT_DOMAIN);
                } else {
                    tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
                    log.warn(
                            "Tenant domain is not available in tenant request message context, hence it might not be "
                                    + "set in the thread local carbon context");
                }
                try {
                    PrivilegedCarbonContext.startTenantFlow();
                    PrivilegedCarbonContext privilegedCarbonContext = PrivilegedCarbonContext
                            .getThreadLocalCarbonContext();
                    privilegedCarbonContext.setTenantDomain(tenantDomain, true);
                    if (tenantResponseMsgCtx == null) {
                        tenantResponseMsgCtx = new MessageContext();
                        tenantResponseMsgCtx.setOperationContext(tenantRequestMsgCtx.getOperationContext());
                    }

                    tenantResponseMsgCtx.setProperty(MultitenantConstants.TENANT_DOMAIN, tenantDomain);
                    tenantResponseMsgCtx.setServerSide(true);
                    tenantResponseMsgCtx.setDoingREST(tenantRequestMsgCtx.isDoingREST());

                    Iterator itr = mainInMsgContext.getPropertyNames();
                    while (itr.hasNext()) {
                        String key = (String) itr.next();
                        if (key != null) {
                            tenantResponseMsgCtx.setProperty(key, mainInMsgContext.getProperty(key));
                        }
                    }

                    tenantResponseMsgCtx.setProperty(MessageContext.TRANSPORT_IN,
                            tenantRequestMsgCtx.getProperty(MessageContext.TRANSPORT_IN));
                    tenantResponseMsgCtx.setTransportIn(tenantRequestMsgCtx.getTransportIn());
                    tenantResponseMsgCtx.setTransportOut(tenantRequestMsgCtx.getTransportOut());

                    tenantResponseMsgCtx.setProperty(MessageContext.TRANSPORT_HEADERS,
                            mainInMsgContext.getProperty(MessageContext.TRANSPORT_HEADERS));

                    tenantResponseMsgCtx.setAxisMessage(tenantRequestMsgCtx.getOperationContext().getAxisOperation()
                            .getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE));

                    tenantResponseMsgCtx.setOperationContext(tenantRequestMsgCtx.getOperationContext());
                    tenantResponseMsgCtx.setConfigurationContext(tenantRequestMsgCtx.getConfigurationContext());

                    tenantResponseMsgCtx.setTo(null);
                    tenantResponseMsgCtx.setSoapAction(mainInMsgContext.getSoapAction());

                    tenantResponseMsgCtx.setEnvelope(mainInMsgContext.getEnvelope());

                    if (mainInMsgContext.getProperty(MultitenantConstants.PASS_THROUGH_PIPE) != null) {
                        tenantResponseMsgCtx.setProperty(MultitenantConstants.PASS_THROUGH_PIPE,
                                mainInMsgContext.getProperty(MultitenantConstants.PASS_THROUGH_PIPE));
                        tenantResponseMsgCtx.setProperty(MultitenantConstants.PASS_THROUGH_SOURCE_CONFIGURATION,
                                mainInMsgContext
                                        .getProperty(MultitenantConstants.PASS_THROUGH_SOURCE_CONFIGURATION));
                        tenantResponseMsgCtx.setProperty("READY2ROCK", mainInMsgContext.getProperty("READY2ROCK"));
                        tenantResponseMsgCtx.setProperty(MultitenantConstants.PASS_THROUGH_SOURCE_CONNECTION,
                                mainInMsgContext.getProperty(MultitenantConstants.PASS_THROUGH_SOURCE_CONNECTION));
                    }

                    tenantResponseMsgCtx.setProperty(MultitenantConstants.MESSAGE_BUILDER_INVOKED, Boolean.FALSE);
                    tenantResponseMsgCtx.setProperty(MultitenantConstants.CONTENT_TYPE,
                            mainInMsgContext.getProperty(MultitenantConstants.CONTENT_TYPE));
                    AxisEngine.receive(tenantResponseMsgCtx);
                } finally {
                    PrivilegedCarbonContext.endTenantFlow();
                }
            }
        }
    }

    /**
     * Process a request message coming in to the multitenant environment
     *
     * @param mainInMsgContext super tenant's MessageContext
     * @throws AxisFault if an error occurs
     */
    private void processRequest(MessageContext mainInMsgContext) throws AxisFault {
        ConfigurationContext mainConfigCtx = mainInMsgContext.getConfigurationContext();
        String to = mainInMsgContext.getTo().getAddress();
        int tenantDelimiterIndex = to.indexOf(TENANT_DELIMITER);

        String tenantDomain;
        String serviceAndOperation;

        if (tenantDelimiterIndex != -1) {
            tenantDomain = MultitenantUtils.getTenantDomainFromUrl(to);
            serviceAndOperation = to.substring(tenantDelimiterIndex + tenantDomain.length() + 4);
        } else {
            // in this case tenant detail is not with the url but user may have send it
            // with a soap header or an http header.
            // in that case TenantDomainHandler may have set it.
            tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
            serviceAndOperation = Utils.getServiceAndOperationPart(to,
                    mainInMsgContext.getConfigurationContext().getServiceContextPath());
        }

        if (tenantDomain == null) {
            // Throw an AxisFault: Tenant not specified
            handleException(mainInMsgContext, new AxisFault("Tenant not specified"));
            return;
        }

        try {
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext privilegedCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
            privilegedCarbonContext.setTenantDomain(tenantDomain, true);
            // this is to prevent non-blocking transports from sending 202
            mainInMsgContext.getOperationContext().setProperty(Constants.RESPONSE_WRITTEN, "SKIP");

            ConfigurationContext tenantConfigCtx = TenantAxisUtils.getTenantConfigurationContext(tenantDomain,
                    mainConfigCtx);
            if (tenantConfigCtx == null) {
                // Throw AxisFault: Tenant does not exist
                handleException(mainInMsgContext, new AxisFault("Tenant " + tenantDomain + "  not found"));
                return;
            }

            if (mainInMsgContext.isDoingREST()) { // Handle REST requests
                doREST(mainInMsgContext, to, tenantDomain, tenantConfigCtx, serviceAndOperation);
            } else {
                doSOAP(mainInMsgContext, tenantDomain, tenantConfigCtx, serviceAndOperation);
            }
        } finally {
            PrivilegedCarbonContext.endTenantFlow();
        }
    }

    /**
     * Process a SOAP request coming in to the multitenant environment
     * @param mainInMsgContext super tenant's message context
     * @param tenant nameof the tenant
     * @param tenantConfigCtx tenant's ConfigurationContext
     * @param serviceName name of the service
     * @throws AxisFault if an error occurs
     */
    private void doSOAP(MessageContext mainInMsgContext, String tenant, ConfigurationContext tenantConfigCtx,
            String serviceName) throws AxisFault {

        // Call the correct tenant's configuration
        MessageContext tenantInMsgCtx = tenantConfigCtx.createMessageContext();
        tenantInMsgCtx.setMessageID(UUIDGenerator.getUUID());
        Options options = tenantInMsgCtx.getOptions();

        options.setTo(new EndpointReference("local://" + tenantConfigCtx.getServicePath() + "/" + serviceName));
        options.setAction(mainInMsgContext.getSoapAction());

        tenantInMsgCtx.setEnvelope(mainInMsgContext.getEnvelope());

        tenantInMsgCtx.setServerSide(true);
        copyProperties(mainInMsgContext, tenantInMsgCtx);

        tenantInMsgCtx.setProperty(MultitenantConstants.TENANT_DOMAIN, tenant);
        try {
            // set a dummy transport out description
            String transportOutName = mainInMsgContext.getTransportOut().getName();
            TransportOutDescription transportOutDescription = tenantConfigCtx.getAxisConfiguration()
                    .getTransportOut(transportOutName);
            tenantInMsgCtx.setTransportOut(transportOutDescription);
            TransportInDescription incomingTransport = tenantConfigCtx.getAxisConfiguration()
                    .getTransportIn(mainInMsgContext.getIncomingTransportName());
            tenantInMsgCtx.setTransportIn(incomingTransport);

            tenantInMsgCtx.setProperty(MessageContext.TRANSPORT_OUT,
                    mainInMsgContext.getProperty(MessageContext.TRANSPORT_OUT));
            tenantInMsgCtx.setProperty(Constants.OUT_TRANSPORT_INFO,
                    mainInMsgContext.getProperty(Constants.OUT_TRANSPORT_INFO));
            tenantInMsgCtx.setIncomingTransportName(mainInMsgContext.getIncomingTransportName());
            tenantInMsgCtx.setProperty(RequestResponseTransport.TRANSPORT_CONTROL,
                    mainInMsgContext.getProperty(RequestResponseTransport.TRANSPORT_CONTROL));

            // inject the message to the tenant inflow handlers
            AxisEngine.receive(tenantInMsgCtx);

            boolean nioAck = tenantInMsgCtx.isPropertyTrue("NIO-ACK-Requested", false);

            String respWritten = "";
            if (tenantInMsgCtx.getOperationContext() != null) {
                respWritten = (String) tenantInMsgCtx.getOperationContext().getProperty(Constants.RESPONSE_WRITTEN);
            }

            boolean respWillFollow = !Constants.VALUE_TRUE.equals(respWritten) && !"SKIP".equals(respWritten);

            boolean forced = tenantInMsgCtx.isPropertyTrue("FORCE_SC_ACCEPTED");

            if (forced) {
                mainInMsgContext.setProperty("FORCE_SC_ACCEPTED", true);
            }

            if (nioAck || respWillFollow || forced) {
                mainInMsgContext.setProperty("HTTP_SC", tenantInMsgCtx.getProperty("HTTP_SC"));
                mainInMsgContext.setProperty("NIO-ACK-Requested", nioAck);
                mainInMsgContext.removeProperty(MessageContext.TRANSPORT_HEADERS);
                Map<String, String> responseHeaders = (Map<String, String>) tenantInMsgCtx
                        .getProperty(MessageContext.TRANSPORT_HEADERS);
                mainInMsgContext.setProperty(MessageContext.TRANSPORT_HEADERS, responseHeaders);
            }

            if (mainInMsgContext.getOperationContext() != null && tenantInMsgCtx.getOperationContext() != null) {
                mainInMsgContext.getOperationContext().setProperty(Constants.RESPONSE_WRITTEN,
                        tenantInMsgCtx.getOperationContext().getProperty(Constants.RESPONSE_WRITTEN));
            }
        } catch (AxisFault axisFault) {
            // at a fault flow message receiver throws a fault.
            // we need to first catch this fault and invoke the fault flow
            // then thorw the AxisFault for main flow which is catch by the carbon servlet
            // and invoke the fault handlers.

            MessageContext faultContext = MessageContextBuilder.createFaultMessageContext(tenantInMsgCtx,
                    axisFault);
            faultContext.setTransportOut(tenantInMsgCtx.getTransportOut());
            faultContext.setProperty(MultitenantConstants.TENANT_MR_STARTED_FAULT, Constants.VALUE_TRUE);
            AxisEngine.sendFault(faultContext);

            // we need to set the detial to null. otherwise the details element is copied to
            // new message context and removed from the original one
            axisFault.setDetail(null);
            MessageContext mainFaultContext = MessageContextBuilder.createFaultMessageContext(mainInMsgContext,
                    axisFault);
            mainFaultContext.setTo(faultContext.getTo());
            mainFaultContext.setSoapAction(faultContext.getSoapAction());

            mainFaultContext.setEnvelope(faultContext.getEnvelope());
            throw new AxisFault(axisFault.getMessage(), mainFaultContext);

        }
    }

    /**
     * Process a REST message coming in to the multitenant environment
     * @param mainInMsgContext SuperTenant's Message Context
     * @param to the to address
     * @param tenant tenant name
     * @param tenantConfigCtx Tentnat's configuration context
     * @param serviceName service name
     * @throws AxisFault if an error occurs
     */
    private void doREST(MessageContext mainInMsgContext, String to, String tenant,
            ConfigurationContext tenantConfigCtx, String serviceName) throws AxisFault {
        HttpServletRequest request = (HttpServletRequest) mainInMsgContext
                .getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);

        if (request != null) {
            HttpServletResponse response = (HttpServletResponse) mainInMsgContext
                    .getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE);
            doServletRest(mainInMsgContext, to, tenant, tenantConfigCtx, serviceName, request, response);
        } else {
            doNhttpREST(mainInMsgContext, to, tenant, tenantConfigCtx, serviceName);
        }
    }

    /**
     * Process a REST message coming in from the Servlet transport.
     * @param mainInMsgContext supertenant's MessageContext
     * @param to the full transport url
     * @param tenant name of the tenant
     * @param tenantConfigCtx tenant ConfigurationContext
     * @param serviceName the part of the to url after the service
     * @param request servlet request
     * @param response servlet response
     * @throws AxisFault if an error occcus
     */
    private void doServletRest(MessageContext mainInMsgContext, String to, String tenant,
            ConfigurationContext tenantConfigCtx, String serviceName, HttpServletRequest request,
            HttpServletResponse response) throws AxisFault {
        String serviceWithSlashT = TENANT_DELIMITER + tenant + "/" + serviceName;
        String requestUri = "local://" + tenantConfigCtx.getServicePath() + "/" + serviceName
                + (to.endsWith(serviceWithSlashT) ? ""
                        : "/" + to.substring(to.indexOf(serviceWithSlashT) + serviceWithSlashT.length() + 1));

        MultitenantRESTServlet restServlet = new MultitenantRESTServlet(tenantConfigCtx, requestUri, tenant);

        String httpMethod = (String) mainInMsgContext.getProperty(HTTPConstants.HTTP_METHOD);
        try {
            if (httpMethod.equals(Constants.Configuration.HTTP_METHOD_GET)) {
                restServlet.doGet(request, response);
            } else if (httpMethod.equals(Constants.Configuration.HTTP_METHOD_POST)) {
                restServlet.doPost(request, response);
            } else if (httpMethod.equals(Constants.Configuration.HTTP_METHOD_PUT)) {
                restServlet.doPut(request, response);
            } else if (httpMethod.equals(Constants.Configuration.HTTP_METHOD_DELETE)) {
                restServlet.doDelete(request, response);
            } else {
                // TODO: throw exception: Invalid verb
            }
        } catch (ServletException e) {
            throw new AxisFault(e.getMessage(), e);
        } catch (IOException e) {
            throw new AxisFault(e.getMessage(), e);
        }

        // Send the response
        MessageContext tenantOutMsgContext = restServlet.getOutMessageContext();
        MessageContext tenantOutFaultMsgContext = restServlet.getOutFaultMessageContext();

        // for a fault case both out and fault contexts are not null. so first we need to
        // check the fault context
        if (tenantOutFaultMsgContext != null) {
            // TODO: set the fault exception
            MessageContext mainOutFaultMsgContext = MessageContextBuilder
                    .createFaultMessageContext(mainInMsgContext, null);
            mainOutFaultMsgContext.setEnvelope(tenantOutFaultMsgContext.getEnvelope());
            throw new AxisFault("Problem with executing the message", mainOutFaultMsgContext);
        } else if (tenantOutMsgContext != null) {
            MessageContext mainOutMsgContext = MessageContextBuilder.createOutMessageContext(mainInMsgContext);
            mainOutMsgContext.getOperationContext().addMessageContext(mainOutMsgContext);
            mainOutMsgContext.getAxisOperation().getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE)
                    .setElementQName(tenantOutMsgContext.getAxisOperation()
                            .getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE).getElementQName());
            mainOutMsgContext.getAxisService().addSchema(tenantOutMsgContext.getAxisService().getSchema());
            mainOutMsgContext.setEnvelope(tenantOutMsgContext.getEnvelope());
            mainOutMsgContext.setProperty(Constants.Configuration.MESSAGE_TYPE,
                    tenantOutMsgContext.getProperty(Constants.Configuration.MESSAGE_TYPE));
            try {
                AxisEngine.send(mainOutMsgContext);
            } finally {
                mainOutMsgContext.getAxisService().getSchema()
                        .removeAll(tenantOutMsgContext.getAxisService().getSchema());
            }
        }
    }

    /**
     * Process a REST message coming in from the NHTTP transport.
     * @param mainInMsgContext supertenant's MessageContext
     * @param to the full transport url
     * @param tenant name of the tenant
     * @param tenantConfigCtx tenant ConfigurationContext
     * @param servicePart the part of the to url after the service
     * @throws AxisFault if an error occcus
     */
    public void doNhttpREST(MessageContext mainInMsgContext, String to, String tenant,
            ConfigurationContext tenantConfigCtx, String servicePart) throws AxisFault {
        String serviceWithSlashT = TENANT_DELIMITER + tenant + "/" + servicePart;
        String requestUri = "local://" + tenantConfigCtx.getServicePath() + "/" + servicePart
                + (to.endsWith(serviceWithSlashT) ? ""
                        : "/" + to.substring(to.indexOf(serviceWithSlashT) + serviceWithSlashT.length() + 1));
        // Now create the message context to invoke
        MessageContext tenantInMsgCtx = tenantConfigCtx.createMessageContext();

        String trsPrefix = (String) mainInMsgContext.getProperty(Constants.Configuration.TRANSPORT_IN_URL);

        int sepindex = trsPrefix.indexOf(':');
        if (sepindex > -1) {
            trsPrefix = trsPrefix.substring(0, sepindex);
            tenantInMsgCtx.setIncomingTransportName(trsPrefix);
        } else {
            tenantInMsgCtx.setIncomingTransportName(Constants.TRANSPORT_HTTP);
        }

        tenantInMsgCtx.setMessageID(UIDGenerator.generateURNString());
        tenantInMsgCtx.setServerSide(true);
        tenantInMsgCtx.setDoingREST(true);
        copyProperties(mainInMsgContext, tenantInMsgCtx);
        tenantInMsgCtx.setTo(new EndpointReference(requestUri));

        // set a dummy transport out description
        String transportOutName = mainInMsgContext.getTransportOut().getName();
        TransportOutDescription transportOutDescription = tenantConfigCtx.getAxisConfiguration()
                .getTransportOut(transportOutName);
        tenantInMsgCtx.setTransportOut(transportOutDescription);
        TransportInDescription incomingTransport = tenantConfigCtx.getAxisConfiguration()
                .getTransportIn(mainInMsgContext.getIncomingTransportName());
        tenantInMsgCtx.setTransportIn(incomingTransport);

        tenantInMsgCtx.setProperty(MessageContext.TRANSPORT_OUT,
                mainInMsgContext.getProperty(MessageContext.TRANSPORT_OUT));
        tenantInMsgCtx.setProperty(Constants.OUT_TRANSPORT_INFO,
                mainInMsgContext.getProperty(Constants.OUT_TRANSPORT_INFO));
        tenantInMsgCtx.setIncomingTransportName(mainInMsgContext.getIncomingTransportName());

        // When initializing caching, cache manager fetches the tenant domain from threadLocalCarbonContext
        // Without setting this, caching cannot be initialised on the API Gateway.
        String transportInClassName = mainInMsgContext.getTransportIn().getReceiver().getClass().getName();

        if ("org.apache.synapse.transport.nhttp.HttpCoreNIOListener".equals(transportInClassName)
                || "org.apache.synapse.transport.nhttp.HttpCoreNIOSSLListener".equals(transportInClassName)
                || "org.apache.synapse.transport.passthru.PassThroughHttpListener".equals(transportInClassName)
                || "org.apache.synapse.transport.passthru.PassThroughHttpSSLListener"
                        .equals(transportInClassName)) {
            tenantInMsgCtx.setProperty(MultitenantConstants.TENANT_DOMAIN, tenant);
        }

        /* // extract the part of the user after the actual service and set it as
         int index = servicePart.indexOf('/');
         String service = (index > 0 ?
            servicePart.substring(servicePart.indexOf('/') + 1) : servicePart);        
         //String servicePath = TENANT_DELIMITER + tenant + "/" + service;
         //String restSuffic = (to.endsWith(servicePath) ? "" :
         // to.substring(to.indexOf(servicePath) + servicePath.length() + 1));
         tenantInMsgCtx.setProperty("REST_URL_POSTFIX", service);*/

        String service = "";
        String postFix = "";
        int index = servicePart.indexOf("/");
        if (index > 0) {
            service = servicePart.substring(0, index);
            postFix = servicePart.substring(index + 1);

        }

        if (service.equals("")) {
            service = servicePart;
        }
        tenantInMsgCtx.setProperty("REST_URL_POSTFIX", postFix);

        // handling requests with invalid service portion
        if (tenantConfigCtx.getAxisConfiguration().getService(service) == null) {
            // we assume that the request should go to the default service
            tenantInMsgCtx.setAxisService(tenantConfigCtx.getAxisConfiguration().getService("__SynapseService"));
        }

        tenantInMsgCtx.setEnvelope(mainInMsgContext.getEnvelope());
        ;

        InputStream in = (InputStream) mainInMsgContext.getProperty("nhttp.input.stream");
        OutputStream os = (OutputStream) mainInMsgContext.getProperty("nhttp.output.stream");
        String contentType = (String) mainInMsgContext.getProperty("ContentType");
        try {
            //  String httpMethod = (String) mainInMsgContext.getProperty(HTTPConstants.HTTP_METHOD);
            String httpMethod = (String) mainInMsgContext.getProperty(Constants.Configuration.HTTP_METHOD);
            if (httpMethod.equals(Constants.Configuration.HTTP_METHOD_GET)
                    || httpMethod.equals(Constants.Configuration.HTTP_METHOD_DELETE) || "OPTIONS".equals(httpMethod)
                    || Constants.Configuration.HTTP_METHOD_HEAD.equals(httpMethod)) {
                //RESTUtil.processURLRequest(tenantInMsgCtx, os, contentType);
                this.processRESTRequest(tenantInMsgCtx, os, contentType);
            } else if (httpMethod.equals(Constants.Configuration.HTTP_METHOD_POST)
                    || httpMethod.equals(Constants.Configuration.HTTP_METHOD_PUT)) {
                //RESTUtil.processXMLRequest(tenantInMsgCtx, in, os, contentType);
                this.processRESTRequest(tenantInMsgCtx, os, contentType);
            } else {
                // TODO: throw exception: Invalid verb
            }
        } catch (AxisFault axisFault) {
            // at a fault flow message receiver throws a fault.
            // we need to first catch this fault and invoke the fault flow
            // then thorw the AxisFault for main flow which is catch by the carbon servlet
            // and invoke the fault handlers.

            MessageContext faultContext = MessageContextBuilder.createFaultMessageContext(tenantInMsgCtx,
                    axisFault);
            faultContext.setTransportOut(tenantInMsgCtx.getTransportOut());
            faultContext.setProperty(MultitenantConstants.TENANT_MR_STARTED_FAULT, Constants.VALUE_TRUE);
            AxisEngine.sendFault(faultContext);

            // we need to set the detial to null. otherwise the details element is copied to
            // new message context and removed from the original one
            axisFault.setDetail(null);
            MessageContext mainFaultContext = MessageContextBuilder.createFaultMessageContext(mainInMsgContext,
                    axisFault);
            mainFaultContext.setTo(faultContext.getTo());
            mainFaultContext.setSoapAction(faultContext.getSoapAction());

            mainFaultContext.setEnvelope(faultContext.getEnvelope());
            throw new AxisFault(axisFault.getMessage(), mainFaultContext);
        }
    }

    /**
     * This is temporary fix to handle REST API invocations requests comes via
     * multitenancy dispatch service,
     * 
     * @param msgContext
     * @param os
     * @param contentType
     * @return
     * @throws AxisFault
     */
    private Handler.InvocationResponse processRESTRequest(MessageContext msgContext, OutputStream os,
            String contentType) throws AxisFault {
        try {
            msgContext.setDoingREST(true);
            String charSetEncoding = BuilderUtil.getCharSetEncoding(contentType);
            msgContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING, charSetEncoding);
            dispatchAndVerify(msgContext);
        } catch (AxisFault axisFault) {
            throw axisFault;
        } finally {
            String messageType = (String) msgContext.getProperty(Constants.Configuration.MESSAGE_TYPE);
            if (HTTPConstants.MEDIA_TYPE_X_WWW_FORM.equals(messageType)
                    || HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA.equals(messageType)) {
                msgContext.setProperty(Constants.Configuration.MESSAGE_TYPE,
                        HTTPConstants.MEDIA_TYPE_APPLICATION_XML);
            }
        }

        return AxisEngine.receive(msgContext);

    }

    private static void dispatchAndVerify(MessageContext msgContext) throws AxisFault {
        RequestURIBasedDispatcher requestDispatcher = new RequestURIBasedDispatcher();
        requestDispatcher.invoke(msgContext);
        AxisService axisService = msgContext.getAxisService();
        if (axisService != null) {
            HTTPLocationBasedDispatcher httpLocationBasedDispatcher = new HTTPLocationBasedDispatcher();
            httpLocationBasedDispatcher.invoke(msgContext);
            if (msgContext.getAxisOperation() == null) {
                RequestURIOperationDispatcher requestURIOperationDispatcher = new RequestURIOperationDispatcher();
                requestURIOperationDispatcher.invoke(msgContext);
            }

            AxisOperation axisOperation;
            if ((axisOperation = msgContext.getAxisOperation()) != null) {
                AxisEndpoint axisEndpoint = (AxisEndpoint) msgContext
                        .getProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME);
                if (axisEndpoint != null) {
                    AxisBindingOperation axisBindingOperation = (AxisBindingOperation) axisEndpoint.getBinding()
                            .getChild(axisOperation.getName());
                    msgContext.setProperty(Constants.AXIS_BINDING_OPERATION, axisBindingOperation);
                }
                msgContext.setAxisOperation(axisOperation);
            }
        }
    }

    /**
      * Copy the properties from main message context to the tenant message context.
      *
      * @param mainMsgCtx super tenant message context
      * @param tenantMsgCtx tenant message context
      */
    private void copyProperties(MessageContext mainMsgCtx, MessageContext tenantMsgCtx) {
        // do not copy options from the original        
        tenantMsgCtx.setSoapAction(mainMsgCtx.getSoapAction());

        tenantMsgCtx.setDoingREST(mainMsgCtx.isDoingREST());
        tenantMsgCtx.setDoingMTOM(mainMsgCtx.isDoingMTOM());
        tenantMsgCtx.setDoingSwA(mainMsgCtx.isDoingSwA());

        // if the original request carries any attachments, copy them to the clone
        // as well, except for the soap part if any
        Attachments attachments = mainMsgCtx.getAttachmentMap();
        if (attachments != null && attachments.getAllContentIDs().length > 0) {
            String[] cIDs = attachments.getAllContentIDs();
            String soapPart = attachments.getSOAPPartContentID();
            for (String cID : cIDs) {
                if (!cID.equals(soapPart)) {
                    tenantMsgCtx.addAttachment(cID, attachments.getDataHandler(cID));
                }
            }
        }

        Iterator itr = mainMsgCtx.getPropertyNames();
        while (itr.hasNext()) {
            String key = (String) itr.next();
            if (key != null) {
                tenantMsgCtx.setProperty(key, mainMsgCtx.getProperty(key));
            }
        }
    }

    private void handleException(MessageContext mainInMsgContext, AxisFault fault) throws AxisFault {
        MessageContext mainOutMsgContext = MessageContextBuilder.createFaultMessageContext(mainInMsgContext, fault);
        OperationContext mainOpContext = mainInMsgContext.getOperationContext();
        mainOpContext.addMessageContext(mainOutMsgContext);
        mainOutMsgContext.setOperationContext(mainOpContext);
        AxisEngine.sendFault(mainOutMsgContext);
    }

    /**
     * Get the EPR for the message passed in
     * @param msgContext the message context
     * @return the destination EPR
     */
    public static EndpointReference getDestinationEPR(MessageContext msgContext) {

        // Trasnport URL can be different from the WSA-To
        String transportURL = (String) msgContext.getProperty(Constants.Configuration.TRANSPORT_URL);

        if (transportURL != null) {
            return new EndpointReference(transportURL);
        } else if ((msgContext.getTo() != null) && !msgContext.getTo().hasAnonymousAddress()) {
            return msgContext.getTo();
        }
        return null;
    }
}