/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.spring.hibernate;
import com.liferay.portal.dao.orm.hibernate.event.MVCCSynchronizerPostUpdateEventListener;
import com.liferay.portal.dao.orm.hibernate.event.NestableAutoFlushEventListener;
import com.liferay.portal.dao.orm.hibernate.event.NestableFlushEventListener;
import com.liferay.portal.kernel.concurrent.ConcurrentReferenceKeyHashMap;
import com.liferay.portal.kernel.dao.db.DBManagerUtil;
import com.liferay.portal.kernel.dao.db.DBType;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.memory.FinalizeManager;
import com.liferay.portal.kernel.util.ClassLoaderUtil;
import com.liferay.portal.kernel.util.Converter;
import com.liferay.portal.kernel.util.PreloadClassLoader;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.util.PropsUtil;
import com.liferay.portal.util.PropsValues;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javassist.util.proxy.ProxyFactory;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.event.AutoFlushEventListener;
import org.hibernate.event.EventListeners;
import org.hibernate.event.FlushEventListener;
import org.hibernate.event.PostUpdateEventListener;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
/**
* @author Brian Wing Shun Chan
* @author Marcellus Tavares
* @author Shuyang Zhou
* @author Tomas Polesovsky
*/
public class PortalHibernateConfiguration extends LocalSessionFactoryBean {
@Override
public SessionFactory buildSessionFactory() throws Exception {
setBeanClassLoader(getConfigurationClassLoader());
return super.buildSessionFactory();
}
@Override
public void destroy() throws HibernateException {
setBeanClassLoader(null);
super.destroy();
}
public void setHibernateConfigurationConverter(
Converter<String> hibernateConfigurationConverter) {
_hibernateConfigurationConverter = hibernateConfigurationConverter;
}
public void setMvccEnabled(boolean mvccEnabled) {
_mvccEnabled = mvccEnabled;
}
protected static Map<String, Class<?>> getPreloadClassLoaderClasses() {
try {
Map<String, Class<?>> classes = new HashMap<>();
for (String className : _PRELOAD_CLASS_NAMES) {
ClassLoader portalClassLoader =
ClassLoaderUtil.getPortalClassLoader();
Class<?> clazz = portalClassLoader.loadClass(className);
classes.put(className, clazz);
}
return classes;
}
catch (ClassNotFoundException cnfe) {
throw new RuntimeException(cnfe);
}
}
protected ClassLoader getConfigurationClassLoader() {
Class<?> clazz = getClass();
return clazz.getClassLoader();
}
protected String[] getConfigurationResources() {
return PropsUtil.getArray(PropsKeys.HIBERNATE_CONFIGS);
}
@Override
protected Configuration newConfiguration() {
Configuration configuration = new Configuration();
Properties properties = PropsUtil.getProperties();
Properties hibernateProperties = getHibernateProperties();
for (Map.Entry<Object, Object> entry : hibernateProperties.entrySet()) {
String key = (String)entry.getKey();
String value = (String)entry.getValue();
properties.setProperty(key, value);
}
Dialect dialect = DialectDetector.getDialect(getDataSource());
if (DBManagerUtil.getDBType(dialect) == DBType.SYBASE) {
properties.setProperty(PropsKeys.HIBERNATE_JDBC_BATCH_SIZE, "0");
}
if (Validator.isNull(PropsValues.HIBERNATE_DIALECT)) {
DBManagerUtil.setDB(dialect, getDataSource());
Class<?> clazz = dialect.getClass();
properties.setProperty("hibernate.dialect", clazz.getName());
}
properties.setProperty("hibernate.cache.use_query_cache", "false");
properties.setProperty(
"hibernate.cache.use_second_level_cache", "false");
properties.remove("hibernate.cache.region.factory_class");
configuration.setProperties(properties);
try {
String[] resources = getConfigurationResources();
for (String resource : resources) {
try {
readResource(configuration, resource);
}
catch (Exception e2) {
if (_log.isWarnEnabled()) {
_log.warn(e2, e2);
}
}
}
if (_mvccEnabled) {
EventListeners eventListeners =
configuration.getEventListeners();
eventListeners.setAutoFlushEventListeners(
new AutoFlushEventListener[] {
NestableAutoFlushEventListener.INSTANCE
});
eventListeners.setFlushEventListeners(
new FlushEventListener[] {
NestableFlushEventListener.INSTANCE
});
eventListeners.setPostUpdateEventListeners(
new PostUpdateEventListener[] {
MVCCSynchronizerPostUpdateEventListener.INSTANCE
});
}
}
catch (Exception e1) {
_log.error(e1, e1);
}
return configuration;
}
@Override
protected void postProcessConfiguration(Configuration configuration) {
// Make sure that the Hibernate settings from PropsUtil are set. See the
// buildSessionFactory implementation in the LocalSessionFactoryBean
// class to understand how Spring automates a lot of configuration for
// Hibernate.
String connectionReleaseMode = PropsUtil.get(
Environment.RELEASE_CONNECTIONS);
if (Validator.isNotNull(connectionReleaseMode)) {
configuration.setProperty(
Environment.RELEASE_CONNECTIONS, connectionReleaseMode);
}
}
protected void readResource(
Configuration configuration, InputStream inputStream)
throws Exception {
if (inputStream == null) {
return;
}
if (_hibernateConfigurationConverter != null) {
String configurationString = StringUtil.read(inputStream);
configurationString = _hibernateConfigurationConverter.convert(
configurationString);
inputStream = new UnsyncByteArrayInputStream(
configurationString.getBytes());
}
configuration.addInputStream(inputStream);
inputStream.close();
}
protected void readResource(Configuration configuration, String resource)
throws Exception {
ClassLoader classLoader = getConfigurationClassLoader();
if (resource.startsWith("classpath*:")) {
String name = resource.substring("classpath*:".length());
Enumeration<URL> enu = classLoader.getResources(name);
if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
_log.debug("No resources found for " + name);
}
while (enu.hasMoreElements()) {
URL url = enu.nextElement();
InputStream inputStream = url.openStream();
readResource(configuration, inputStream);
}
}
else {
InputStream inputStream = classLoader.getResourceAsStream(resource);
readResource(configuration, inputStream);
}
}
private static final String[] _PRELOAD_CLASS_NAMES =
PropsValues.SPRING_HIBERNATE_CONFIGURATION_PROXY_FACTORY_PRELOAD_CLASSLOADER_CLASSES;
private static final Log _log = LogFactoryUtil.getLog(
PortalHibernateConfiguration.class);
private static final Map<ProxyFactory, ClassLoader>
_proxyFactoryClassLoaders = new ConcurrentReferenceKeyHashMap<>(
FinalizeManager.WEAK_REFERENCE_FACTORY);
static {
ProxyFactory.classLoaderProvider =
new ProxyFactory.ClassLoaderProvider() {
@Override
public ClassLoader get(ProxyFactory proxyFactory) {
return _proxyFactoryClassLoaders.computeIfAbsent(
proxyFactory,
(ProxyFactory pf) -> {
ClassLoader classLoader =
ClassLoaderUtil.getPortalClassLoader();
ClassLoader contextClassLoader =
ClassLoaderUtil.getContextClassLoader();
if (classLoader != contextClassLoader) {
classLoader = new PreloadClassLoader(
contextClassLoader,
getPreloadClassLoaderClasses());
}
return classLoader;
});
}
};
}
private Converter<String> _hibernateConfigurationConverter;
private boolean _mvccEnabled = true;
}