org.gbif.ipt.config.JdbcSupport.java Source code

Java tutorial

Introduction

Here is the source code for org.gbif.ipt.config.JdbcSupport.java

Source

/***************************************************************************
 * Copyright 2010 Global Biodiversity Information Facility Secretariat
 * 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.gbif.ipt.config;

import org.gbif.ipt.model.SqlSource;

import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

public class JdbcSupport {

    public class JdbcInfo {

        protected final String name;
        protected final String title;
        protected final String driver;
        protected final String url;
        protected final LIMIT_TYPE limitType;

        protected JdbcInfo(String name, String title, String driver, String url, LIMIT_TYPE limitType) {
            this.name = name;
            this.title = title;
            this.driver = driver;
            this.url = url;
            this.limitType = limitType;
        }

        public String addLimit(String sql, int limit) {
            if (sql == null) {
                return null;
            }
            // replace select
            Matcher m = null;
            if (LIMIT_TYPE.LIMIT == limitType) {
                m = LIMIT.matcher(sql);
                // does LIMIT already exist?
                if (m.find()) {
                    sql = m.replaceAll(" LIMIT " + limit);
                } else {
                    // lets append it then
                    if (sql.endsWith(";")) {
                        sql = sql.substring(0, sql.length() - 1);
                    }
                    sql += " LIMIT " + limit;
                }

            } else if (LIMIT_TYPE.TOP == limitType) {
                m = SELECT.matcher(sql);
                if (m.find()) {
                    // does TOP already exist?
                    Matcher m2 = TOP.matcher(sql);
                    if (m2.find()) {
                        sql = m2.replaceFirst(" TOP " + limit);
                    } else {
                        sql = m.replaceAll(" SELECT TOP " + limit + " ");
                    }
                } /*
                   * else {
                   * // TODO: there MUST be a select...should we throw an error?
                   * }
                   */

            } else if (LIMIT_TYPE.ROWNUM == limitType) {
                m = WHERE.matcher(sql);
                if (m.find()) {
                    // does rownum already exist?
                    Matcher m2 = ROWNUM.matcher(sql);
                    if (m2.find()) {
                        sql = m2.replaceAll(" rownum <= " + limit + " ");
                    } else {
                        sql = m.replaceAll(" WHERE rownum <= " + limit + " AND ");
                    }
                } else {
                    // lets append it then
                    // TODO: lookout for order or group bys
                    sql += " WHERE rownum <= " + limit;
                }
            }

            return sql;
        }

        public void enableLargeResultSet(Statement stmnt) throws SQLException {
            // force resultsset streaming for MYSQL only
            if (this.driver.startsWith("com.mysql")) {
                // see http://benjchristensen.com/2008/05/27/mysql-jdbc-memory-usage-on-large-resultset/
                stmnt.setFetchSize(Integer.MIN_VALUE);
            } else {
                stmnt.setFetchSize(1000);
            }
        }

        public String getDriver() {
            return driver;
        }

        public String getJdbcUrl(SqlSource source) {
            return this.url.replace("{host}", source.getHost()).replace("{database}", source.getDatabase());
        }

        public String getJdbcUrl(String host, String database) {
            return this.url.replace("{host}", host).replace("{database}", database);
        }

        public String getName() {
            return name;
        }

        public String getTitle() {
            return title;
        }

        public String getUrl() {
            return url;
        }

    }

    protected enum LIMIT_TYPE {
        LIMIT, TOP, ROWNUM
    }

    private static final Pattern SELECT = Pattern.compile("(^| )select ", Pattern.CASE_INSENSITIVE);
    private static final Pattern TOP = Pattern.compile(" top \\d+", Pattern.CASE_INSENSITIVE);
    private static final Pattern WHERE = Pattern.compile(" where ", Pattern.CASE_INSENSITIVE);
    private static final Pattern ROWNUM = Pattern.compile(" rownum[ <>=]+\\d+", Pattern.CASE_INSENSITIVE);
    private static final Pattern LIMIT = Pattern.compile(" limit \\d+", Pattern.CASE_INSENSITIVE);

    public static final String CLASSPATH_PROPFILE = "jdbc.properties";

    private final Map<String, JdbcInfo> driver = new TreeMap<String, JdbcInfo>();

    public JdbcInfo get(String name) {
        return driver.get(name.toLowerCase());
    }

    public List<String> list() {
        List<String> driverNames = new ArrayList(driver.keySet());
        Collections.sort(driverNames);
        return driverNames;
    }

    public Map<String, String> optionMap() {
        Map<String, String> map = new TreeMap<String, String>();
        for (JdbcInfo j : options()) {
            map.put(j.getName(), j.getTitle());
        }
        return map;
    }

    /**
     * @return map of name to jdbc info suitable for html selects
     */
    public Collection<JdbcInfo> options() {
        return driver.values();
    }

    protected int setProperties(Properties props) {
        driver.clear();
        // get distinct list of driver names
        Set<String> names = new HashSet<String>();
        for (Enumeration propertyNames = props.propertyNames(); propertyNames.hasMoreElements();) {
            String name = StringUtils.substringBefore((String) propertyNames.nextElement(), ".");
            names.add(name);
        }
        // create a jdbc info object for each
        for (String name : names) {
            name = name.toLowerCase();
            LIMIT_TYPE lt = LIMIT_TYPE.valueOf(props.getProperty(name + ".limitType"));
            JdbcInfo info = new JdbcInfo(name, props.getProperty(name + ".title"),
                    props.getProperty(name + ".driver"), props.getProperty(name + ".url"), lt);
            driver.put(name, info);
        }
        return driver.size();
    }

}