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

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.dataservices.core.DBUtils.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.OMAbstractFactory;
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.databinding.utils.ConverterUtil;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.java2wsdl.TypeTable;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
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.RDBMSEngines;
import org.wso2.carbon.dataservices.common.RDBMSUtils;
import org.wso2.carbon.dataservices.core.auth.AuthorizationProvider;
import org.wso2.carbon.dataservices.core.auth.UserStoreAuthorizationProvider;
import org.wso2.carbon.dataservices.core.description.config.Config;
import org.wso2.carbon.dataservices.core.engine.DataService;
import org.wso2.carbon.dataservices.core.engine.ExternalParam;
import org.wso2.carbon.dataservices.core.engine.ExternalParamCollection;
import org.wso2.carbon.dataservices.core.engine.InternalParam;
import org.wso2.carbon.dataservices.core.engine.ParamValue;
import org.wso2.carbon.dataservices.core.internal.DataServicesDSComponent;
import org.wso2.carbon.ndatasource.core.utils.DataSourceUtils;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import org.wso2.carbon.utils.xml.XMLPrettyPrinter;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;

import javax.naming.InitialContext;
import javax.transaction.TransactionManager;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.sql.Date;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Utility class for data services based operations.
 */
public class DBUtils {

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

    private static Pattern udtPattern = Pattern.compile("(.*?(\\[\\d+\\]))");

    private static ScheduledExecutorService globalExecutorService = Executors.newSingleThreadScheduledExecutor();

    private static HashMap<String, String> conversionTypes = null;

    private static HashMap<String, String> xsdSqlTypeMap = null;

    /* initialize the conversion types */

    static {
        conversionTypes = new HashMap<String, String>();
        conversionTypes.put(DBConstants.DataTypes.CHAR, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.STRING, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.QUERY_STRING, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.VARCHAR, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.NVARCHAR, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.TEXT, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.NUMERIC, "java.math.BigDecimal");
        conversionTypes.put(DBConstants.DataTypes.DECIMAL, "java.math.BigDecimal");
        conversionTypes.put(DBConstants.DataTypes.MONEY, "java.math.BigDecimal");
        conversionTypes.put(DBConstants.DataTypes.SMALLMONEY, "java.math.BigDecimal");
        conversionTypes.put(DBConstants.DataTypes.BIT, "boolean");
        conversionTypes.put(DBConstants.DataTypes.BOOLEAN, "boolean");
        conversionTypes.put(DBConstants.DataTypes.TINYINT, "byte");
        conversionTypes.put(DBConstants.DataTypes.SMALLINT, "short");
        conversionTypes.put(DBConstants.DataTypes.INTEGER, "int");
        conversionTypes.put(DBConstants.DataTypes.BIGINT, "long");
        conversionTypes.put(DBConstants.DataTypes.REAL, "float");
        conversionTypes.put(DBConstants.DataTypes.FLOAT, "double");
        conversionTypes.put(DBConstants.DataTypes.DOUBLE, "double");
        conversionTypes.put(DBConstants.DataTypes.BINARY, "base64Binary"); /* byte[] */
        conversionTypes.put(DBConstants.DataTypes.VARBINARY, "base64Binary"); /* byte[] */
        conversionTypes.put(DBConstants.DataTypes.LONG_VARBINARY, "base64Binary"); /* byte [] */
        conversionTypes.put(DBConstants.DataTypes.IMAGE, "base64Binary"); /* byte[] */
        conversionTypes.put(DBConstants.DataTypes.BLOB, "base64Binary"); /* byte[] */
        conversionTypes.put(DBConstants.DataTypes.DATE, "java.sql.Date");
        conversionTypes.put(DBConstants.DataTypes.TIME, "java.sql.Time");
        conversionTypes.put(DBConstants.DataTypes.TIMESTAMP, "java.sql.Timestamp");
        conversionTypes.put(DBConstants.DataTypes.ANYURI, "java.net.URI");
        conversionTypes.put(DBConstants.DataTypes.STRUCT, "java.sql.Struct");

        conversionTypes.put(DBConstants.DataTypes.VARINT, "java.math.BigInteger");
        conversionTypes.put(DBConstants.DataTypes.UUID, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.INETADDRESS, "java.lang.String");
        conversionTypes.put(DBConstants.DataTypes.CLOB, "java.lang.String");

        xsdSqlTypeMap = new HashMap<String, String>();
        xsdSqlTypeMap.put("string", DBConstants.DataTypes.STRING);
        xsdSqlTypeMap.put("boolean", DBConstants.DataTypes.BOOLEAN);
        xsdSqlTypeMap.put("int", DBConstants.DataTypes.INTEGER);
        xsdSqlTypeMap.put("integer", DBConstants.DataTypes.INTEGER);
        xsdSqlTypeMap.put("long", DBConstants.DataTypes.LONG);
        xsdSqlTypeMap.put("float", DBConstants.DataTypes.FLOAT);
        xsdSqlTypeMap.put("double", DBConstants.DataTypes.DOUBLE);
        xsdSqlTypeMap.put("decimal", DBConstants.DataTypes.DECIMAL);
        xsdSqlTypeMap.put("dateTime", DBConstants.DataTypes.TIMESTAMP);
        xsdSqlTypeMap.put("time", DBConstants.DataTypes.TIME);
        xsdSqlTypeMap.put("date", DBConstants.DataTypes.DATE);
        xsdSqlTypeMap.put("base64Binary", DBConstants.DataTypes.BINARY);
        xsdSqlTypeMap.put("binary", DBConstants.DataTypes.BINARY);
    }

    private static SecretResolver secretResolver;

    private static XMLOutputFactory xmlOutputFactory;

    /** pre-fetch the XMLOutputFactory */
    static {
        xmlOutputFactory = XMLOutputFactory.newInstance();
    }

    private static XMLInputFactory xmlInputFactory;

    /** pre-fetch the XMLInputFactory */
    static {
        xmlInputFactory = XMLInputFactory.newInstance();
    }

    private static OMFactory omFactory;

    /** pre-fetch the OMFactory */
    static {
        omFactory = OMAbstractFactory.getOMFactory();
    }

    public static XMLOutputFactory getXMLOutputFactory() {
        return xmlOutputFactory;
    }

    public static XMLInputFactory getXMLInputFactory() {
        return xmlInputFactory;
    }

    public static OMFactory getOMFactory() {
        return omFactory;
    }

    /**
     * Converts from DS SQL types to Java types, e.g. "STRING" -> "java.lang.String".
     */
    public static String getJavaTypeFromSQLType(String sqlType) {
        return conversionTypes.get(sqlType);
    }

    /**
     * Converts from XML schema types to DS SQL types, e.g. "string" -> "STRING".
     */
    public static String getSQLTypeFromXsdType(String xsdType) {
        String sqlType = xsdSqlTypeMap.get(xsdType);
        if (sqlType == null) {
            sqlType = DBConstants.DataTypes.STRING;
        }
        return sqlType;
    }

    public static String getCurrentContextUsername(DataService dataService) {
        MessageContext ctx = MessageContext.getCurrentMessageContext();
        if (ctx != null) {
            try {
                return dataService.getAuthorizationProvider().getUsername(ctx);
            } catch (DataServiceFault dataServiceFault) {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Retrieves the current user's roles given the username.
     *
     * @param username The username
     * @return The user roles
     * @throws DataServiceFault
     */
    public static String[] getUserRoles(String username) throws DataServiceFault {
        RealmService realmService = DataServicesDSComponent.getRealmService();
        RegistryService registryService = DataServicesDSComponent.getRegistryService();
        String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
        int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
        try {
            if (tenantId < MultitenantConstants.SUPER_TENANT_ID) {
                tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
            }
            if (tenantId < MultitenantConstants.SUPER_TENANT_ID) {
                /* the tenant doesn't exist. */
                log.error("The tenant doesn't exist. Tenant domain:" + tenantDomain);
                throw new DataServiceFault("Access Denied. You are not authorized.");
            }
            if (tenantId != MultitenantConstants.SUPER_TENANT_ID) { //tenant space users can't access super tenant
                username = MultitenantUtils.getTenantAwareUsername(username);
            }
            if (!realmService.getTenantManager().isTenantActive(tenantId)) {
                /* the tenant is not active. */
                log.error("The tenant is not active. Tenant domain:" + tenantDomain);
                throw new DataServiceFault("The tenant is not active. Tenant domain:" + tenantDomain);
            }
            UserRealm realm = registryService.getUserRealm(tenantId);
            String roles[] = realm.getUserStoreManager().getRoleListOfUser(username);
            return roles;
        } catch (Exception e) {
            String msg = "Error in retrieving the realm for the tenant id: " + tenantId + ", username: " + username
                    + ". " + e.getMessage();
            log.error(msg);
            throw new DataServiceFault(msg);
        }
    }

    /**
     * Retrieves all roles for a given tenantId to be used in role based filtering when creating dataservice.
     *
     * @return The user roles
     * @throws DataServiceFault
     */
    public static String[] getAllRoles(int tenantId) throws DataServiceFault {
        RegistryService registryService = DataServicesDSComponent.getRegistryService();
        try {
            UserRealm realm = registryService.getUserRealm(tenantId);
            String roles[] = realm.getUserStoreManager().getRoleNames();
            return roles;
        } catch (Exception e) {
            String msg = "Error in retrieving the realm for the tenant id: " + tenantId + ". " + e.getMessage();
            log.error(msg);
            throw new DataServiceFault(msg);
        }
    }

    /**
     * This method is to get current user tenant ID, This will be only called when creating data service with
     * role based filtering. So a user will invoke this method hence there should be active session when this is
     * called.
     *
     * @return tenantId
     * @throws DataServiceFault
     */
    public static int getCurrentUserTenantId() throws DataServiceFault {
        RealmService realmService = DataServicesDSComponent.getRealmService();
        String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
        int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
        try {
            if (tenantId < MultitenantConstants.SUPER_TENANT_ID) {
                tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
            }
            if (tenantId < MultitenantConstants.SUPER_TENANT_ID) {
                /* the tenant doesn't exist. */
                log.error("The tenant doesn't exist. Tenant domain:" + tenantDomain);
                throw new DataServiceFault("Access Denied. You are not authorized.");
            }
            if (!realmService.getTenantManager().isTenantActive(tenantId)) {
                /* the tenant is not active. */
                log.error("The tenant is not active. Tenant domain:" + tenantDomain);
                throw new DataServiceFault("The tenant is not active. Tenant domain:" + tenantDomain);
            }
            return tenantId;
        } catch (Exception e) {
            String msg = "Error in retrieving the realm for the tenant id: " + tenantId + ". " + e.getMessage();
            log.error(msg);
            throw new DataServiceFault(msg);
        }
    }

    public static boolean authenticate(String username, String password) throws DataServiceFault {
        try {
            RegistryService registryService = DataServicesDSComponent.getRegistryService();
            UserRealm realm = registryService
                    .getUserRealm(PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId());
            username = MultitenantUtils.getTenantAwareUsername(username);
            return realm.getUserStoreManager().authenticate(username, password);
        } catch (Exception e) {
            throw new DataServiceFault(e, "Error in authenticating user '" + username + "'");
        }
    }

    /**
     * This method returns the available data services names.
     *
     * @param axisConfiguration Axis configuration
     * @return names of available data services
     * @throws AxisFault
     */
    public static String[] getAvailableDS(AxisConfiguration axisConfiguration) throws AxisFault {
        List<String> serviceList = new ArrayList<>();
        Map<String, AxisService> map = axisConfiguration.getServices();
        Set<String> set = map.keySet();
        for (String serviceName : set) {
            AxisService axisService = axisConfiguration.getService(serviceName);
            Parameter parameter = axisService.getParameter(DBConstants.AXIS2_SERVICE_TYPE);
            if (parameter != null) {
                if (DBConstants.DB_SERVICE_TYPE.equals(parameter.getValue().toString())) {
                    serviceList.add(serviceName);
                }
            }
        }
        return serviceList.toArray(new String[serviceList.size()]);
    }

    /**
     * This method verifies whether there's an existing data service for the given name.
     *
     * @param axisConfiguration Axis configuration
     * @param dataService       Data service
     * @return Boolean (Is available)
     * @throws AxisFault
     */
    public static boolean isAvailableDS(AxisConfiguration axisConfiguration, String dataService) throws AxisFault {
        Map<String, AxisService> map = axisConfiguration.getServices();
        AxisService axisService = map.get(dataService);
        if (axisService != null) {
            Parameter parameter = axisService.getParameter(DBConstants.AXIS2_SERVICE_TYPE);
            if (parameter != null) {
                if (DBConstants.DB_SERVICE_TYPE.equals(parameter.getValue().toString())) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean isRegistryPath(String path) {
        if (path.startsWith(DBConstants.CONF_REGISTRY_PATH_PREFIX)
                || path.startsWith(DBConstants.GOV_REGISTRY_PATH_PREFIX)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Creates and returns an InputStream from the file path / http location given.
     *
     * @throws DataServiceFault
     * @see InputStream
     */
    public static InputStream getInputStreamFromPath(String path) throws IOException, DataServiceFault {
        InputStream ins;
        if (path.startsWith("http://")) {
            /* This is a url file path */
            URL url = new URL(path);
            ins = url.openStream();
        } else if (isRegistryPath(path)) {
            try {
                RegistryService registryService = DataServicesDSComponent.getRegistryService();
                if (registryService == null) {
                    throw new DataServiceFault(
                            "DBUtils.getInputStreamFromPath(): Registry service is not available");
                }
                Registry registry;
                if (path.startsWith(DBConstants.CONF_REGISTRY_PATH_PREFIX)) {
                    if (path.length() > DBConstants.CONF_REGISTRY_PATH_PREFIX.length()) {
                        path = path.substring(DBConstants.CONF_REGISTRY_PATH_PREFIX.length());
                        registry = registryService.getConfigSystemRegistry(getCurrentTenantId());
                    } else {
                        throw new DataServiceFault("Empty configuration registry path given");
                    }
                } else {
                    if (path.length() > DBConstants.GOV_REGISTRY_PATH_PREFIX.length()) {
                        path = path.substring(DBConstants.GOV_REGISTRY_PATH_PREFIX.length());
                        registry = registryService.getGovernanceSystemRegistry(getCurrentTenantId());
                    } else {
                        throw new DataServiceFault("Empty governance registry path given");
                    }
                }
                if (registry.resourceExists(path)) {
                    Resource serviceResource = registry.get(path);
                    ins = serviceResource.getContentStream();
                } else {
                    throw new DataServiceFault("The given XSLT resource path at '" + path + "' does not exist");
                }
            } catch (RegistryException e) {
                String msg = "Error in retrieving the resource: " + path;
                log.error(msg, e);
                throw new DataServiceFault(e, msg);
            }
        } else {
            File csvFile = new File(path);
            if (path.startsWith("." + File.separator) || path.startsWith(".." + File.separator)) {
                /* this is a relative path */
                path = csvFile.getAbsolutePath();
            }
            /* local file */
            ins = new FileInputStream(path);
        }
        return ins;
    }

    /**
     * create a map which maps the column numbers to column names,
     * column numbers starts with 1 (1 based).
     */
    public static Map<Integer, String> createColumnMappings(String[] header) throws IOException {
        Map<Integer, String> mappings = null;
        if (header != null) {
            mappings = new HashMap<Integer, String>();
            /* add mappings: column index -> column name */
            for (int i = 0; i < header.length; i++) {
                mappings.put(i + 1, header[i]);
            }
        } else {
            mappings = new StringNumberMap();
        }
        return mappings;
    }

    /**
     * This class represents a Map class which always returns the value same as the key.
     */
    private static class StringNumberMap extends AbstractMap<Integer, String> {

        public Set<Map.Entry<Integer, String>> entrySet() {
            return null;
        }

        @Override
        public String get(Object key) {
            return key.toString();
        }

    }

    /**
     * Utility method that returns a string which contains the stack trace of the given
     * Exception object.
     */
    public static String getStacktraceFromException(Throwable e) {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        PrintWriter writer = new PrintWriter(byteOut);
        e.printStackTrace(writer);
        writer.close();
        String message = new String(byteOut.toByteArray());
        return message;
    }

    /**
     * Returns the most suitable value for the JDBC Result Set FetchSize property,
     * for the DBMS engine of the given JDBC URL.
     */
    public static int getOptimalRSFetchSizeForRDBMS(String jdbcUrl) {
        if (jdbcUrl == null) {
            return 1;
        }
        String rdbms = RDBMSUtils.getRDBMSEngine(jdbcUrl);
        if (rdbms.equals(RDBMSEngines.MYSQL)) {
            return Integer.MIN_VALUE;
        } else {
            return 1;
        }
    }

    /**
     * Returns whether or not to apply fetch size for the given jdbc connection
     */
    public static boolean getChangeFetchSizeForRDBMS(String jdbcUrl) {
        if (jdbcUrl == null) {
            return false;
        }
        String rdbms = RDBMSUtils.getRDBMSEngine(jdbcUrl);
        if (rdbms.equals(RDBMSEngines.MYSQL)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Create a Timestamp object from the given timestamp string.
     */
    public static Timestamp getTimestamp(String value) throws DataServiceFault, ParseException {
        if (value == null || value.isEmpty()) {
            throw new DataServiceFault("Empty string or null value was found as timeStamp.");
        }
        return new Timestamp(ConverterUtil.convertToDateTime(value).getTimeInMillis());
    }

    /**
     * Create a Time object from the given time string.
     */
    public static Time getTime(String value) throws DataServiceFault, ParseException {
        if (value == null || value.isEmpty()) {
            throw new DataServiceFault("Empty string or null value was found as time.");
        }
        return new Time(ConverterUtil.convertToTime(value).getAsCalendar().getTimeInMillis());
    }

    /**
     * Create a Date object from the given date string.
     */
    public static Date getDate(String value) throws DataServiceFault {
        /* if something goes wrong with converting the value to a date,
           * try with dateTime and get the date out it, this is because,
           * some service clients send a full date-time string for a date */
        try {
            java.util.Date date = ConverterUtil.convertToDate(value);
            if (null == date) {
                throw new DataServiceFault("Empty string or null value was found as date.");
            } else {
                return new Date(date.getTime());
            }
        } catch (Exception e) {
            java.util.Calendar calendarDate = ConverterUtil.convertToDateTime(value);
            if (null == calendarDate) {
                throw new DataServiceFault("Empty string or null value was found as date.");
            } else {
                return new Date(calendarDate.getTimeInMillis());
            }
        }
    }

    /**
     * Prettify a given XML string
     */
    public static String prettifyXML(String xmlContent) {
        Element element = DataSourceUtils.stringToElement(xmlContent);
        if (element == null) {
            throw new RuntimeException("Error in converting string to XML: " + xmlContent);
        }
        removeWhitespaceInMixedContentElements(element);
        xmlContent = DataSourceUtils.elementToString(element);
        ByteArrayInputStream byteIn = new ByteArrayInputStream(xmlContent.getBytes());
        XMLPrettyPrinter prettyPrinter = new XMLPrettyPrinter(byteIn);
        return prettyPrinter.xmlFormat().trim();
    }

    private static List<Node> getNodesAsList(Element element) {
        List<Node> nodes = new ArrayList<Node>();
        NodeList nodeList = element.getChildNodes();
        int count = nodeList.getLength();
        for (int i = 0; i < count; i++) {
            nodes.add(nodeList.item(i));
        }
        return nodes;
    }

    private static List<Element> getChildElements(Element element) {
        List<Element> childEls = new ArrayList<Element>();
        for (Node tmpNode : getNodesAsList(element)) {
            if (tmpNode.getNodeType() == Node.ELEMENT_NODE) {
                childEls.add((Element) tmpNode);
            }
        }
        return childEls;
    }

    private static List<Node> getWhitespaceNodes(Element element) {
        List<Node> nodes = new ArrayList<Node>();
        for (Node node : getNodesAsList(element)) {
            if (node.getNodeType() == Node.TEXT_NODE && node.getNodeValue().trim().length() == 0) {
                nodes.add(node);
            }
        }
        return nodes;
    }

    private static void removeWhitespaceInMixedContentElements(Element element) {
        List<Element> childEls = getChildElements(element);
        if (childEls.size() > 0) {
            for (Node node : getWhitespaceNodes(element)) {
                element.removeChild(node);
            }
            for (Element childEl : childEls) {
                removeWhitespaceInMixedContentElements(childEl);
            }
        }
    }

    /**
     * Prettify a given XML file
     */
    public static void prettifyXMLFile(String filePath) throws IOException {
        String prettyXML = prettifyXML(FileUtils.readFileToString(new File(filePath)));
        FileUtils.writeStringToFile(new File(filePath), prettyXML);
    }

    /**
     * Encode the given string with base64 encoding.
     */
    public static String encodeBase64(String value) {
        try {
            return new String(Base64.encodeBase64(value.getBytes(DBConstants.DEFAULT_CHAR_SET_TYPE)),
                    DBConstants.DEFAULT_CHAR_SET_TYPE);
        } catch (UnsupportedEncodingException ueo) {
            throw new RuntimeException(ueo);
        }
    }

    /**
     * Creates an AxisFault.
     */
    public static AxisFault createAxisFault(Exception e) {
        AxisFault fault;
        Throwable cause = e.getCause();
        if (cause != null) {
            fault = new AxisFault(e.getMessage(), cause);
        } else {
            fault = new AxisFault(e.getMessage());
        }
        fault.setDetail(DataServiceFault.extractFaultMessage(e));
        fault.setFaultCode(new QName(DBConstants.WSO2_DS_NAMESPACE, DataServiceFault.extractFaultCode(e)));
        return fault;
    }

    /**
     * Creates OMElement using error details.
     */
    public static OMElement createDSFaultOM(String msg) {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMElement ele = fac.createOMElement(new QName(DBConstants.WSO2_DS_NAMESPACE, DBConstants.DS_FAULT_ELEMENT));
        ele.setText(msg);
        return ele;
    }

    public static String evaluateString(String source, ExternalParamCollection params) throws DataServiceFault {
        StringBuilder builder = new StringBuilder();
        /* http://www.product.fake/cd/{productCode} */
        int leftBracketIndex = source.indexOf('{', 0);
        int rightBracketIndex = source.indexOf('}', leftBracketIndex);
        if (leftBracketIndex == -1 || rightBracketIndex == -1) {
            throw new DataServiceFault("The source string: " + source + " is not parameterized.");
        }
        String paramName = source.substring(leftBracketIndex + 1, rightBracketIndex);
        /* workaround for different character case issues in column names */
        paramName = paramName.toLowerCase();
        ExternalParam exParam = params.getParam(paramName);
        if (exParam == null) {
            throw new DataServiceFault(
                    "The parameter: " + paramName + " cannot be found for the source string: " + source);
        }
        String paramValue = exParam.getValue().getValueAsString();
        builder.append(source.subSequence(0, leftBracketIndex));
        builder.append(paramValue);
        builder.append(source.substring(rightBracketIndex + 1));
        return builder.toString();
    }

    /**
     * Schedules a given task for one-time execution using the executer framework.
     *
     * @param task  The task to be executed
     * @param delay The delay in milliseconds for the task to be executed
     */
    public static void scheduleTask(Runnable task, long delay) {
        globalExecutorService.schedule(task, delay, TimeUnit.MILLISECONDS);
    }

    /**
     * Check the given text is empty or not.
     *
     * @param text The text to be checked
     * @return true if text is null or trimmed text length is empty, or else false
     */
    public static boolean isEmptyString(String text) {
        if (text != null && text.trim().length() > 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Check the given password is encrypted or not, if its encrypted resolve the password.
     *
     * @param dataService Data service object
     * @param password    Password before resolving
     * @return Resolved password
     */
    public static String resolvePasswordValue(DataService dataService, String password) {
        SecretResolver secretResolver = dataService.getSecretResolver();
        if (secretResolver != null && secretResolver.isTokenProtected(password)) {
            return secretResolver.resolve(password);
        } else {
            return password;
        }
    }

    /**
     * Returns the best effort way of finding the current tenant id,
     * even if this is not in a current message request, i.e. deploying services.
     * Assumption: when tenants other than the super tenant is activated,
     * the registry service must be available. So, the service deployment and accessing the registry,
     * will happen in the same thread, without the callbacks being used.
     *
     * @return The tenant id
     */
    public static int getCurrentTenantId() {
        try {
            int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
            if (tenantId == -1) {
                throw new RuntimeException("Tenant id cannot be -1");
            }
            return tenantId;
        } catch (NoClassDefFoundError e) { // Workaround for Unit Test failure 
            return MultitenantConstants.SUPER_TENANT_ID;
        } catch (ExceptionInInitializerError e) {
            return MultitenantConstants.SUPER_TENANT_ID;
        }

    }

    /**
     * Returns the simple schema type from the type name,
     */
    public static QName getSimpleSchemaTypeName(TypeTable typeTable, String typeName) {
        if (typeName.equals("java.net.URI")) {
            return new QName(DBConstants.XSD_NAMESPACE, "anyURI");
        }
        if (typeName.equals("java.sql.Struct")) {
            return new QName(DBConstants.XSD_NAMESPACE, "anyType");
        }
        return typeTable.getSimpleSchemaTypeName(typeName);
    }

    @SuppressWarnings("unchecked")
    public static Map<String, String> extractProperties(OMElement propsParentEl) {
        Map<String, String> properties = new HashMap<String, String>();
        OMElement propEl = null;
        Iterator<OMElement> itr = propsParentEl.getChildrenWithName(new QName(DBSFields.PROPERTY));
        String text;
        while (itr.hasNext()) {
            propEl = itr.next();
            if (propEl.getChildElements().hasNext()) {
                text = propEl.toString();
            } else {
                text = propEl.getText();
            }
            if (text != null && !text.equals("")) {
                properties.put(propEl.getAttributeValue(new QName(DBSFields.NAME)), text);
            }
        }
        return properties;
    }

    /**
     * Get the container managed transaction manager; if a JNDI name is given,
     * that name is looked for a TransactionManager object, if not, the standard JNDI
     * names are checked.
     *
     * @param txManagerJNDIName The user given JNDI name of the TransactionManager
     * @return The TransactionManager object
     * @throws DataServiceFault
     */
    public static TransactionManager getContainerTransactionManager(String txManagerJNDIName)
            throws DataServiceFault {
        TransactionManager txManager = null;
        if (txManagerJNDIName != null) {
            try {
                txManager = InitialContext.doLookup(txManagerJNDIName);
            } catch (Exception e) {
                throw new DataServiceFault(e,
                        "Cannot find TransactionManager with the given JNDI name '" + txManagerJNDIName + "'");
            }
        }
        /* get the transaction manager from the well known JNDI names from the cache */
        txManager = DBDeployer.getCachedTransactionManager();
        return txManager;
    }

    /**
     * Creates a new OMElement from the given element and build it and return.
     *
     * @param result The object to be cloned and built
     * @return The new cloned and built OMElement
     */
    public static OMElement cloneAndReturnBuiltElement(OMElement result) {
        StAXOMBuilder builder = new StAXOMBuilder(result.getXMLStreamReaderWithoutCaching());
        result = builder.getDocumentElement();
        result.build();
        return result;
    }

    /**
     * This util method is used to retrieve the string tokens resides in a particular
     * udt parameter.
     *
     * @param param Name of the parameter
     * @return
     */
    public static Queue<String> getTokens(String param) {
        boolean isString = false;
        Queue<String> tokens = new LinkedBlockingQueue<String>();
        char[] chars = param.toCharArray();
        StringBuilder columnName = new StringBuilder();
        for (int i = 0; i < chars.length; i++) {
            Character c = chars[i];
            if (!".".equals(c.toString()) && !"[".equals(c.toString()) && !"]".equals(c.toString())) {
                isString = true;
                columnName.append(c.toString());
                if (i == chars.length - 1) {
                    tokens.add(columnName.toString());
                }
            } else {
                if (isString) {
                    tokens.add(columnName.toString());
                    columnName = new StringBuilder();
                    isString = false;
                }
                tokens.add(c.toString());
            }

        }
        return tokens;
    }

    /**
     * This method is used to embed syntaxes associated with UDT attribute notations to
     * a queue of string tokens extracted from a UDT parameter.
     *
     * @param tokens      Queue of string tokens
     * @param syntaxQueue Syntax embedded tokens
     * @param isIndex     Flag to determine whether a particular string token is an inidex
     *                    or a column name
     */
    public static void getSyntaxEmbeddedQueue(Queue<String> tokens, Queue<String> syntaxQueue, boolean isIndex) {
        if (!tokens.isEmpty()) {
            if ("[".equals(tokens.peek())) {
                isIndex = true;
                tokens.poll();
                syntaxQueue.add("INEDX_START");
                syntaxQueue.add(tokens.poll());
            } else if ("]".equals(tokens.peek())) {
                isIndex = false;
                tokens.poll();
                syntaxQueue.add("INDEX_END");
            } else if (".".equals(tokens.peek())) {
                tokens.poll();
                syntaxQueue.add("DOT");
                syntaxQueue.add("COLUMN");
                syntaxQueue.add(tokens.poll());
            } else {
                if (isIndex) {
                    syntaxQueue.add("INDEX");
                    syntaxQueue.add(tokens.poll());
                } else {
                    syntaxQueue.add("COLUMN");
                    syntaxQueue.add(tokens.poll());
                }
            }
            getSyntaxEmbeddedQueue(tokens, syntaxQueue, isIndex);
        }
    }

    public static String getConnectionURL4XADataSource(Config config) throws XMLStreamException {
        String connectionURL = null;
        String connectionProperty = config.getProperty(DBConstants.RDBMS.DATASOURCE_PROPS);
        if (connectionProperty != null) {
            OMElement payload = AXIOMUtil.stringToOM(connectionProperty);
            Map<String, String> properties = extractProperties(payload);
            Collection<String> propValues = properties.values();
            for (String propValue : propValues) {
                if (propValue.startsWith("jdbc:")) {
                    connectionURL = propValue;
                    break;
                }
            }
        }
        return connectionURL;
    }

    public static boolean isUDT(ParamValue paramValue) {
        return paramValue != null && (paramValue.getValueType() == ParamValue.PARAM_VALUE_UDT);
    }

    public static boolean isSQLArray(ParamValue paramValue) {
        return paramValue != null && (paramValue.getValueType() == ParamValue.PARAM_VALUE_ARRAY);
    }

    /**
     * Util method to parse index string and produce the list of nested indices.
     *
     * @param indexString Index String.
     * @return The list of nested indices.
     * @throws DataServiceFault DataServiceFault.
     */
    public static List<Integer> getNestedIndices(String indexString) throws DataServiceFault {
        List<Integer> indices = new ArrayList<Integer>();
        String[] temp = indexString.split("\\[");
        for (String s : temp) {
            if (!"".equals(s)) {
                try {
                    indices.add(Integer.parseInt(s.substring(0, s.indexOf("]"))));
                } catch (NumberFormatException e) {
                    throw new DataServiceFault("Unable to determine nested indices. Incompatible "
                            + "value specified for the attribute index");
                }
            }
        }
        return indices;
    }

    /**
     * Processes a particular SQL Array object and interprets its value as a ParamValue object.
     *
     * @param sqlArray   SQL Array element.
     * @param paramValue Parameter value object initialized to contain an array of ParamValues.
     * @return ParamValue object representing the SQL Array.
     * @throws SQLException Throws an SQL Exception if the result set is not accessible.
     */
    public static ParamValue processSQLArray(Array sqlArray, ParamValue paramValue) throws SQLException {
        ResultSet rs = sqlArray.getResultSet();
        while (rs.next()) {
            Object arrayEl = rs.getObject(2);
            if (arrayEl instanceof Struct) {
                paramValue.getArrayValue().add(new ParamValue((Struct) arrayEl));
            } else if (arrayEl instanceof Array) {
                paramValue.getArrayValue()
                        .add(processSQLArray((Array) arrayEl, new ParamValue(ParamValue.PARAM_VALUE_ARRAY)));
            } else {
                paramValue.getArrayValue().add(new ParamValue(String.valueOf(arrayEl)));
            }
        }
        rs.close();
        return paramValue;
    }

    /**
     * Extracts the UDT column name from a given parameter name
     *
     * @param param User specified parameter name
     * @return UDT column name
     */
    public static String extractUDTObjectName(String param) {
        Matcher m = udtPattern.matcher(param);
        if (m.find()) {
            String tmp = m.group();
            Pattern patternToGetIndex = Pattern.compile("\\[\\d+\\]");
            Matcher matcherToGetIndex = patternToGetIndex.matcher(tmp);
            if (matcherToGetIndex.find()) {
                int lengthOfIndexPart = matcherToGetIndex.group().length();
                return tmp.substring(0, tmp.length() - lengthOfIndexPart).trim();
            }
        }
        return null;
    }

    public static synchronized String loadFromSecureVault(String alias) {
        if (secretResolver == null) {
            secretResolver = SecretResolverFactory.create((OMElement) null, false);
            secretResolver
                    .init(DataServicesDSComponent.getSecretCallbackHandlerService().getSecretCallbackHandler());
        }
        return secretResolver.resolve(alias);
    }

    public static OMElement wrapBoxCarringResponse(OMElement result) {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMElement wrapperElement = fac.createOMElement(
                new QName(DBConstants.WSO2_DS_NAMESPACE, DBConstants.DATA_SERVICE_RESPONSE_WRAPPER_ELEMENT));
        if (result != null) {
            wrapperElement.addChild(result);
        }
        OMDocument doc = fac.createOMDocument();
        doc.addChild(wrapperElement);
        return doc.getOMDocumentElement();
    }

    public static void populateStandardCustomDSProps(Map<String, String> dsProps, DataService dataService,
            Config config) {
        String dsInfo = dataService.getTenantId() + "#" + dataService.getName() + "#" + config.getConfigId();
        dsProps.put(DBConstants.CustomDataSource.DATASOURCE_ID, UUID
                .nameUUIDFromBytes(dsInfo.getBytes(Charset.forName(DBConstants.DEFAULT_CHAR_SET_TYPE))).toString());
        if (log.isDebugEnabled()) {
            log.debug("Custom Inline Data Source; ID: " + dsInfo + " UUID:"
                    + dsProps.get(DBConstants.CustomDataSource.DATASOURCE_ID));
        }
    }

    /**
     * Convert the input parameter values to its types object values.
     * @param params The input params
     * @return The typed object values
     * @throws DataServiceFault
     */
    public static Object[] convertInputParamValues(List<InternalParam> params) throws DataServiceFault {
        Object[] result = new Object[params.size()];
        InternalParam param;
        for (int i = 0; i < result.length; i++) {
            param = params.get(i);
            try {
                result[i] = convertInputParamValue(param.getValue().getValueAsString(), param.getSqlType());
            } catch (DataServiceFault dataServiceFault) {
                throw new DataServiceFault(dataServiceFault, "Error processing parameter - " + param.getName()
                        + ", Error - " + dataServiceFault.getMessage());
            }
        }
        return result;
    }

    /**
     * Convert the string input param value to its typed object value.
     * @param value The string value of the input param
     * @param type The type of the input value, defined at DBConstants.DataTypes.
     * @return The typed object value of the input param 
     */
    public static Object convertInputParamValue(String value, String type) throws DataServiceFault {
        try {
            if (DBConstants.DataTypes.INTEGER.equals(type)) {
                return Integer.parseInt(value);
            } else if (DBConstants.DataTypes.LONG.equals(type)) {
                return Long.parseLong(value);
            } else if (DBConstants.DataTypes.FLOAT.equals(type)) {
                return Float.parseFloat(value);
            } else if (DBConstants.DataTypes.DOUBLE.equals(type)) {
                return Double.parseDouble(value);
            } else if (DBConstants.DataTypes.BOOLEAN.equals(type)) {
                return Boolean.parseBoolean(value);
            } else if (DBConstants.DataTypes.DATE.equals(type)) {
                return new java.util.Date(DBUtils.getDate(value).getTime());
            } else if (DBConstants.DataTypes.TIME.equals(type)) {
                Calendar cal = Calendar.getInstance();
                cal.setTimeInMillis(DBUtils.getTime(value).getTime());
                return cal;
            } else if (DBConstants.DataTypes.TIMESTAMP.equals(type)) {
                Calendar cal = Calendar.getInstance();
                cal.setTimeInMillis(DBUtils.getTimestamp(value).getTime());
                return cal;
            } else {
                return value;
            }
        } catch (Exception e) {
            throw new DataServiceFault(e);
        }
    }

    public static String getTenantDomainFromId(int tid) {
        try {
            return DataServicesDSComponent.getRealmService().getTenantManager().getTenant(tid).getDomain();
        } catch (UserStoreException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Get roles using the AuthorizationProvider using the config given.
     *
     * @param authProviderConfig xml config.
     * @return role array
     * @throws DataServiceFault
     */
    public static String[] getAllRolesUsingAuthorizationProvider(String authProviderConfig)
            throws DataServiceFault {
        try {
            AuthorizationProvider authorizationProvider;
            if (authProviderConfig != null && !authProviderConfig.isEmpty()) {
                StAXOMBuilder builder = new StAXOMBuilder(
                        new ByteArrayInputStream(authProviderConfig.getBytes(StandardCharsets.UTF_8)));
                OMElement documentElement = builder.getDocumentElement();
                authorizationProvider = generateAuthProviderFromXMLOMElement(documentElement);
            } else {
                authorizationProvider = new UserStoreAuthorizationProvider();
            }
            return authorizationProvider.getAllRoles();
        } catch (XMLStreamException e) {
            throw new DataServiceFault(e,
                    "Error reading XML file data - " + authProviderConfig + " Error - " + e.getMessage());
        }
    }

    /**
     * Helper method to generate Authorization provider using config element
     *
     * @param authorizationProviderElement config element
     * @return authorizationProvider
     * @throws DataServiceFault
     */
    public static AuthorizationProvider generateAuthProviderFromXMLOMElement(OMElement authorizationProviderElement)
            throws DataServiceFault {
        Class roleRetrieverClass = null;
        String roleRetrieverClassName = null;
        try {
            AuthorizationProvider authorizationProvider;
            roleRetrieverClassName = authorizationProviderElement
                    .getAttributeValue(new QName(DBConstants.AuthorizationProviderConfig.ATTRIBUTE_NAME_CLASS));
            //initialize the roleRetrieverElement
            roleRetrieverClass = Class.forName(roleRetrieverClassName);
            authorizationProvider = (AuthorizationProvider) roleRetrieverClass.newInstance();

            //read the properties in the authenticator element and set them in the authenticator.
            Iterator<OMElement> propertyElements = authorizationProviderElement
                    .getChildrenWithName(new QName(DBSFields.PROPERTY));
            Map<String, String> properties = new HashMap<String, String>();
            if (propertyElements != null) {
                while (propertyElements.hasNext()) {
                    OMElement propertyElement = propertyElements.next();
                    String attributeName = propertyElement.getAttributeValue(new QName(DBSFields.NAME));
                    String attributeValue = propertyElement.getText();
                    properties.put(attributeName, attributeValue);
                }
            }
            authorizationProvider.init(properties);
            return authorizationProvider;
        } catch (ClassNotFoundException e) {
            throw new DataServiceFault(e, "Specified class - " + roleRetrieverClassName
                    + " class cannot be found, Error - " + e.getMessage());
        } catch (InstantiationException e) {
            throw new DataServiceFault(e,
                    "Initialisation Error for class - " + roleRetrieverClass + " Error - " + e.getMessage());
        } catch (IllegalAccessException e) {
            throw new DataServiceFault(e,
                    "Illegal access attempt for class - " + roleRetrieverClass + " Error - " + e.getMessage());
        }
    }

}