001/*
002 * Copyright 2006-2007 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.batch.support;
018
019import org.springframework.jdbc.support.JdbcUtils;
020import org.springframework.jdbc.support.MetaDataAccessException;
021import org.springframework.util.StringUtils;
022
023import javax.sql.DataSource;
024import java.util.HashMap;
025import java.util.Map;
026
027
028/**
029 * Enum representing a database type, such as DB2 or oracle.  The type also
030 * contains a product name, which is expected to be the same as the product name
031 * provided by the database driver's metadata.
032 *
033 * @author Lucas Ward
034 * @since 2.0
035 */
036public enum DatabaseType {
037
038        DERBY("Apache Derby"),
039        DB2("DB2"),
040        DB2VSE("DB2VSE"),
041        DB2ZOS("DB2ZOS"),
042        DB2AS400("DB2AS400"),
043        HSQL("HSQL Database Engine"),
044        SQLSERVER("Microsoft SQL Server"),
045        MYSQL("MySQL"),
046        ORACLE("Oracle"),
047        POSTGRES("PostgreSQL"),
048        SYBASE("Sybase"),
049        H2("H2"),
050        SQLITE("SQLite");
051
052        private static final Map<String, DatabaseType> nameMap;
053
054        static{
055                nameMap = new HashMap<String, DatabaseType>();
056                for(DatabaseType type: values()){
057                        nameMap.put(type.getProductName(), type);
058                }
059        }
060        //A description is necessary due to the nature of database descriptions
061        //in metadata.
062        private final String productName;
063
064        private DatabaseType(String productName) {
065                this.productName = productName;
066        }
067
068        public String getProductName() {
069                return productName;
070        }
071
072        /**
073         * Static method to obtain a DatabaseType from the provided product name.
074         *
075         * @param productName {@link String} containing the product name.
076         * @return the {@link DatabaseType} for given product name.
077         *
078         * @throws IllegalArgumentException if none is found.
079         */
080        public static DatabaseType fromProductName(String productName){
081                if(productName.equals("MariaDB"))
082                        productName = "MySQL";
083                if(!nameMap.containsKey(productName)){
084                        throw new IllegalArgumentException("DatabaseType not found for product name: [" +
085                                        productName + "]");
086                }
087                else{
088                        return nameMap.get(productName);
089                }
090        }
091
092        /**
093         * Convenience method that pulls a database product name from the DataSource's metadata.
094         *
095         * @param dataSource {@link DataSource} to the database to be used.
096         * @return {@link DatabaseType} for the {@link DataSource} specified.
097         *
098         * @throws MetaDataAccessException thrown if error occured during Metadata lookup.
099         */
100        public static DatabaseType fromMetaData(DataSource dataSource) throws MetaDataAccessException {
101                String databaseProductName =
102                                JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString();
103                if (StringUtils.hasText(databaseProductName) && databaseProductName.startsWith("DB2")) {
104                        String databaseProductVersion =
105                                        JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion").toString();
106                        if (databaseProductVersion.startsWith("ARI")) {
107                                databaseProductName = "DB2VSE";
108                        }
109                        else if (databaseProductVersion.startsWith("DSN")) {
110                                databaseProductName = "DB2ZOS";
111                        }
112                        else if (databaseProductName.indexOf("AS") != -1 && (databaseProductVersion.startsWith("QSQ") ||
113                                        databaseProductVersion.substring(databaseProductVersion.indexOf('V')).matches("V\\dR\\d[mM]\\d"))) {
114                                databaseProductName = "DB2AS400";
115                        }
116                        else {
117                                databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);
118                        }
119                }
120                else {
121                        databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);
122                }
123                return fromProductName(databaseProductName);
124        }
125}