/*
* Copyright 2014 mango.jfaster.org
*
* The Mango Project licenses this file to you 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.jfaster.mango.jdbc;
import org.jfaster.mango.transaction.exception.CannotGetJdbcConnectionException;
import org.jfaster.mango.jdbc.exception.MetaDataAccessException;
import org.jfaster.mango.transaction.DataSourceUtils;
import org.jfaster.mango.util.PatternMatchUtils;
import org.jfaster.mango.util.logging.InternalLogger;
import org.jfaster.mango.util.logging.InternalLoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* @author ash
*/
public class SQLErrorCodesFactory {
protected final static InternalLogger logger = InternalLoggerFactory.getInstance(SQLErrorCodesFactory.class);
private final static SQLErrorCodesFactory instance = new SQLErrorCodesFactory();
private final Map<DataSource, SQLErrorCodes> dataSourceCache = new HashMap<DataSource, SQLErrorCodes>(16);
private final Map<String, SQLErrorCodes> errorCodesMap;
public SQLErrorCodesFactory() {
this.errorCodesMap = buildErrorCodesMap();
}
public static SQLErrorCodesFactory getInstance() {
return instance;
}
public SQLErrorCodes getErrorCodes(DataSource dataSource) {
if (logger.isDebugEnabled()) {
logger.debug("Looking up default SQLErrorCodes for DataSource [" + dataSource + "]");
}
synchronized (this.dataSourceCache) {
SQLErrorCodes sec = this.dataSourceCache.get(dataSource);
if (sec != null) {
if (logger.isDebugEnabled()) {
logger.debug("SQLErrorCodes found in cache for DataSource [" +
dataSource.getClass().getName() + '@' + Integer.toHexString(dataSource.hashCode()) + "]");
}
return sec;
}
try {
String dbName = fetchDatabaseProductName(dataSource);
if (dbName != null) {
if (logger.isDebugEnabled()) {
logger.debug("Database product name cached for DataSource [" +
dataSource.getClass().getName() + '@' + Integer.toHexString(dataSource.hashCode()) +
"]: name is '" + dbName + "'");
}
sec = getErrorCodes(dbName);
this.dataSourceCache.put(dataSource, sec);
return sec;
}
} catch (MetaDataAccessException ex) {
logger.warn("Error while extracting database product name - falling back to empty error codes", ex);
}
}
// 失败返回空的SQLErrorCodes
return SQLErrorCodes.EMPTY;
}
private SQLErrorCodes getErrorCodes(String dbName) {
SQLErrorCodes sec = this.errorCodesMap.get(dbName);
if (sec == null) {
for (SQLErrorCodes candidate : this.errorCodesMap.values()) {
if (PatternMatchUtils.simpleMatch(candidate.getDatabaseProductNames(), dbName)) {
sec = candidate;
break;
}
}
}
if (sec != null) {
return sec;
}
if (logger.isDebugEnabled()) {
logger.debug("SQL error codes for '" + dbName + "' not found");
}
return SQLErrorCodes.EMPTY;
}
private Map<String, SQLErrorCodes> buildErrorCodesMap() {
Map<String, SQLErrorCodes> errorCodesMap = new HashMap<String, SQLErrorCodes>();
for (SQLErrorCodes errorCodes : SQLErrorCodes.values()) {
if (errorCodes != SQLErrorCodes.EMPTY) {
errorCodes.init();
errorCodesMap.put(errorCodes.name(), errorCodes);
}
}
return errorCodesMap;
}
/**
* 获取数据库名称
*
* @param dataSource
* @return
* @throws MetaDataAccessException
*/
private String fetchDatabaseProductName(DataSource dataSource) throws MetaDataAccessException {
Connection conn = null;
try {
conn = DataSourceUtils.getConnection(dataSource);
DatabaseMetaData metaData = conn.getMetaData();
return metaData.getDatabaseProductName();
} catch (CannotGetJdbcConnectionException ex) {
throw new MetaDataAccessException("Could not get Connection for extracting meta data", ex);
} catch (SQLException ex) {
throw new MetaDataAccessException("Error while extracting DatabaseMetaData", ex);
} finally {
DataSourceUtils.releaseConnection(conn, dataSource);
}
}
}