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