/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.utils.jdbc;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.sql.DataSource;
import org.apereo.portal.hibernate.DelegatingHibernateIntegrator.HibernateConfiguration;
import org.apereo.portal.hibernate.HibernateConfigurationAware;
import org.apereo.portal.utils.Tuple;
import org.hibernate.dialect.Dialect;
import org.hibernate.service.jdbc.dialect.spi.DialectResolver;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.jasig.portlet.utils.jdbc.DelayedValidationQueryResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.support.DatabaseMetaDataCallback;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
public class DelayedValidationQueryResolverImpl
implements DelayedValidationQueryResolver, HibernateConfigurationAware {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final List<Tuple<DataSource, ValidationQueryRegistrationHandler>> delayedDataSources =
new ArrayList<Tuple<DataSource, ValidationQueryRegistrationHandler>>();
private ConcurrentMap<Class<? extends Dialect>, String> validationQueryMap;
private String persistenceUnit;
private DialectResolver dialectResolver;
public void setValidationQueryMap(Map<Class<? extends Dialect>, String> validationQueryMap) {
this.validationQueryMap =
new ConcurrentHashMap<Class<? extends Dialect>, String>(validationQueryMap);
}
public void setPersistenceUnit(String persistenceUnit) {
this.persistenceUnit = persistenceUnit;
}
@Override
public boolean supports(String persistenceUnit) {
return this.persistenceUnit.equals(persistenceUnit);
}
@Override
public void setConfiguration(
String persistenceUnit, HibernateConfiguration hibernateConfiguration) {
final SessionFactoryServiceRegistry serviceRegistry =
hibernateConfiguration.getServiceRegistry();
synchronized (this.delayedDataSources) {
this.dialectResolver = serviceRegistry.getService(DialectResolver.class);
for (final Tuple<DataSource, ValidationQueryRegistrationHandler> delayedDataSource :
this.delayedDataSources) {
final String validationQuery = this.getValidationQuery(delayedDataSource.first);
delayedDataSource.second.setValidationQuery(validationQuery);
}
this.delayedDataSources.clear();
}
}
@Override
public void registerValidationQueryCallback(
DataSource dataSource,
ValidationQueryRegistrationHandler validationQueryRegistrationHandler) {
synchronized (this.delayedDataSources) {
if (this.dialectResolver != null) {
final String validationQuery = this.getValidationQuery(dataSource);
validationQueryRegistrationHandler.setValidationQuery(validationQuery);
} else {
this.delayedDataSources.add(
new Tuple<DataSource, ValidationQueryRegistrationHandler>(
dataSource, validationQueryRegistrationHandler));
}
}
}
protected String getValidationQuery(DataSource dataSource) {
final Dialect dialect = this.resolveDialect(dataSource);
if (dialect == null) {
return null;
}
final Class<? extends Dialect> dialectType = dialect.getClass();
return resolveValidationQuery(dialectType);
}
protected String resolveValidationQuery(final Class<? extends Dialect> dialectType) {
//First try a direct lookup
String validationQuery = this.validationQueryMap.get(dialectType);
if (validationQuery != null) {
return validationQuery;
}
//Next search the mappings looking for a sublcass match
for (final Map.Entry<Class<? extends Dialect>, String> validationQueryEntry :
this.validationQueryMap.entrySet()) {
final Class<? extends Dialect> dialectEntryType = validationQueryEntry.getKey();
if (dialectEntryType.isAssignableFrom(dialectType)) {
validationQuery = validationQueryEntry.getValue();
//Cache the resolution for future tests
this.validationQueryMap.put(dialectType, validationQuery);
return validationQuery;
}
}
logger.warn("Failed to resolve validation query for Dialect: " + dialectType);
return null;
}
protected Dialect resolveDialect(DataSource dataSource) {
try {
return (Dialect)
JdbcUtils.extractDatabaseMetaData(
dataSource,
new DatabaseMetaDataCallback() {
@Override
public Object processMetaData(DatabaseMetaData dbmd)
throws SQLException, MetaDataAccessException {
return dialectResolver.resolveDialect(dbmd);
}
});
} catch (MetaDataAccessException e) {
logger.warn(
"Failed to resolve Dialect for DataSource "
+ dataSource
+ " no validation query will be resolved",
e);
return null;
}
}
}