org.wso2.carbon.dataservices.core.DBDeployer.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.dataservices.core.DBDeployer.java

Source

/*
 *  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. 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.wso2.carbon.dataservices.core;

import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.deployment.AbstractDeployer;
import org.apache.axis2.deployment.DeploymentEngine;
import org.apache.axis2.deployment.DeploymentErrorMsgs;
import org.apache.axis2.deployment.DeploymentException;
import org.apache.axis2.deployment.repository.util.DeploymentFileData;
import org.apache.axis2.deployment.util.Utils;
import org.apache.axis2.description.AxisBinding;
import org.apache.axis2.description.AxisBindingMessage;
import org.apache.axis2.description.AxisBindingOperation;
import org.apache.axis2.description.AxisEndpoint;
import org.apache.axis2.description.AxisMessage;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.AxisServiceGroup;
import org.apache.axis2.description.InOnlyAxisOperation;
import org.apache.axis2.description.InOutAxisOperation;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.TransportInDescription;
import org.apache.axis2.description.WSDL2Constants;
import org.apache.axis2.description.java2wsdl.Java2WSDLConstants;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.ws.commons.schema.utils.NamespaceMap;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.dataservices.common.DBConstants;
import org.wso2.carbon.dataservices.common.DBConstants.DBSFields;
import org.wso2.carbon.dataservices.common.DBConstants.ResultTypes;
import org.wso2.carbon.dataservices.core.description.config.Config;
import org.wso2.carbon.dataservices.core.description.operation.Operation;
import org.wso2.carbon.dataservices.core.description.query.Query;
import org.wso2.carbon.dataservices.core.description.resource.Resource;
import org.wso2.carbon.dataservices.core.description.resource.Resource.ResourceID;
import org.wso2.carbon.dataservices.core.engine.CallQuery;
import org.wso2.carbon.dataservices.core.engine.CallQuery.WithParam;
import org.wso2.carbon.dataservices.core.engine.CallableRequest;
import org.wso2.carbon.dataservices.core.engine.DataService;
import org.wso2.carbon.dataservices.core.engine.QueryParam;
import org.wso2.carbon.dataservices.core.internal.DataServicesDSComponent;
import org.wso2.carbon.dataservices.core.jmx.DataServiceInstance;
import org.wso2.carbon.dataservices.core.jmx.DataServiceInstanceMBean;
import org.wso2.carbon.dataservices.core.odata.ODataServiceHandler;
import org.wso2.carbon.dataservices.core.odata.ODataServiceRegistry;
import org.wso2.carbon.ndatasource.common.DataSourceConstants;
import org.wso2.carbon.ndatasource.common.DataSourceException;
import org.wso2.carbon.ndatasource.core.DataSourceManager;
import org.wso2.carbon.utils.CarbonUtils;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.transaction.TransactionManager;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;

/**
 * Represents the custom Axis2 deployer used in deploying data-services .dbs files.
 */
public class DBDeployer extends AbstractDeployer {

    public static final String HTTP_TRANSPORT = "http";

    public static final String HTTPS_TRANSPORT = "https";

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

    /**
     * Data Services directory name to be used in Axis2 service deployment
     */
    public static final String DEPLOYMENT_FOLDER_NAME = "dataservices";

    /**
     * Current Axis2 AxisConfiguration
     */
    private AxisConfiguration axisConfig;

    /**
     * Current Axis2 ConfigurationContext
     */
    private ConfigurationContext configCtx;

    /**
     * Data Services repository directory
     */
    private String repoDir;

    /**
     * Data Services file directory (i.e. '.dbs')
     */
    private String extension;

    /**
     * used for REST processing
     */
    private Map<String, AxisOperation> httpLocationTable;
    private Map<Pattern, AxisOperation> httpLocationTableForResource;

    /** cached transaction manager instance */
    private static TransactionManager cachedTransactionManager = null;

    public ConfigurationContext getConfigContext() {
        return configCtx;
    }

    /**
     * Deploys a data service with the given deployment data.
     */
    public void deploy(DeploymentFileData deploymentFileData) throws DeploymentException {
        PrivilegedCarbonContext.getThreadLocalCarbonContext().setApplicationName(deploymentFileData.getName());
        /* If there's already a faulty service corresponding to this particular service,
           remove it */
        if (isFaultyService(deploymentFileData)) {
            this.axisConfig.removeFaultyService(deploymentFileData.getFile().getAbsolutePath());
        }

        String serviceHierarchy = Utils.getServiceHierarchy(deploymentFileData.getAbsolutePath(), this.repoDir);
        if (serviceHierarchy == null) {
            serviceHierarchy = "";
        }

        /* state variable kept to check if the service was successfully deployed at the end */
        boolean successfullyDeployed = false;
        /* used to store the error message if there is a problem in deploying */
        String errorMessage = null;
        /* Axis2 service to be deployed */
        AxisService service = null;

        try {
            /* In the context of dataservices one service group will only contain one dataservice.
               *  Hence assigning the service group as the service group name */
            String serviceGroupName = serviceHierarchy
                    + this.getServiceNameFromDSContents(deploymentFileData.getFile());

            /* service active property */
            boolean serviceActive;

            AxisServiceGroup serviceGroup = new AxisServiceGroup();
            serviceGroup.setServiceGroupName(serviceGroupName);
            service = processService(deploymentFileData, serviceGroup, this.configCtx);
            service.setName(serviceHierarchy + service.getName());
            /* save original value */
            serviceActive = service.isActive();

            ArrayList<AxisService> services = new ArrayList<AxisService>();
            services.add(service);

            boolean secEnabled = this.handleSecurityProxy(deploymentFileData, service);

            DeploymentEngine.addServiceGroup(serviceGroup, services, deploymentFileData.getFile().toURI().toURL(),
                    deploymentFileData, this.axisConfig);

            //Engage rampart module if security is enabled
            if (secEnabled) {
                service.engageModule(
                        this.configCtx.getAxisConfiguration().getModule(DBConstants.SECURITY_MODULE_NAME),
                        this.configCtx.getAxisConfiguration());
            }

            /* restore original service active value */
            service.setActive(serviceActive);

            if (log.isDebugEnabled()) {
                log.debug(Messages.getMessage(DeploymentErrorMsgs.DEPLOYING_WS, deploymentFileData.getName(),
                        deploymentFileData.getAbsolutePath()));
            }
            super.deploy(deploymentFileData);
            /* finished deploying successfully */
            successfullyDeployed = true;

        } catch (DataServiceFault e) {
            errorMessage = DBUtils.getStacktraceFromException(e);
            log.error(Messages.getMessage(DeploymentErrorMsgs.INVALID_SERVICE, deploymentFileData.getName()), e);
            /* if there is a request to re-schedule in the exception, do it .. */
            if (DBConstants.FaultCodes.CONNECTION_UNAVAILABLE_ERROR.equals(e.getCode())) {
                this.sheduleRedeploy(deploymentFileData, service);
            }
            DataService ds = e.getSourceDataService();
            try {
                /* only if the data service is available, for XML syntax based error in the dbs,
                 * we cannot get the data service */
                if (ds != null) {
                    ds.cleanup();
                }
            } catch (DataServiceFault e2) {
                log.warn("Error in data service cleanup: " + e2.getMessage(), e2);
            }
            throw new DeploymentException(
                    Messages.getMessage(DeploymentErrorMsgs.INVALID_SERVICE, deploymentFileData.getName()), e);
        } catch (Throwable e) {
            errorMessage = DBUtils.getStacktraceFromException(e);
            log.error(Messages.getMessage(DeploymentErrorMsgs.INVALID_SERVICE, deploymentFileData.getName()), e);
            throw new DeploymentException(
                    Messages.getMessage(DeploymentErrorMsgs.INVALID_SERVICE, deploymentFileData.getName()), e);
        } finally {
            if (!successfullyDeployed) {
                String deploymentFilePath = deploymentFileData.getFile().getAbsolutePath();
                /* Register the faulty service */
                this.axisConfig.getFaultyServices().put(deploymentFilePath, errorMessage);
                try {
                    CarbonUtils.registerFaultyService(deploymentFilePath, DBConstants.DB_SERVICE_TYPE, configCtx);
                } catch (Exception e) {
                    log.error("Cannot register faulty service with Carbon", e);
                }
            }
        }
    }

    /**
     * Checks whether the service that is being deployed is already marked as a faulty service
     *
     * @param deploymentFileData    DeploymentFileData instance corresponding to the service being
     *                              deployed.
     * @return                      Boolean representing the existence of the service as a faulty
     *                              service
     */
    private boolean isFaultyService(DeploymentFileData deploymentFileData) {
        String faultyServiceFilePath = deploymentFileData.getFile().getAbsolutePath();
        AxisService faultyService = CarbonUtils.getFaultyService(faultyServiceFilePath, this.configCtx);
        return faultyService != null;
    }

    private String getServiceNameFromDSContents(File file) throws Exception {
        StAXOMBuilder builder = new StAXOMBuilder(new FileInputStream(file.getAbsoluteFile()));
        OMElement serviceEl = builder.getDocumentElement();
        String serviceName = serviceEl.getAttributeValue(new QName(DBSFields.NAME));
        builder.close();
        if (DBUtils.isEmptyString(serviceName)) {
            throw new DataServiceFault(
                    "Service group cannot be determined for the data service at '" + file.getAbsolutePath() + "'");
        }
        return serviceName;
    }

    /**
     * Creates a timer with a one minute delay, for re-deploying a data service.
     */
    private void sheduleRedeploy(DeploymentFileData deploymentFileData, AxisService service) {
        Runnable faultyServiceRectifier = new FaultyServiceRectifier(service, deploymentFileData, configCtx);
        /* Retry in one minute */
        long retryIn = 1000 * 60;
        DBUtils.scheduleTask(faultyServiceRectifier, retryIn);
    }

    /**
     * Initializes the deployer.
     */
    public void init(ConfigurationContext configCtx) {
        this.configCtx = configCtx;
        this.axisConfig = this.configCtx.getAxisConfiguration();
        /* init is called after the setDirectory is called so setting the
         * repoDir and the extension here. */
        configCtx.setProperty(DBConstants.DB_SERVICE_REPO, this.repoDir);
        configCtx.setProperty(DBConstants.DB_SERVICE_EXTENSION, this.extension);
        configCtx.setProperty(DBConstants.DB_SERVICE_DEPLOYER, this);

        /* retrieve tenant id */
        int tid;
        try {
            tid = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
        } catch (ExceptionInInitializerError e) {
            /* workaround for unit test failures */
            tid = MultitenantConstants.SUPER_TENANT_ID;
        }

        try {
            /* load tenant registry */
            DataServicesDSComponent.getTenantRegistryLoader().loadTenantRegistry(tid);
        } catch (Exception e) {
            /*ignore*/
        }

        /* transaction manager looked up and cached for later use, rather than always doing the JNDI lookup */
        this.doExtractTransactionManager();

        /* data sources component tenant initialized, this is done here as a precaution to
         * make sure that the tenant's data sources are initialized before the data services
         * are deployed, this uncertainty comes because we cannot predict the order which
         * the Axis2ConfigurationContext observers will be called */
        try {
            DataSourceManager.getInstance().initTenant(tid);
        } catch (DataSourceException e) {
            log.error("Error in intializing Carbon data sources for tenant: " + tid + " from data services");
        } catch (NoClassDefFoundError e) {
            //workaround for unit test failures
        } catch (NoSuchMethodError e) {
            //workaround for unit test failures
        }
    }

    private void doExtractTransactionManager() {
        if (cachedTransactionManager != null) {
            return;
        }
        try {
            Object txObj = InitialContext.doLookup(DBConstants.STANDARD_USER_TRANSACTION_JNDI_NAME);
            if (txObj instanceof TransactionManager) {
                cachedTransactionManager = (TransactionManager) txObj;
            }
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug("Cannot find transaction manager at: " + DBConstants.STANDARD_USER_TRANSACTION_JNDI_NAME,
                        e);
            }
            /* ignore, move onto next step */
        }
        if (cachedTransactionManager == null) {
            try {
                cachedTransactionManager = InitialContext
                        .doLookup(DBConstants.STANDARD_TRANSACTION_MANAGER_JNDI_NAME);
            } catch (Exception e) {
                if (log.isDebugEnabled()) {
                    log.debug("Cannot find transaction manager at: "
                            + DBConstants.STANDARD_TRANSACTION_MANAGER_JNDI_NAME, e);
                }
                /* we'll do the lookup later, maybe user provided a custom JNDI name */
            }
        }
    }

    public static TransactionManager getCachedTransactionManager() {
        return cachedTransactionManager;
    }

    public void setDirectory(String repoDir) {
        this.repoDir = repoDir;
    }

    public String getRepoDir() {
        return repoDir;
    }

    public void setExtension(String extension) {
        this.extension = extension;
    }

    public String getExtension() {
        return extension;
    }

    private DataService getDataServiceByServicePath(String servicePath) throws Exception {
        Parameter tmpParam;
        DataService tmpDS;
        String canonicalServicePath = new File(servicePath).getCanonicalPath();
        for (AxisService axisService : this.axisConfig.getServices().values()) {
            tmpParam = axisService.getParameter(DBConstants.DATA_SERVICE_OBJECT);
            if (tmpParam != null) {
                tmpDS = (DataService) tmpParam.getValue();
                if (new File(tmpDS.getDsLocation()).getCanonicalPath().equals(canonicalServicePath)) {
                    return tmpDS;
                }
            }
        }
        //throw new DataServiceFault("Data service at '" + servicePath + "' cannot be found");
        return null;
    }

    /**
     * Undeploys a service.
     */
    public void undeploy(String servicePath) throws DeploymentException {
        try {
            DataService dataService = this.getDataServiceByServicePath(servicePath);
            if (dataService == null) {
                /* must be a faulty service */
                /* the faulty service should be removed at this point from the axis configuration.
                   otherwise the service would still be shown as a faulty service in the management
                   console UI since it queries and lists out the faulty services from the
                   axisConfiguration itself.
                   */
                this.axisConfig.removeFaultyService(servicePath);
                return;
            }
            String serviceHierarchy = Utils.getServiceHierarchy(servicePath, this.repoDir);
            if (serviceHierarchy == null) {
                serviceHierarchy = "";
            }
            String serviceName = serviceHierarchy + dataService.getName();
            /* In the context of dataservices one service group will only contain one dataservice.
            *  Hence assigning the service group as the service group name */
            AxisServiceGroup serviceGroup = this.axisConfig.getServiceGroup(serviceName);
            CarbonContext cCtx = CarbonContext.getThreadLocalCarbonContext();
            if (serviceGroup == null) { /* must be a faulty service */
                this.axisConfig.removeFaultyService(servicePath);
                for (String configID : dataService.getConfigs().keySet()) {
                    if (dataService.getConfig(configID).isODataEnabled()) {
                        removeODataHandler(cCtx.getTenantDomain(), dataService.getName() + configID);
                    }
                }
            } else {
                /* cleanup data service */
                for (String configID : dataService.getConfigs().keySet()) {
                    if (dataService.getConfig(configID).isODataEnabled()) {
                        removeODataHandler(cCtx.getTenantDomain(), dataService.getName() + configID);
                    }
                }
                dataService.cleanup();
                this.axisConfig.removeService(serviceName);
                /* if the service group is now empty, remove it as well */
                if (!serviceGroup.getServices().hasNext()) {
                    /* when the service group is removed re-deployment causes problems */
                    this.axisConfig.removeServiceGroup(serviceGroup.getServiceGroupName());
                }
            }
            if (log.isDebugEnabled()) {
                log.debug(Messages.getMessage(DeploymentErrorMsgs.SERVICE_REMOVED, serviceName));
            }
            super.undeploy(servicePath);
        } catch (Exception e) {
            String msg = "Error in undeploying service";
            log.error(msg, e);
            throw new DeploymentException(msg, e);
        }
    }

    /**
     * Configuration files prior to multiple data source support did not have id attribute
     * for config element. Adding that & saving.
     */
    @SuppressWarnings("unchecked")
    private void convertConfigToMultipleDSFormat(String configFilePath) throws DataServiceFault {
        FileInputStream fis = null;
        boolean changed = false;
        try {
            fis = new FileInputStream(configFilePath);
            OMElement configElement = (new StAXOMBuilder(fis)).getDocumentElement();
            configElement.build();
            Iterator<OMElement> configElements = configElement.getChildrenWithName(new QName(DBSFields.CONFIG));
            int emptyConfigs = 0;
            while (configElements.hasNext()) {
                OMElement config = configElements.next();
                String configId = config.getAttributeValue(new QName(DBSFields.ID));
                if (configId == null || configId.trim().length() == 0) {
                    config.addAttribute(DBSFields.ID, DBConstants.DEFAULT_CONFIG_ID, null);
                    changed = true;
                    emptyConfigs++;
                    if (emptyConfigs > 1) {
                        throw new DataServiceFault("More than one config elements found in " + configFilePath);
                    }
                }
            }
            Iterator<OMElement> queryElements = configElement.getChildrenWithName(new QName(DBSFields.QUERY));
            while (queryElements.hasNext()) {
                OMElement query = queryElements.next();
                String useConfig = query.getAttributeValue(new QName(DBSFields.USE_CONFIG));
                if (useConfig == null || useConfig.trim().length() == 0) {
                    query.addAttribute(DBSFields.USE_CONFIG, DBConstants.DEFAULT_CONFIG_ID, null);
                    changed = true;
                }
            }
            if (changed) {
                if (log.isDebugEnabled()) {
                    log.debug("Converting " + configFilePath + " to support multiple data sources.");
                }
                BufferedWriter out = new BufferedWriter(new FileWriter(configFilePath));
                configElement.serialize(out);
                out.close();
                DBUtils.prettifyXMLFile(configFilePath);
            }
        } catch (Exception e) {
            throw new DataServiceFault(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("Error in closing data service configuration file", e);
                }
            }
        }
    }

    /**
     * Creates an AxisOperation with the given data service operation object.
     * @see Operation
     * @see AxisOperation
     */
    private AxisOperation createAxisOperationFromDSOperation(Operation operation, AxisBinding soap11Binding,
            AxisBinding soap12Binding, AxisBinding httpBinding) throws AxisFault {
        String opName = operation.getName();
        String requestName = operation.getRequestName();

        int index = opName.indexOf(":");
        if (index > -1) {
            opName = opName.substring(index + 1);
        }
        boolean hasResult = operation.getCallQuery().isHasResult() || operation.isReturnRequestStatus();
        String description = operation.getDescription();
        return createAxisOperation(requestName, opName, HTTPConstants.HTTP_METHOD_POST, hasResult, soap11Binding,
                soap12Binding, httpBinding, description);
    }

    /**
     * Creates an AxisOperation with the given data service resource object.
     * @see Operation
     * @see AxisOperation
     */
    private AxisOperation createAxisOperationFromDSResource(Resource resource, AxisBinding soap11Binding,
            AxisBinding soap12Binding, AxisBinding httpBinding) {
        ResourceID resourceId = resource.getResourceId();
        String method = resourceId.getMethod();
        String path = resourceId.getPath();
        String requestName = resource.getRequestName();
        String description = resource.getDescription();
        boolean hasResult = resource.getCallQuery().isHasResult() || resource.isReturnRequestStatus();
        return createAxisOperation(requestName, path, method, hasResult, soap11Binding, soap12Binding, httpBinding,
                description);
    }

    /**
     * Utility method for creating AxisOperation objects.
     */
    private AxisOperation createAxisOperation(String operationName, String httpLocation, String method,
            boolean hasResult, AxisBinding soap11Binding, AxisBinding soap12Binding, AxisBinding httpBinding,
            String description) {
        AxisOperation axisOperation;
        if (hasResult) {
            axisOperation = new InOutAxisOperation(new QName(operationName));
            DBInOutMessageReceiver inoutMsgReceiver = new DBInOutMessageReceiver();
            axisOperation.setMessageReceiver(inoutMsgReceiver);
            axisOperation.setMessageExchangePattern(WSDL2Constants.MEP_URI_IN_OUT);
        } else {
            axisOperation = new InOnlyAxisOperation(new QName(operationName));
            DBInOnlyMessageReceiver inonlyMsgReceiver = new DBInOnlyMessageReceiver();
            axisOperation.setMessageReceiver(inonlyMsgReceiver);
            axisOperation.setMessageExchangePattern(WSDL2Constants.MEP_URI_ROBUST_IN_ONLY);
        }

        axisOperation.setStyle(WSDLConstants.STYLE_DOC);

        String opName = axisOperation.getName().getLocalPart();
        // Create a default SOAP 1.1 Binding operation
        AxisBindingOperation soap11BindingOperation = createDefaultSOAP11BindingOperation(axisOperation,
                httpLocation, "urn:" + opName, soap11Binding);

        // Create a default SOAP 1.2 Binding operation
        AxisBindingOperation soap12BindingOperation = createDefaultSOAP12BindingOperation(axisOperation,
                httpLocation, "urn:" + opName, soap12Binding);

        // Create a default HTTP Binding operation
        AxisBindingOperation httpBindingOperation = createDefaultHTTPBindingOperation(axisOperation, httpLocation,
                method, httpBinding);

        if (httpLocation.startsWith("/")) {
            httpLocation = httpLocation.substring(1);
        }

        Pattern httpLocationPattern = WSDLUtil.getConstantFromHTTPLocationForResource(httpLocation, method);
        this.httpLocationTableForResource.put(httpLocationPattern, axisOperation);

        // Create the in and out axis messages for this operation
        AxisMessage inMessage = axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
        if (inMessage != null) {
            inMessage.setName(operationName + Java2WSDLConstants.MESSAGE_SUFFIX);
            createAxisBindingMessage(soap11BindingOperation, inMessage, WSDLConstants.MESSAGE_LABEL_IN_VALUE,
                    false);
            createAxisBindingMessage(soap12BindingOperation, inMessage, WSDLConstants.MESSAGE_LABEL_IN_VALUE,
                    false);
            createAxisBindingMessage(httpBindingOperation, inMessage, WSDLConstants.MESSAGE_LABEL_IN_VALUE, false);
        }

        if (axisOperation instanceof InOutAxisOperation) {
            AxisMessage outMessage = axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
            if (outMessage != null) {
                outMessage.setName(operationName + Java2WSDLConstants.RESPONSE_MESSAGE);
                createAxisBindingMessage(soap11BindingOperation, outMessage, WSDLConstants.MESSAGE_LABEL_OUT_VALUE,
                        false);
                createAxisBindingMessage(soap12BindingOperation, outMessage, WSDLConstants.MESSAGE_LABEL_OUT_VALUE,
                        false);
                createAxisBindingMessage(httpBindingOperation, outMessage, WSDLConstants.MESSAGE_LABEL_OUT_VALUE,
                        false);
            }
        }
        /* Set the fault message, only if operation returns a result*/
        if (hasResult) {
            AxisMessage faultMessage = new AxisMessage();
            faultMessage.setName(DBConstants.DS_FAULT_ELEMENT);
            faultMessage.setElementQName(new QName(DBConstants.WSO2_DS_NAMESPACE, DBConstants.DS_FAULT_ELEMENT));
            axisOperation.setFaultMessages(faultMessage);
            createAxisBindingMessage(soap11BindingOperation, faultMessage, WSDLConstants.MESSAGE_LABEL_FAULT_VALUE,
                    true);
            createAxisBindingMessage(soap12BindingOperation, faultMessage, WSDLConstants.MESSAGE_LABEL_FAULT_VALUE,
                    true);
            createAxisBindingMessage(httpBindingOperation, faultMessage, WSDLConstants.MESSAGE_LABEL_FAULT_VALUE,
                    true);
        }

        axisOperation.setDocumentation(description);
        return axisOperation;
    }

    /**
     * Creates a schema from a DataService object, to be used later in WSDL generation.
     */
    @SuppressWarnings("unchecked")
    private void createDSSchema(AxisService axisService, DataService dataService) throws DataServiceFault {
        NamespaceMap map = new NamespaceMap();
        map.put(Java2WSDLConstants.DEFAULT_SCHEMA_NAMESPACE_PREFIX, Java2WSDLConstants.URI_2001_SCHEMA_XSD);
        axisService.setNamespaceMap(map);
        DataServiceDocLitWrappedSchemaGenerator.populateServiceSchema(axisService);
    }

    /**
     * Validate the data service to see if the data service is invalid.
     */
    private void validateDataService(DataService dataService) throws DataServiceFault {
        this.validateRequestCallQuery(dataService);
        this.validateRequestQueryParams(dataService);
        this.validateRequestQueryResults(dataService);
    }

    /**
     * Check call-queries of callable requests (i.e. operations, resources) to see if the queries
     * exists.
     */
    private void validateRequestCallQuery(DataService dataService) throws DataServiceFault {
        for (CallableRequest cr : dataService.getCallableRequests().values()) {
            CallQuery callQuery = cr.getCallQuery();
            if (callQuery.getQuery() == null) {
                DataServiceFault dsf = new DataServiceFault("Invalid DBS",
                        "Call query with id: " + callQuery.getQueryId()
                                + " doesn't exist as referenced by the operation/resource: " + cr.getRequestName());
                dsf.setSourceDataService(dataService);
                throw dsf;
            }
        }
    }

    /**
     * Check query-params if they exist in the query as mentioned in the 'with-params' in
     * operation/resource, the computational complexity of this code is not an issue, since this is
     * deployment time.
     */
    private void validateRequestQueryParams(DataService dataService) throws DataServiceFault {
        for (CallableRequest cr : dataService.getCallableRequests().values()) {
            CallQuery callQuery = cr.getCallQuery();
            Query query = callQuery.getQuery();
            for (WithParam withParam : callQuery.getWithParams().values()) {
                boolean found = false;
                for (QueryParam queryParam : query.getQueryParams()) {
                    if (withParam.getName().equals(queryParam.getName())) {
                        found = true;
                        break;
                    }
                }
                if (found) {
                    /* param found, move onto next 'with-param' */
                    continue;
                } else {
                    /* the param is not found in the query, throw an exception */
                    DataServiceFault dsf = new DataServiceFault("Invalid DBS",
                            "with-param with name: " + withParam.getName() + " doesn't exist in query with id: "
                                    + query.getQueryId() + " as referenced by the operation/resource: "
                                    + cr.getRequestName());
                    dsf.setSourceDataService(dataService);
                    throw dsf;
                }
            }
        }
    }

    /**
     * Check if an request's query has a result, and if that result contain an element wrapper.
     */
    private void validateRequestQueryResults(DataService dataService) throws DataServiceFault {
        for (CallableRequest request : dataService.getCallableRequests().values()) {
            CallQuery callQuery = request.getCallQuery();
            if (callQuery == null) {
                continue;
            }
            Query query = callQuery.getQuery();
            if (query == null) {
                continue;
            }
            if (query.getResult() != null) {
                if (query.getResult().getResultType() != ResultTypes.JSON
                        && DBUtils.isEmptyString(query.getResult().getElementName())) {
                    throw new DataServiceFault(
                            "The request '" + request.getRequestName() + "' contains the query with id '"
                                    + query.getQueryId() + "' contains an XML result with no element wrapper.");
                }
            }
        }
    }

    /**
     * Creates AxisService from DBS.
     */
    private AxisService createDBService(String configFilePath, AxisConfiguration axisConfiguration)
            throws DataServiceFault {
        FileInputStream fis = null;
        try {
            /* convert to multiple config format */
            convertConfigToMultipleDSFormat(configFilePath);

            fis = new FileInputStream(configFilePath);
            OMElement dbsElement = (new StAXOMBuilder(fis)).getDocumentElement();
            dbsElement.build();

            /* apply secure vault information in resolving the aliases to decrypted values */
            this.secureVaultResolve(dbsElement);

            /* create the data service object from dbs */
            DataService dataService = DataServiceFactory.createDataService(dbsElement, configFilePath);

            String serviceName = dataService.getName();
            if (DBUtils.isAvailableDS(axisConfig, serviceName)) {
                throw new DataServiceFault(
                        "Data Service name is already exists. Please choose different name for \'" + serviceName
                                + "\' data service.");
            }

            /*create the odata service */
            for (String configId : dataService.getConfigs().keySet()) {
                Config config = dataService.getConfig(configId);
                if (config.isODataEnabled()) {
                    ODataServiceHandler serviceHandler = new ODataServiceHandler(config.createODataHandler(),
                            dataService.getServiceNamespace(), configId);
                    CarbonContext cCtx = CarbonContext.getThreadLocalCarbonContext();
                    registerODataHandler(dataService.getName(), serviceHandler, cCtx.getTenantDomain(), configId);
                }
            }

            /* validate the data service */
            this.validateDataService(dataService);

            String interfaceName = serviceName + WSDL2Constants.INTERFACE_PREFIX;

            AxisService axisService = new AxisService(serviceName);
            try {
                axisService.setFileName(new URL("file://" + configFilePath));
            } catch (MalformedURLException e) {
                throw new DataServiceFault(e);
            }

            /* set service target namespace */
            axisService.setTargetNamespace(dataService.getServiceNamespace());

            /* Used by the container to find out what kind of a service this is. */
            axisService.addParameter(new Parameter(DBConstants.AXIS2_SERVICE_TYPE, DBConstants.DB_SERVICE_TYPE));

            /* save the data service object in the AxisService */
            axisService.addParameter(DBConstants.DATA_SERVICE_OBJECT, dataService);

            /* set service description */
            axisService.setDocumentation(dataService.getDescription());

            this.httpLocationTable = new TreeMap<String, AxisOperation>(new Comparator<String>() {
                public int compare(String o1, String o2) {
                    return (-1 * o1.compareTo(o2));
                }
            });
            this.httpLocationTableForResource = new TreeMap<Pattern, AxisOperation>(new Comparator<Pattern>() {
                public int compare(Pattern o1, Pattern o2) {
                    return (-1 * o1.pattern().compareTo(o2.pattern()));
                }
            });

            AxisBinding soap11Binding = createDefaultSOAP11Binding(serviceName, interfaceName);
            AxisBinding soap12Binding = createDefaultSOAP12Binding(serviceName, interfaceName);
            AxisBinding httpBinding = createDefaultHTTPBinding(serviceName, interfaceName);

            /* REST processing - adding DS resources to AxisService */
            Set<ResourceID> resourceIds = dataService.getResourceIds();
            for (ResourceID resourceId : resourceIds) {
                Resource resource = dataService.getResource(resourceId);
                AxisOperation axisOperation = createAxisOperationFromDSResource(resource, soap11Binding,
                        soap12Binding, httpBinding);
                axisService.addOperation(axisOperation);
                axisConfig.getPhasesInfo().setOperationPhases(axisOperation);
            }

            /* add operations */
            Iterator<String> opPathItr = dataService.getOperationNames().iterator();
            while (opPathItr.hasNext()) {
                Operation operation = dataService.getOperation(opPathItr.next());
                AxisOperation axisOperation = createAxisOperationFromDSOperation(operation, soap11Binding,
                        soap12Binding, httpBinding);
                axisService.addOperation(axisOperation);
                axisConfig.getPhasesInfo().setOperationPhases(axisOperation);
            }

            createDefaultEndpoints(axisService, soap11Binding, soap12Binding, httpBinding);

            /* create schema */
            createDSSchema(axisService, dataService);

            /* set session scope type for boxcarring */
            if (dataService.isBoxcarringEnabled()) {
                axisService.setScope(Constants.SCOPE_TRANSPORT_SESSION);
            }

            /* register JMX MBean */
            this.registerMBean(dataService);

            /* set service status */
            axisService.setActive(!dataService.isServiceInactive());

            return axisService;
        } catch (FileNotFoundException e) {
            throw new DataServiceFault(e, "Error reading service configuration file.");
        } catch (XMLStreamException e) {
            throw new DataServiceFault(e, "Error while parsing the service configuration file.");
        } catch (AxisFault e) {
            throw new DataServiceFault(e);
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                log.error("Error in closing data services configuration file", e);
            }
        }
    }

    /**
     * Registers an MBean representing the given data service.
     */
    private void registerMBean(DataService dataService) {
        DataServiceInstanceMBean dsMBean = new DataServiceInstance(dataService);
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        if (server != null) {
            try {
                ObjectName objectName = new ObjectName(DBConstants.DATA_SERVICES_JMX_DOMAIN
                        + ":section=Services,service=" + dsMBean.getServiceName());
                try {
                    server.unregisterMBean(objectName);
                } catch (Exception ignore) {
                    /* ignore if it doesn't exist */
                }
                server.registerMBean(dsMBean, objectName);
            } catch (Exception e) {
                log.error("Error in Registering Data Services MBean", e);
            }
        }
    }

    /**
     * Creates AxisBindingMessage and populates it.
     */
    private void createAxisBindingMessage(AxisBindingOperation bindingOperation, AxisMessage inMessage,
            String label, boolean isFault) {
        AxisBindingMessage soap11InBindingMessage = new AxisBindingMessage();
        soap11InBindingMessage.setName(inMessage.getName());
        soap11InBindingMessage.setAxisMessage(inMessage);
        soap11InBindingMessage.setParent(bindingOperation);
        if (isFault) {
            soap11InBindingMessage.setFault(true);
            bindingOperation.addFault(soap11InBindingMessage);
        } else {
            soap11InBindingMessage.setFault(false);
            bindingOperation.addChild(label, soap11InBindingMessage);
        }
    }

    /**
     * Creates AxisBindingOperation and populates it with HTTP properties
     */
    private AxisBindingOperation createDefaultHTTPBindingOperation(AxisOperation axisOp, String httpLocation,
            String httpMethod, AxisBinding httpBinding) {
        AxisBindingOperation httpBindingOperation = new AxisBindingOperation();
        httpBindingOperation.setAxisOperation(axisOp);
        httpBindingOperation.setName(axisOp.getName());
        httpBindingOperation.setParent(httpBinding);
        httpBindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION, httpLocation);
        httpBindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_METHOD, httpMethod);
        httpBinding.addChild(httpBindingOperation.getName(), httpBindingOperation);
        return httpBindingOperation;
    }

    /**
     * Creates AxisBindingOperation and populates it with SOAP 1.2 properties
     */
    private AxisBindingOperation createDefaultSOAP12BindingOperation(AxisOperation axisOp, String httpLocation,
            String inputAction, AxisBinding soap12Binding) {
        AxisBindingOperation soap12BindingOperation = new AxisBindingOperation();
        soap12BindingOperation.setAxisOperation(axisOp);
        soap12BindingOperation.setName(axisOp.getName());
        soap12BindingOperation.setParent(soap12Binding);
        soap12BindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION, httpLocation);
        soap12Binding.addChild(soap12BindingOperation.getName(), soap12BindingOperation);
        soap12BindingOperation.setProperty(WSDL2Constants.ATTR_WSOAP_ACTION, inputAction);
        return soap12BindingOperation;
    }

    /**
     * Creates AxisBindingOperation and populates it with SOAP 1.1 properties
     */
    private AxisBindingOperation createDefaultSOAP11BindingOperation(AxisOperation axisOp, String httpLocation,
            String inputAction, AxisBinding soap11Binding) {
        AxisBindingOperation soap11BindingOperation = new AxisBindingOperation();
        soap11BindingOperation.setAxisOperation(axisOp);
        soap11BindingOperation.setName(axisOp.getName());
        soap11BindingOperation.setParent(soap11Binding);
        soap11BindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION, httpLocation);
        soap11Binding.addChild(soap11BindingOperation.getName(), soap11BindingOperation);
        soap11BindingOperation.setProperty(WSDL2Constants.ATTR_WSOAP_ACTION, inputAction);
        return soap11BindingOperation;
    }

    /**
     * Creates a AxisBinding and populates it with default SOAP 1.1 properties
     */
    private AxisBinding createDefaultSOAP11Binding(String name, String interfaceName) {
        AxisBinding soap11Binding = new AxisBinding();
        soap11Binding.setName(new QName(name + Java2WSDLConstants.BINDING_NAME_SUFFIX));
        soap11Binding.setType(WSDL2Constants.URI_WSDL2_SOAP);
        soap11Binding.setProperty(WSDL2Constants.ATTR_WSOAP_PROTOCOL, WSDL2Constants.HTTP_PROTOCAL);
        soap11Binding.setProperty(WSDL2Constants.ATTR_WSOAP_VERSION, SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
        soap11Binding.setProperty(WSDL2Constants.INTERFACE_LOCAL_NAME, interfaceName);
        soap11Binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
        soap11Binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE_FOR_RESOURCE, httpLocationTableForResource);
        return soap11Binding;
    }

    /**
     * Creates a AxisBinding and populates it with default HTTP properties
     */
    private AxisBinding createDefaultHTTPBinding(String name, String interfaceName) {
        AxisBinding httpBinding = new AxisBinding();
        httpBinding.setName(new QName(name + Java2WSDLConstants.HTTP_BINDING));
        httpBinding.setType(WSDL2Constants.URI_WSDL2_HTTP);
        httpBinding.setProperty(WSDL2Constants.INTERFACE_LOCAL_NAME, interfaceName);
        httpBinding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
        httpBinding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE_FOR_RESOURCE, httpLocationTableForResource);
        return httpBinding;
    }

    /**
     * Creates a AxisBinding and populates it with default SOAP 1.2 properties
     */
    private AxisBinding createDefaultSOAP12Binding(String name, String interfaceName) {
        AxisBinding soap12Binding = new AxisBinding();
        soap12Binding.setName(new QName(name + Java2WSDLConstants.SOAP12BINDING_NAME_SUFFIX));
        soap12Binding.setType(WSDL2Constants.URI_WSDL2_SOAP);
        soap12Binding.setProperty(WSDL2Constants.ATTR_WSOAP_PROTOCOL, WSDL2Constants.HTTP_PROTOCAL);
        soap12Binding.setProperty(WSDL2Constants.ATTR_WSOAP_VERSION, SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
        soap12Binding.setProperty(WSDL2Constants.INTERFACE_LOCAL_NAME, interfaceName);
        soap12Binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
        soap12Binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE_FOR_RESOURCE, httpLocationTableForResource);
        return soap12Binding;
    }

    /**
     * Creates a set of default endpoints for this service
     */
    private void createDefaultEndpoints(AxisService axisService, AxisBinding soap11Binding,
            AxisBinding soap12Binding, AxisBinding httpBinding) {
        Map<String, TransportInDescription> transportsIn = axisConfig.getTransportsIn();
        Iterator<TransportInDescription> iterator = transportsIn.values().iterator();
        while (iterator.hasNext()) {
            /*
             * Used to indicate whether a HTTPEndpoint is needed. Http endpoint
             * is needed only for http and https transports
             */
            boolean needHttp = false;

            /* The prefix is used to generate endpoint names */
            String prefix = "";
            TransportInDescription transportIn = iterator.next();
            String transportInName = transportIn.getName();
            if (HTTP_TRANSPORT.equalsIgnoreCase(transportInName)) {
                needHttp = true;
            } else if (HTTPS_TRANSPORT.equalsIgnoreCase(transportInName)) {
                needHttp = true;
                prefix = WSDL2Constants.DEFAULT_HTTPS_PREFIX;
            } else if (transportInName != null) {
                prefix = transportInName.toUpperCase();
            }

            /* Creates a default SOAP 1.1 endpoint */
            AxisEndpoint soap11Endpoint = new AxisEndpoint();
            String soap11EndpointName = prefix + WSDL2Constants.DEFAULT_SOAP11_ENDPOINT_NAME;
            soap11Endpoint.setName(soap11EndpointName);
            soap11Endpoint.setBinding(soap11Binding);
            soap11Endpoint.setParent(axisService);
            soap11Endpoint.setTransportInDescription(transportInName);
            soap11Endpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
            soap11Endpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE_FOR_RESOURCE,
                    httpLocationTableForResource);
            axisService.addEndpoint(soap11EndpointName, soap11Endpoint);

            /* setting soap11 endpoint as the default endpoint */
            axisService.setEndpointName(soap11EndpointName);

            /* Creates a default SOAP 1.2 endpoint */
            AxisEndpoint soap12Endpoint = new AxisEndpoint();
            String soap12EndpointName = prefix + WSDL2Constants.DEFAULT_SOAP12_ENDPOINT_NAME;
            soap12Endpoint.setName(soap12EndpointName);
            soap12Endpoint.setBinding(soap12Binding);
            soap12Endpoint.setParent(axisService);
            soap12Endpoint.setTransportInDescription(transportInName);
            soap12Endpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
            soap12Endpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE_FOR_RESOURCE,
                    httpLocationTableForResource);
            axisService.addEndpoint(soap12EndpointName, soap12Endpoint);

            /* Creates a HTTP endpoint if its http or https transport is used */
            if (needHttp) {
                AxisEndpoint httpEndpoint = new AxisEndpoint();
                String httpEndpointName = prefix + WSDL2Constants.DEFAULT_HTTP_ENDPOINT_NAME;
                httpEndpoint.setName(httpEndpointName);
                httpEndpoint.setBinding(httpBinding);
                httpEndpoint.setParent(axisService);
                httpEndpoint.setTransportInDescription(transportInName);
                httpEndpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
                httpEndpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE_FOR_RESOURCE,
                        httpLocationTableForResource);
                axisService.addEndpoint(httpEndpointName, httpEndpoint);
            }
        }
    }

    /**
     * This method checks if the given data service has a corresponding "services.xml" is available,
     * if so, the AxisService representing the data service is applied the instructions from its
     * "services.xml".
     */
    private AxisService handleTransports(DeploymentFileData file, AxisService axisService) throws DataServiceFault {
        try {
            StAXOMBuilder builder = new StAXOMBuilder(new FileInputStream(file.getFile().getAbsoluteFile()));
            OMElement documentElement = builder.getDocumentElement();
            OMAttribute transports = documentElement.getAttribute(new QName(DBSFields.TRANSPORTS));
            if (transports != null) {
                String[] transportArr = transports.getAttributeValue().split(" ");
                axisService.setExposedTransports(Arrays.asList(transportArr));
            }
        } catch (Exception e) {
            throw new DataServiceFault(e, "Error in processing transports info");
        }
        return axisService;
    }

    /**
     * Creates AxisService with the given deployment information.
     */
    private AxisService processService(DeploymentFileData currentFile, AxisServiceGroup axisServiceGroup,
            ConfigurationContext configCtx) throws DataServiceFault {
        AxisService axisService = createDBService(currentFile.getAbsolutePath(), configCtx.getAxisConfiguration());
        axisService.setParent(axisServiceGroup);
        axisService.setClassLoader(axisConfig.getServiceClassLoader());
        /* handle services.xml, if exists */
        this.handleTransports(currentFile, axisService);
        return axisService;
    }

    /**
     * Helper method to handle security policies.
     *
     * @param file deployment data file.
     * @param axisService to be modified.
     * @return true if security is enabled, false otherwise.
     * @throws DataServiceFault
     */
    private boolean handleSecurityProxy(DeploymentFileData file, AxisService axisService) throws DataServiceFault {
        try {
            boolean secEnabled = false;
            StAXOMBuilder builder = new StAXOMBuilder(new FileInputStream(file.getFile().getAbsoluteFile()));
            OMElement documentElement = builder.getDocumentElement();
            OMElement enableSecElement = documentElement.getFirstChildWithName(new QName(DBSFields.ENABLESEC));
            if (enableSecElement != null) {
                secEnabled = true;
            }
            OMElement policyElement = documentElement.getFirstChildWithName(new QName(DBSFields.POLICY));
            if (policyElement != null) {
                String policyKey = policyElement.getAttributeValue(new QName(DBSFields.POLICY_KEY));
                if (null == policyKey) {
                    throw new DataServiceFault(
                            "Policy key element should contain a policy key in " + file.getFile().getName());
                }
                Policy policy = PolicyEngine.getPolicy(DBUtils.getInputStreamFromPath(policyKey));
                axisService.getPolicySubject().attachPolicy(policy);
            }
            return secEnabled;
        } catch (Exception e) {
            throw new DataServiceFault(e, "Error in processing security policy");
        }
    }

    @SuppressWarnings("unchecked")
    private void secureVaultResolve(OMElement dbsElement) {
        String secretAliasAttr = dbsElement.getAttributeValue(
                new QName(DataSourceConstants.SECURE_VAULT_NS, DataSourceConstants.SECRET_ALIAS_ATTR_NAME));
        if (secretAliasAttr != null) {
            dbsElement.setText(DBUtils.loadFromSecureVault(secretAliasAttr));
        }
        Iterator<OMElement> childEls = (Iterator<OMElement>) dbsElement.getChildElements();
        while (childEls.hasNext()) {
            this.secureVaultResolve(childEls.next());
        }
    }

    private void removeODataHandler(String tenantDomain, String dataServiceName) throws DataServiceFault {
        ODataServiceRegistry registry = ODataServiceRegistry.getInstance();
        registry.removeODataService(tenantDomain, dataServiceName);
    }

    private void registerODataHandler(String dataServiceName, ODataServiceHandler handler, String tenantDomain,
            String configId) throws DataServiceFault {
        ODataServiceRegistry registry = ODataServiceRegistry.getInstance();
        registry.registerODataService(dataServiceName + configId, handler, tenantDomain);
    }
}