001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.spring.hibernate;
016    
017    import com.liferay.portal.dao.orm.hibernate.event.MVCCSynchronizerPostUpdateEventListener;
018    import com.liferay.portal.dao.orm.hibernate.event.NestableAutoFlushEventListener;
019    import com.liferay.portal.kernel.dao.db.DBManagerUtil;
020    import com.liferay.portal.kernel.dao.db.DBType;
021    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.util.ClassLoaderUtil;
025    import com.liferay.portal.kernel.util.Converter;
026    import com.liferay.portal.kernel.util.PreloadClassLoader;
027    import com.liferay.portal.kernel.util.PropsKeys;
028    import com.liferay.portal.kernel.util.StringUtil;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.util.PropsUtil;
031    import com.liferay.portal.util.PropsValues;
032    
033    import java.io.InputStream;
034    
035    import java.net.URL;
036    
037    import java.util.Enumeration;
038    import java.util.HashMap;
039    import java.util.Map;
040    import java.util.Properties;
041    import java.util.WeakHashMap;
042    
043    import javassist.util.proxy.ProxyFactory;
044    
045    import org.hibernate.HibernateException;
046    import org.hibernate.SessionFactory;
047    import org.hibernate.cfg.Configuration;
048    import org.hibernate.cfg.Environment;
049    import org.hibernate.dialect.Dialect;
050    import org.hibernate.event.AutoFlushEventListener;
051    import org.hibernate.event.EventListeners;
052    import org.hibernate.event.PostUpdateEventListener;
053    
054    import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
055    
056    /**
057     * @author Brian Wing Shun Chan
058     * @author Marcellus Tavares
059     * @author Shuyang Zhou
060     * @author Tomas Polesovsky
061     */
062    public class PortalHibernateConfiguration extends LocalSessionFactoryBean {
063    
064            @Override
065            public SessionFactory buildSessionFactory() throws Exception {
066                    setBeanClassLoader(getConfigurationClassLoader());
067    
068                    return super.buildSessionFactory();
069            }
070    
071            @Override
072            public void destroy() throws HibernateException {
073                    setBeanClassLoader(null);
074    
075                    super.destroy();
076            }
077    
078            public void setHibernateConfigurationConverter(
079                    Converter<String> hibernateConfigurationConverter) {
080    
081                    _hibernateConfigurationConverter = hibernateConfigurationConverter;
082            }
083    
084            public void setMvccEnabled(boolean mvccEnabled) {
085                    _mvccEnabled = mvccEnabled;
086            }
087    
088            protected static Map<String, Class<?>> getPreloadClassLoaderClasses() {
089                    try {
090                            Map<String, Class<?>> classes = new HashMap<>();
091    
092                            for (String className : _PRELOAD_CLASS_NAMES) {
093                                    ClassLoader portalClassLoader =
094                                            ClassLoaderUtil.getPortalClassLoader();
095    
096                                    Class<?> clazz = portalClassLoader.loadClass(className);
097    
098                                    classes.put(className, clazz);
099                            }
100    
101                            return classes;
102                    }
103                    catch (ClassNotFoundException cnfe) {
104                            throw new RuntimeException(cnfe);
105                    }
106            }
107    
108            protected ClassLoader getConfigurationClassLoader() {
109                    Class<?> clazz = getClass();
110    
111                    return clazz.getClassLoader();
112            }
113    
114            protected String[] getConfigurationResources() {
115                    return PropsUtil.getArray(PropsKeys.HIBERNATE_CONFIGS);
116            }
117    
118            @Override
119            protected Configuration newConfiguration() {
120                    Configuration configuration = new Configuration();
121    
122                    Properties properties = PropsUtil.getProperties();
123    
124                    Properties hibernateProperties = getHibernateProperties();
125    
126                    for (Map.Entry<Object, Object> entry : hibernateProperties.entrySet()) {
127                            String key = (String)entry.getKey();
128                            String value = (String)entry.getValue();
129    
130                            properties.setProperty(key, value);
131                    }
132    
133                    Dialect dialect = DialectDetector.getDialect(getDataSource());
134    
135                    if (DBManagerUtil.getDBType(dialect) == DBType.SYBASE) {
136                            properties.setProperty(PropsKeys.HIBERNATE_JDBC_BATCH_SIZE, "0");
137                    }
138    
139                    if (Validator.isNull(PropsValues.HIBERNATE_DIALECT)) {
140                            DBManagerUtil.setDB(dialect, getDataSource());
141    
142                            Class<?> clazz = dialect.getClass();
143    
144                            properties.setProperty("hibernate.dialect", clazz.getName());
145                    }
146    
147                    properties.setProperty("hibernate.cache.use_query_cache", "false");
148                    properties.setProperty(
149                            "hibernate.cache.use_second_level_cache", "false");
150    
151                    properties.remove("hibernate.cache.region.factory_class");
152    
153                    configuration.setProperties(properties);
154    
155                    try {
156                            String[] resources = getConfigurationResources();
157    
158                            for (String resource : resources) {
159                                    try {
160                                            readResource(configuration, resource);
161                                    }
162                                    catch (Exception e2) {
163                                            if (_log.isWarnEnabled()) {
164                                                    _log.warn(e2, e2);
165                                            }
166                                    }
167                            }
168    
169                            if (_mvccEnabled) {
170                                    EventListeners eventListeners =
171                                            configuration.getEventListeners();
172    
173                                    eventListeners.setAutoFlushEventListeners(
174                                            new AutoFlushEventListener[] {
175                                                    NestableAutoFlushEventListener.INSTANCE
176                                            });
177                                    eventListeners.setPostUpdateEventListeners(
178                                            new PostUpdateEventListener[] {
179                                                    MVCCSynchronizerPostUpdateEventListener.INSTANCE
180                                            });
181                            }
182                    }
183                    catch (Exception e1) {
184                            _log.error(e1, e1);
185                    }
186    
187                    return configuration;
188            }
189    
190            @Override
191            protected void postProcessConfiguration(Configuration configuration) {
192    
193                    // Make sure that the Hibernate settings from PropsUtil are set. See the
194                    // buildSessionFactory implementation in the LocalSessionFactoryBean
195                    // class to understand how Spring automates a lot of configuration for
196                    // Hibernate.
197    
198                    String connectionReleaseMode = PropsUtil.get(
199                            Environment.RELEASE_CONNECTIONS);
200    
201                    if (Validator.isNotNull(connectionReleaseMode)) {
202                            configuration.setProperty(
203                                    Environment.RELEASE_CONNECTIONS, connectionReleaseMode);
204                    }
205            }
206    
207            protected void readResource(
208                            Configuration configuration, InputStream inputStream)
209                    throws Exception {
210    
211                    if (inputStream == null) {
212                            return;
213                    }
214    
215                    if (_hibernateConfigurationConverter != null) {
216                            String configurationString = StringUtil.read(inputStream);
217    
218                            configurationString = _hibernateConfigurationConverter.convert(
219                                    configurationString);
220    
221                            inputStream = new UnsyncByteArrayInputStream(
222                                    configurationString.getBytes());
223                    }
224    
225                    configuration.addInputStream(inputStream);
226    
227                    inputStream.close();
228            }
229    
230            protected void readResource(Configuration configuration, String resource)
231                    throws Exception {
232    
233                    ClassLoader classLoader = getConfigurationClassLoader();
234    
235                    if (resource.startsWith("classpath*:")) {
236                            String name = resource.substring("classpath*:".length());
237    
238                            Enumeration<URL> enu = classLoader.getResources(name);
239    
240                            if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
241                                    _log.debug("No resources found for " + name);
242                            }
243    
244                            while (enu.hasMoreElements()) {
245                                    URL url = enu.nextElement();
246    
247                                    InputStream inputStream = url.openStream();
248    
249                                    readResource(configuration, inputStream);
250                            }
251                    }
252                    else {
253                            InputStream inputStream = classLoader.getResourceAsStream(resource);
254    
255                            readResource(configuration, inputStream);
256                    }
257            }
258    
259            private static final String[] _PRELOAD_CLASS_NAMES =
260                    PropsValues.SPRING_HIBERNATE_CONFIGURATION_PROXY_FACTORY_PRELOAD_CLASSLOADER_CLASSES;
261    
262            private static final Log _log = LogFactoryUtil.getLog(
263                    PortalHibernateConfiguration.class);
264    
265            private static final Map<ProxyFactory, ClassLoader>
266                    _proxyFactoryClassLoaders = new WeakHashMap<>();
267    
268            static {
269                    ProxyFactory.classLoaderProvider =
270                            new ProxyFactory.ClassLoaderProvider() {
271    
272                                    @Override
273                                    public ClassLoader get(ProxyFactory proxyFactory) {
274                                            synchronized (_proxyFactoryClassLoaders) {
275                                                    ClassLoader classLoader = _proxyFactoryClassLoaders.get(
276                                                            proxyFactory);
277    
278                                                    if (classLoader != null) {
279                                                            return classLoader;
280                                                    }
281    
282                                                    classLoader = ClassLoaderUtil.getPortalClassLoader();
283    
284                                                    ClassLoader contextClassLoader =
285                                                            ClassLoaderUtil.getContextClassLoader();
286    
287                                                    if (classLoader != contextClassLoader) {
288                                                            classLoader = new PreloadClassLoader(
289                                                                    contextClassLoader,
290                                                                    getPreloadClassLoaderClasses());
291                                                    }
292    
293                                                    _proxyFactoryClassLoaders.put(
294                                                            proxyFactory, classLoader);
295    
296                                                    return classLoader;
297                                            }
298                                    }
299    
300                            };
301            }
302    
303            private Converter<String> _hibernateConfigurationConverter;
304            private boolean _mvccEnabled = true;
305    
306    }