org.wso2.carbon.datasource.core.utils.RDBMSDataSourceUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.datasource.core.utils.RDBMSDataSourceUtils.java

Source

/**
 *  Copyright (c) 2012, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.wso2.carbon.datasource.core.utils;

import org.apache.commons.io.IOUtils;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.wso2.carbon.datasource.api.DataSourceException;
import org.wso2.carbon.datasource.core.rdbms.RDBMSConfiguration;
import org.wso2.carbon.datasource.core.rdbms.RDBMSDataSourceConstants;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

/**
 * Utility class for RDBMS data sources.
 */
public class RDBMSDataSourceUtils {

    public static void assignBeanProps(Object obj, Map<String, Object> props) throws DataSourceException {
        Method method;
        for (Entry<String, Object> prop : props.entrySet()) {
            method = getSetterMethod(obj, getSetterMethodNameFromPropName(prop.getKey()));
            if (method == null) {
                throw new DataSourceException("Setter method for property '" + prop.getKey() + "' cannot be found");
            }
            try {
                method.invoke(obj, convertStringToGivenType(prop.getValue(), method.getParameterTypes()[0]));
            } catch (Exception e) {
                throw new DataSourceException("Cannot invoke setter for property '" + prop.getKey() + "'", e);
            }
        }
    }

    public static String replaceSystemVariablesInXml(String xmlConfiguration) throws Exception {
        InputStream in = replaceSystemVariablesInXml(new ByteArrayInputStream(xmlConfiguration.getBytes()));
        try {
            xmlConfiguration = IOUtils.toString(in);
        } catch (IOException e) {
            throw new Exception("Error in converting InputStream to String");
        }
        return xmlConfiguration;
    }

    /**
     *
     * @param xmlConfiguration InputStream that carries xml configuration
     * @return returns a InputStream that has evaluated system variables in input
     */
    public static InputStream replaceSystemVariablesInXml(InputStream xmlConfiguration) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder;
        Document doc;
        try {
            builder = factory.newDocumentBuilder();
            doc = builder.parse(xmlConfiguration);
        } catch (Exception e) {
            throw new Exception("Error in building Document", e);
        }
        NodeList nodeList = null;
        if (doc != null) {
            nodeList = doc.getElementsByTagName("*");
        }
        if (nodeList != null) {
            for (int i = 0; i < nodeList.getLength(); i++) {
                resolveLeafNodeValue(nodeList.item(i));
            }
        }
        return toInputStream(doc);
    }

    public static InputStream toInputStream(Document doc) throws Exception {
        InputStream in;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Source xmlSource = new DOMSource(doc);
            Result result = new StreamResult(outputStream);
            TransformerFactory.newInstance().newTransformer().transform(xmlSource, result);
            in = new ByteArrayInputStream(outputStream.toByteArray());
        } catch (TransformerException e) {
            throw new Exception("Error in transforming DOM to InputStream", e);
        }
        return in;
    }

    public static void resolveLeafNodeValue(Node node) {
        if (node != null) {
            Element element = (Element) node;
            NodeList childNodeList = element.getChildNodes();
            for (int j = 0; j < childNodeList.getLength(); j++) {
                Node chileNode = childNodeList.item(j);
                if (!chileNode.hasChildNodes()) {
                    String nodeValue = resolveSystemProperty(chileNode.getTextContent());
                    childNodeList.item(j).setTextContent(nodeValue);
                } else {
                    resolveLeafNodeValue(chileNode);
                }
            }
        }
    }

    public static String resolveSystemProperty(String text) {
        int indexOfStartingChars = -1;
        int indexOfClosingBrace;

        // The following condition deals with properties.
        // Properties are specified as ${system.property},
        // and are assumed to be System properties
        while (indexOfStartingChars < text.indexOf("${") && (indexOfStartingChars = text.indexOf("${")) != -1
                && (indexOfClosingBrace = text.indexOf('}')) != -1) { // Is a
            // property
            // used?
            String sysProp = text.substring(indexOfStartingChars + 2, indexOfClosingBrace);
            String propValue = System.getProperty(sysProp);
            if (propValue != null) {
                text = text.substring(0, indexOfStartingChars) + propValue
                        + text.substring(indexOfClosingBrace + 1);
            }
            if (sysProp.equals("carbon.home") && propValue != null && propValue.equals(".")) {

                text = new File(".").getAbsolutePath() + File.separator + text;

            }
        }
        return text;
    }

    private static Object convertStringToGivenType(Object value, Class<?> type) throws DataSourceException {
        if (String.class.equals(type) || Properties.class.equals(type)) {
            return value;
        }
        if (boolean.class.equals(type) || Boolean.class.equals(type)) {
            return Boolean.parseBoolean(String.valueOf(value));
        }
        if (int.class.equals(type) || Integer.class.equals(type)) {
            return Integer.parseInt(String.valueOf(value));
        }
        if (short.class.equals(type) || Short.class.equals(type)) {
            return Short.parseShort(String.valueOf(value));
        }
        if (byte.class.equals(type) || Byte.class.equals(type)) {
            return Byte.parseByte(String.valueOf(value));
        }
        if (long.class.equals(type) || Long.class.equals(type)) {
            return Long.parseLong(String.valueOf(value));
        }
        if (float.class.equals(type) || Float.class.equals(type)) {
            return Float.parseFloat(String.valueOf(value));
        }
        if (double.class.equals(type) || Double.class.equals(type)) {
            return Double.parseDouble(String.valueOf(value));
        }
        throw new DataSourceException("Cannot convert value: '" + value + "' to type: '" + type.getName() + "'");
    }

    public static boolean isEmptyString(String text) {
        if (text != null && text.trim().length() > 0) {
            return false;
        } else {
            return true;
        }
    }

    private static String getSetterMethodNameFromPropName(String propName) throws RuntimeException {
        if (isEmptyString(propName)) {
            throw new RuntimeException("Invalid property name");
        }
        return "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
    }

    private static Method getSetterMethod(Object obj, String name) {
        Method[] methods = obj.getClass().getMethods();
        for (Method method : methods) {
            if (method.getName().equals(name) && method.getReturnType().equals(void.class)
                    && method.getParameterTypes().length == 1) {
                return method;
            }
        }
        return null;
    }

    public static Map<String, String> extractPrimitiveFieldNameValuePairs(Object object)
            throws DataSourceException {
        Map<String, String> nameValueMap = new HashMap<String, String>();
        Method methods[] = object.getClass().getMethods();
        for (Method method : methods) {
            if (isMethodMatched(method)) {
                String FieldName = getFieldNameFromMethodName(method.getName());
                String result = null;
                try {
                    if (method.invoke(object) != null) {
                        result = method.invoke(object).toString();
                        nameValueMap.put(FieldName, result);
                    }
                } catch (Exception e) {
                    throw new DataSourceException("Error in retrieving " + FieldName + " value from the object :"
                            + object.getClass() + e.getMessage(), e);
                }
            }
        }
        return nameValueMap;
    }

    private static String getFieldNameFromMethodName(String name) throws DataSourceException {
        String prefixGet = "get";
        String prefixIs = "is";
        String firstLetter = null;

        if (name.startsWith(prefixGet)) {
            firstLetter = name.substring(3, 4);
            name = name.substring(4);
        } else if (name.startsWith(prefixIs)) {
            firstLetter = name.substring(2, 3);
            name = name.substring(3);
        } else {
            throw new DataSourceException("Error in retrieving attribute name from method : " + name);
        }
        firstLetter = firstLetter.toLowerCase();
        return firstLetter.concat(name);
    }

    private static boolean isMethodMatched(Method method) {
        String returnType = method.getReturnType().getSimpleName();
        String methodName = method.getName();

        if (!Modifier.isPublic(method.getModifiers())) {
            return false;
        }
        if (returnType.equals("void")) {
            return false;
        }
        if (!(methodName.startsWith("get") || (methodName.startsWith("is")
                && (returnType.equals("Boolean") || returnType.equals("boolean"))))) {
            return false;
        }
        if (!(method.getReturnType().isPrimitive()
                || Arrays.asList(RDBMSDataSourceConstants.CLASS_RETURN_TYPES).contains(returnType))) {
            return false;
        }
        return true;
    }

    public static PoolConfiguration createPoolConfiguration(RDBMSConfiguration config) throws DataSourceException {
        PoolProperties props = new PoolProperties();
        props.setUrl(config.getUrl());
        if (config.isDefaultAutoCommit() != null) {
            props.setDefaultAutoCommit(config.isDefaultAutoCommit());
        }
        if (config.isDefaultReadOnly() != null) {
            props.setDefaultReadOnly(config.isDefaultReadOnly());
        }
        String isolationLevelString = config.getDefaultTransactionIsolation();
        if (isolationLevelString != null) {
            if (RDBMSDataSourceConstants.TX_ISOLATION_LEVELS.NONE.equals(isolationLevelString)) {
                props.setDefaultTransactionIsolation(Connection.TRANSACTION_NONE);
            } else if (RDBMSDataSourceConstants.TX_ISOLATION_LEVELS.READ_UNCOMMITTED.equals(isolationLevelString)) {
                props.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
            } else if (RDBMSDataSourceConstants.TX_ISOLATION_LEVELS.READ_COMMITTED.equals(isolationLevelString)) {
                props.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            } else if (RDBMSDataSourceConstants.TX_ISOLATION_LEVELS.REPEATABLE_READ.equals(isolationLevelString)) {
                props.setDefaultTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            } else if (RDBMSDataSourceConstants.TX_ISOLATION_LEVELS.SERIALIZABLE.equals(isolationLevelString)) {
                props.setDefaultTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
            }
        }
        props.setDefaultCatalog(config.getDefaultCatalog());
        props.setDriverClassName(config.getDriverClassName());
        props.setUsername(config.getUsername());
        props.setPassword(config.getPassword());
        if (config.getMaxActive() != null) {
            props.setMaxActive(config.getMaxActive());
        }
        if (config.getMaxIdle() != null) {
            props.setMaxIdle(config.getMaxIdle());
        }
        if (config.getMinIdle() != null) {
            props.setMinIdle(config.getMinIdle());
        }
        if (config.getInitialSize() != null) {
            props.setInitialSize(config.getInitialSize());
        }
        if (config.getMaxWait() != null) {
            props.setMaxWait(config.getMaxWait());
        }
        if (config.isTestOnBorrow() != null) {
            props.setTestOnBorrow(config.isTestOnBorrow());
        }
        if (config.isTestOnReturn() != null) {
            props.setTestOnReturn(config.isTestOnReturn());
        }
        if (config.isTestWhileIdle() != null) {
            props.setTestWhileIdle(config.isTestWhileIdle());
        }
        props.setValidationQuery(config.getValidationQuery());
        props.setValidatorClassName(config.getValidatorClassName());
        if (config.getTimeBetweenEvictionRunsMillis() != null) {
            props.setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis());
        }
        if (config.getNumTestsPerEvictionRun() != null) {
            props.setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun());
        }
        if (config.getMinEvictableIdleTimeMillis() != null) {
            props.setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis());
        }
        if (config.isAccessToUnderlyingConnectionAllowed() != null) {
            props.setAccessToUnderlyingConnectionAllowed(config.isAccessToUnderlyingConnectionAllowed());
        }
        if (config.isRemoveAbandoned() != null) {
            props.setRemoveAbandoned(config.isRemoveAbandoned());
        }
        if (config.getRemoveAbandonedTimeout() != null) {
            props.setRemoveAbandonedTimeout(config.getRemoveAbandonedTimeout());
        }
        if (config.isLogAbandoned() != null) {
            props.setLogAbandoned(config.isLogAbandoned());
        }
        props.setConnectionProperties(config.getConnectionProperties());
        props.setInitSQL(config.getInitSQL());
        props.setJdbcInterceptors(config.getJdbcInterceptors());
        if (config.getValidationInterval() != null) {
            props.setValidationInterval(config.getValidationInterval());
        }
        if (config.isJmxEnabled() != null) {
            props.setJmxEnabled(config.isJmxEnabled());
        }
        if (config.isFairQueue() != null) {
            props.setFairQueue(config.isFairQueue());
        }
        if (config.getAbandonWhenPercentageFull() != null) {
            props.setAbandonWhenPercentageFull(config.getAbandonWhenPercentageFull());
        }
        if (config.getMaxAge() != null) {
            props.setMaxAge(config.getMaxAge());
        }
        if (config.isUseEquals() != null) {
            props.setUseEquals(config.isUseEquals());
        }
        if (config.getSuspectTimeout() != null) {
            props.setSuspectTimeout(config.getSuspectTimeout());
        }
        if (config.isAlternateUsernameAllowed() != null) {
            props.setAlternateUsernameAllowed(config.isAlternateUsernameAllowed());
        }
        if (config.getDataSourceClassName() != null) {
            handleExternalDataSource(props, config);
        }
        return props;
    }

    private static Map<String, Object> dataSourcePropsToMap(List<RDBMSConfiguration.DataSourceProperty> dsProps) {
        Map<String, Object> result = new HashMap<String, Object>();
        if (dsProps != null) {
            String[] prop;
            Map<String, Properties> tmpPropertiesObjects = new HashMap<String, Properties>();
            Properties tmpProp;
            for (RDBMSConfiguration.DataSourceProperty dsProp : dsProps) {
                prop = dsProp.getName().split("\\.");
                if (prop.length > 1) {
                    if (!tmpPropertiesObjects.containsKey(prop[0])) {
                        tmpProp = new Properties();
                        tmpPropertiesObjects.put(prop[0], tmpProp);
                    } else {
                        tmpProp = tmpPropertiesObjects.get(prop[0]);
                    }
                    tmpProp.setProperty(prop[1], dsProp.getValue());
                } else {
                    result.put(dsProp.getName(), dsProp.getValue());
                }
            }
            result.putAll(tmpPropertiesObjects);

        }
        return result;
    }

    private static void handleExternalDataSource(PoolProperties poolProps, RDBMSConfiguration config)
            throws DataSourceException {
        String dsClassName = config.getDataSourceClassName();
        try {
            Object extDataSource = Class.forName(dsClassName).newInstance();
            RDBMSDataSourceUtils.assignBeanProps(extDataSource, dataSourcePropsToMap(config.getDataSourceProps()));
            poolProps.setDataSource(extDataSource);
        } catch (Exception e) {
            throw new DataSourceException("Error in creating external data source: " + e.getMessage(), e);
        }
    }

}