001/* 002 * Copyright 2002-2020 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.jdbc.core.metadata; 018 019import java.util.Arrays; 020import java.util.List; 021 022import javax.sql.DataSource; 023 024import org.apache.commons.logging.Log; 025import org.apache.commons.logging.LogFactory; 026 027import org.springframework.dao.DataAccessResourceFailureException; 028import org.springframework.jdbc.support.JdbcUtils; 029import org.springframework.jdbc.support.MetaDataAccessException; 030 031/** 032 * Factory used to create a {@link CallMetaDataProvider} implementation 033 * based on the type of database being used. 034 * 035 * @author Thomas Risberg 036 * @author Juergen Hoeller 037 * @since 2.5 038 */ 039public final class CallMetaDataProviderFactory { 040 041 /** List of supported database products for procedure calls. */ 042 public static final List<String> supportedDatabaseProductsForProcedures = Arrays.asList( 043 "Apache Derby", 044 "DB2", 045 "Informix Dynamic Server", 046 "MariaDB", 047 "Microsoft SQL Server", 048 "MySQL", 049 "Oracle", 050 "PostgreSQL", 051 "Sybase" 052 ); 053 054 /** List of supported database products for function calls. */ 055 public static final List<String> supportedDatabaseProductsForFunctions = Arrays.asList( 056 "MariaDB", 057 "Microsoft SQL Server", 058 "MySQL", 059 "Oracle", 060 "PostgreSQL" 061 ); 062 063 private static final Log logger = LogFactory.getLog(CallMetaDataProviderFactory.class); 064 065 066 private CallMetaDataProviderFactory() { 067 } 068 069 070 /** 071 * Create a {@link CallMetaDataProvider} based on the database meta-data. 072 * @param dataSource the JDBC DataSource to use for retrieving meta-data 073 * @param context the class that holds configuration and meta-data 074 * @return instance of the CallMetaDataProvider implementation to be used 075 */ 076 public static CallMetaDataProvider createMetaDataProvider(DataSource dataSource, final CallMetaDataContext context) { 077 try { 078 return JdbcUtils.extractDatabaseMetaData(dataSource, databaseMetaData -> { 079 String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName()); 080 boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData(); 081 if (context.isFunction()) { 082 if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) { 083 if (logger.isInfoEnabled()) { 084 logger.info(databaseProductName + " is not one of the databases fully supported for function calls " + 085 "-- supported are: " + supportedDatabaseProductsForFunctions); 086 } 087 if (accessProcedureColumnMetaData) { 088 logger.info("Metadata processing disabled - you must specify all parameters explicitly"); 089 accessProcedureColumnMetaData = false; 090 } 091 } 092 } 093 else { 094 if (!supportedDatabaseProductsForProcedures.contains(databaseProductName)) { 095 if (logger.isInfoEnabled()) { 096 logger.info(databaseProductName + " is not one of the databases fully supported for procedure calls " + 097 "-- supported are: " + supportedDatabaseProductsForProcedures); 098 } 099 if (accessProcedureColumnMetaData) { 100 logger.info("Metadata processing disabled - you must specify all parameters explicitly"); 101 accessProcedureColumnMetaData = false; 102 } 103 } 104 } 105 106 CallMetaDataProvider provider; 107 if ("Oracle".equals(databaseProductName)) { 108 provider = new OracleCallMetaDataProvider(databaseMetaData); 109 } 110 else if ("PostgreSQL".equals(databaseProductName)) { 111 provider = new PostgresCallMetaDataProvider((databaseMetaData)); 112 } 113 else if ("Apache Derby".equals(databaseProductName)) { 114 provider = new DerbyCallMetaDataProvider((databaseMetaData)); 115 } 116 else if ("DB2".equals(databaseProductName)) { 117 provider = new Db2CallMetaDataProvider((databaseMetaData)); 118 } 119 else if ("HDB".equals(databaseProductName)) { 120 provider = new HanaCallMetaDataProvider((databaseMetaData)); 121 } 122 else if ("Microsoft SQL Server".equals(databaseProductName)) { 123 provider = new SqlServerCallMetaDataProvider((databaseMetaData)); 124 } 125 else if ("Sybase".equals(databaseProductName)) { 126 provider = new SybaseCallMetaDataProvider((databaseMetaData)); 127 } 128 else { 129 provider = new GenericCallMetaDataProvider(databaseMetaData); 130 } 131 132 if (logger.isDebugEnabled()) { 133 logger.debug("Using " + provider.getClass().getName()); 134 } 135 provider.initializeWithMetaData(databaseMetaData); 136 if (accessProcedureColumnMetaData) { 137 provider.initializeWithProcedureColumnMetaData(databaseMetaData, 138 context.getCatalogName(), context.getSchemaName(), context.getProcedureName()); 139 } 140 return provider; 141 }); 142 } 143 catch (MetaDataAccessException ex) { 144 throw new DataAccessResourceFailureException("Error retrieving database meta-data", ex); 145 } 146 } 147 148}