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