All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.jdbc.core.metadata.GenericTableMetaDataProvider Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * Copyright 2002-2007 the original author or authors.
 *
 * 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.springframework.jdbc.core.metadata;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.dao.DataAccessResourceFailureException;

/**
 * A generic implementation of the {@link TableMetaDataProvider} that should provide enough features for all supported
 * databases.
 *
 * @author Thomas Risberg
 * @since 2.5
 */
public class GenericTableMetaDataProvider implements TableMetaDataProvider {

	/** Logger available to subclasses */
	protected static final Log logger = LogFactory.getLog(TableMetaDataProvider.class);

	/** indicator whether column metadata should be used */
	private boolean tableColumnMetaDataUsed = false;

	/** the version of the database */
	private String databaseVersion;

	/** the name of the user currently connected */
	private String userName;

	/** indicates whether the identifiers are uppercased */
	private boolean storesUpperCaseIdentifiers = true;

	/** indicates whether the identifiers are lowercased */
	private boolean storesLowerCaseIdentifiers = false;

	/** indicates whether generated keys retrieval is supported */
	private boolean getGeneratedKeysSupported = true;

	/** indicates whether the use of a String[] for generated keys is supported */
	private boolean generatedKeysColumnNameArraySupported = true;

	/** database product we know that don't support the use of a String[] for generated keys */
	private List productsNotSupportingGeneratedKeysColumnNameArray = Arrays.asList(new String[] {"Apache Derby"});

	/** Collection of TableParameterMetaData objects */
	private List insertParameterMetaData = new ArrayList();


	/**
	 * Constructor used to initialize with provided database meta data.
	 * @param databaseMetaData meta data to be used
	 * @throws SQLException
	 */
	protected GenericTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
		userName = databaseMetaData.getUserName();
	}

	/**
	 * Get whether identifiers use upper case
	 */
	public boolean isStoresUpperCaseIdentifiers() {
		return storesUpperCaseIdentifiers;
	}

	/**
	 * Specify whether identifiers use upper case
	 */
	public void setStoresUpperCaseIdentifiers(boolean storesUpperCaseIdentifiers) {
		this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
	}

	/**
	 * Get whether identifiers use lower case
	 */
	public boolean isStoresLowerCaseIdentifiers() {
		return storesLowerCaseIdentifiers;
	}

	/**
	 * Specify whether identifiers use lower case
	 */
	public void setStoresLowerCaseIdentifiers(boolean storesLowerCaseIdentifiers) {
		this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
	}

	public boolean isTableColumnMetaDataUsed() {
		return tableColumnMetaDataUsed;
	}

	public List getTableParameterMetaData() {
		return insertParameterMetaData;
	}

	public boolean isGetGeneratedKeysSupported() {
		return getGeneratedKeysSupported;
	}

	public boolean isGetGeneratedKeysSimulated(){
		return false;
	}

	public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
		return null;
	}

	/**
	 * Specify whether a column name array is supported for generated keys
	 */
	public void setGetGeneratedKeysSupported(boolean getGeneratedKeysSupported) {
		this.getGeneratedKeysSupported = getGeneratedKeysSupported;
	}

	public boolean isGeneratedKeysColumnNameArraySupported() {
		return generatedKeysColumnNameArraySupported;
	}

	/**
	 * Specify whether a column name array is supported for generated keys
	 */
	public void setGeneratedKeysColumnNameArraySupported(boolean generatedKeysColumnNameArraySupported) {
		this.generatedKeysColumnNameArraySupported = generatedKeysColumnNameArraySupported;
	}


	public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {

		try {
			if (databaseMetaData.supportsGetGeneratedKeys()) {
				logger.debug("GetGeneratedKeys is supported");
				setGetGeneratedKeysSupported(true);
			}
			else {
				logger.debug("GetGeneratedKeys is not supported");
				setGetGeneratedKeysSupported(false);
			}
		}
		catch (SQLException se) {
			logger.warn("Error retrieving 'DatabaseMetaData.getGeneratedKeys' - " + se.getMessage());
		}
		try {
			String databaseProductName = databaseMetaData.getDatabaseProductName();
			if (productsNotSupportingGeneratedKeysColumnNameArray.contains(databaseProductName)) {
				logger.debug("GeneratedKeysColumnNameArray is not supported for " + databaseProductName);
				setGeneratedKeysColumnNameArraySupported(false);
			}
			else {
				logger.debug("GeneratedKeysColumnNameArray is supported for " + databaseProductName);
				setGeneratedKeysColumnNameArraySupported(true);
			}
		}
		catch (SQLException se) {
			logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductName' - " + se.getMessage());
		}
		try {
			databaseVersion = databaseMetaData.getDatabaseProductVersion();
		}
		catch (SQLException se) {
			logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductVersion' - " + se.getMessage());
		}
		try {
			setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers());
		}
		catch (SQLException se) {
			logger.warn("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + se.getMessage());
		}
		try {
			setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers());
		}
		catch (SQLException se) {
			logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + se.getMessage());
		}

	}

	public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName)
			throws SQLException {

		tableColumnMetaDataUsed = true;

		locateTableAndProcessMetaData(databaseMetaData, catalogName, schemaName, tableName);


	}

	public String tableNameToUse(String tableName) {
		if (tableName == null)
			return null;
		else if (isStoresUpperCaseIdentifiers())
			return tableName.toUpperCase();
		else if(isStoresLowerCaseIdentifiers())
			return tableName.toLowerCase();
		else
			return tableName;
	}

	public String catalogNameToUse(String catalogName) {
		if (catalogName == null)
			return null;
		else if (isStoresUpperCaseIdentifiers())
			return catalogName.toUpperCase();
		else if(isStoresLowerCaseIdentifiers())
			return catalogName.toLowerCase();
		else
		return catalogName;
	}

	public String schemaNameToUse(String schemaName) {
		if (schemaName == null)
			return null;
		else if (isStoresUpperCaseIdentifiers())
			return schemaName.toUpperCase();
		else if(isStoresLowerCaseIdentifiers())
			return schemaName.toLowerCase();
		else
		return schemaName;
	}

	public String metaDataCatalogNameToUse(String catalogName) {
		return catalogNameToUse(catalogName);
	}

	public String metaDataSchemaNameToUse(String schemaName) {
		if (schemaName == null) {
			return schemaNameToUse(userName);
		}
		return schemaNameToUse(schemaName);
	}


	/**
	 * Provide access to version info for subclasses 
	 */
	protected String getDatabaseVersion() {
		return databaseVersion;
	}

	/**
	 * Method supporting the metedata processing for a table
	 */
	private void locateTableAndProcessMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName) {
		Map tableMeta = new HashMap();
		ResultSet tables = null;

		try {
			tables = databaseMetaData.getTables(
				catalogNameToUse(catalogName),
				schemaNameToUse(schemaName),
				tableNameToUse(tableName),
				null);
			while (tables != null && tables.next()) {
				TableMetaData tmd = new TableMetaData();
				tmd.setCatalogName(tables.getString("TABLE_CAT"));
				tmd.setSchemaName(tables.getString("TABLE_SCHEM"));
				tmd.setTableName(tables.getString("TABLE_NAME"));
				tmd.setType(tables.getString("TABLE_TYPE"));
				if (tmd.getSchemaName() == null) {
					tableMeta.put(userName.toUpperCase(), tmd);
				}
				else {
					tableMeta.put(tmd.getSchemaName().toUpperCase(), tmd);
				}
			}
		}
		catch (SQLException se) {
			logger.warn("Error while accessing table meta data results" + se.getMessage());
		}
		finally {
			if (tables != null) {
				try {
					tables.close();
				} catch (SQLException e) {
					logger.warn("Error while closing table meta data reults" + e.getMessage());
				}
			}
		}

		if (tableMeta.size() < 1) {
			logger.warn("Unable to locate table meta data for '" + tableName +"' -- column names must be provided");
		}
		else {
			TableMetaData tmd = null;
			if (schemaName == null) {
				tmd = tableMeta.get(userName.toUpperCase());
				if (tmd == null) {
					tmd = tableMeta.get("PUBLIC");
					if (tmd == null) {
						tmd = tableMeta.get("DBO");
					}
					if (tmd == null) {
						throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + tableName + "' in the default schema");
					}
				}
			}
			else {
				tmd = tableMeta.get(schemaName.toUpperCase());
				if (tmd == null) {
					throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + tableName + "' in the '" + schemaName + "' schema");
				}
			}

			processTableColumns(databaseMetaData, tmd);
		}
	}

	/**
	 * Method supporting the metedata processing for a table's columns
	 */
	private void processTableColumns(DatabaseMetaData databaseMetaData, TableMetaData tmd) {
		ResultSet tableColumns = null;
		String metaDataCatalogName = metaDataCatalogNameToUse(tmd.getCatalogName());
		String metaDataSchemaName = metaDataSchemaNameToUse(tmd.getSchemaName());
		String metaDataTableName = tableNameToUse(tmd.getTableName());
		if (logger.isDebugEnabled()) {
			logger.debug("Retrieving metadata for " + metaDataCatalogName + "/" +
					metaDataSchemaName + "/" + metaDataTableName);
		}
		try {
			tableColumns = databaseMetaData.getColumns(
					metaDataCatalogName,
					metaDataSchemaName,
					metaDataTableName,
					null);
			while (tableColumns.next()) {
				TableParameterMetaData meta = new TableParameterMetaData(
						tableColumns.getString("COLUMN_NAME"),
						tableColumns.getInt("DATA_TYPE"),
						tableColumns.getBoolean("NULLABLE")
				);
				insertParameterMetaData.add(meta);
				if (logger.isDebugEnabled()) {
					logger.debug("Retrieved metadata: "
						+ meta.getParameterName() +
						" " + meta.getSqlType() +
						" " + meta.isNullable()
					);
				}
			}
		}
		catch (SQLException se) {
			logger.warn("Error while retreiving metadata for procedure columns: " + se.getMessage());
		}
		finally {
			try {
				if (tableColumns != null)
					tableColumns.close();
			}
			catch (SQLException se) {
				logger.warn("Problem closing resultset for procedure column metadata " + se.getMessage());
			}
		}

	}


	/**
	 * Class representing table meta data
	 */
	private class TableMetaData {
		private String catalogName;
		private String schemaName;
		private String tableName;
		private String type;


		public String getCatalogName() {
			return catalogName;
		}

		public void setCatalogName(String catalogName) {
			this.catalogName = catalogName;
		}

		public String getSchemaName() {
			return schemaName;
		}

		public void setSchemaName(String schemaName) {
			this.schemaName = schemaName;
		}

		public String getTableName() {
			return tableName;
		}

		public void setTableName(String tableName) {
			this.tableName = tableName;
		}

		public String getType() {
			return type;
		}

		public void setType(String type) {
			this.type = type;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy