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.dao.shard.ShardSpringSessionContext;
020    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
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            public void setShardEnabled(boolean shardEnabled) {
089                    _shardEnabled = shardEnabled;
090            }
091    
092            protected static Map<String, Class<?>> getPreloadClassLoaderClasses() {
093                    try {
094                            Map<String, Class<?>> classes = new HashMap<>();
095    
096                            for (String className : _PRELOAD_CLASS_NAMES) {
097                                    ClassLoader portalClassLoader =
098                                            ClassLoaderUtil.getPortalClassLoader();
099    
100                                    Class<?> clazz = portalClassLoader.loadClass(className);
101    
102                                    classes.put(className, clazz);
103                            }
104    
105                            return classes;
106                    }
107                    catch (ClassNotFoundException cnfe) {
108                            throw new RuntimeException(cnfe);
109                    }
110            }
111    
112            protected Dialect determineDialect() {
113                    return DialectDetector.getDialect(getDataSource());
114            }
115    
116            protected ClassLoader getConfigurationClassLoader() {
117                    Class<?> clazz = getClass();
118    
119                    return clazz.getClassLoader();
120            }
121    
122            protected String[] getConfigurationResources() {
123                    return PropsUtil.getArray(PropsKeys.HIBERNATE_CONFIGS);
124            }
125    
126            @Override
127            protected Configuration newConfiguration() {
128                    Configuration configuration = new Configuration();
129    
130                    Properties properties = PropsUtil.getProperties();
131    
132                    Properties hibernateProperties = getHibernateProperties();
133    
134                    for (Map.Entry<Object, Object> entry : hibernateProperties.entrySet()) {
135                            String key = (String)entry.getKey();
136                            String value = (String)entry.getValue();
137    
138                            properties.setProperty(key, value);
139                    }
140    
141                    if (Validator.isNull(PropsValues.HIBERNATE_DIALECT)) {
142                            Dialect dialect = determineDialect();
143    
144                            setDB(dialect);
145    
146                            Class<?> clazz = dialect.getClass();
147    
148                            properties.setProperty("hibernate.dialect", clazz.getName());
149                    }
150    
151                    if (_shardEnabled) {
152                            properties.setProperty(
153                                    Environment.CURRENT_SESSION_CONTEXT_CLASS,
154                                    ShardSpringSessionContext.class.getName());
155                    }
156    
157                    properties.setProperty("hibernate.cache.use_query_cache", "false");
158                    properties.setProperty(
159                            "hibernate.cache.use_second_level_cache", "false");
160    
161                    properties.remove("hibernate.cache.region.factory_class");
162    
163                    configuration.setProperties(properties);
164    
165                    try {
166                            String[] resources = getConfigurationResources();
167    
168                            for (String resource : resources) {
169                                    try {
170                                            readResource(configuration, resource);
171                                    }
172                                    catch (Exception e2) {
173                                            if (_log.isWarnEnabled()) {
174                                                    _log.warn(e2, e2);
175                                            }
176                                    }
177                            }
178    
179                            if (_mvccEnabled) {
180                                    EventListeners eventListeners =
181                                            configuration.getEventListeners();
182    
183                                    eventListeners.setAutoFlushEventListeners(
184                                            new AutoFlushEventListener[] {
185                                                    NestableAutoFlushEventListener.INSTANCE
186                                            });
187                                    eventListeners.setPostUpdateEventListeners(
188                                            new PostUpdateEventListener[] {
189                                                    MVCCSynchronizerPostUpdateEventListener.INSTANCE
190                                            });
191                            }
192                    }
193                    catch (Exception e1) {
194                            _log.error(e1, e1);
195                    }
196    
197                    return configuration;
198            }
199    
200            @Override
201            protected void postProcessConfiguration(Configuration configuration) {
202    
203                    // Make sure that the Hibernate settings from PropsUtil are set. See the
204                    // buildSessionFactory implementation in the LocalSessionFactoryBean
205                    // class to understand how Spring automates a lot of configuration for
206                    // Hibernate.
207    
208                    String connectionReleaseMode = PropsUtil.get(
209                            Environment.RELEASE_CONNECTIONS);
210    
211                    if (Validator.isNotNull(connectionReleaseMode)) {
212                            configuration.setProperty(
213                                    Environment.RELEASE_CONNECTIONS, connectionReleaseMode);
214                    }
215            }
216    
217            protected void readResource(
218                            Configuration configuration, InputStream inputStream)
219                    throws Exception {
220    
221                    if (inputStream == null) {
222                            return;
223                    }
224    
225                    if (_hibernateConfigurationConverter != null) {
226                            String configurationString = StringUtil.read(inputStream);
227    
228                            configurationString = _hibernateConfigurationConverter.convert(
229                                    configurationString);
230    
231                            inputStream = new UnsyncByteArrayInputStream(
232                                    configurationString.getBytes());
233                    }
234    
235                    configuration.addInputStream(inputStream);
236    
237                    inputStream.close();
238            }
239    
240            protected void readResource(Configuration configuration, String resource)
241                    throws Exception {
242    
243                    ClassLoader classLoader = getConfigurationClassLoader();
244    
245                    if (resource.startsWith("classpath*:")) {
246                            String name = resource.substring("classpath*:".length());
247    
248                            Enumeration<URL> enu = classLoader.getResources(name);
249    
250                            if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
251                                    _log.debug("No resources found for " + name);
252                            }
253    
254                            while (enu.hasMoreElements()) {
255                                    URL url = enu.nextElement();
256    
257                                    InputStream inputStream = url.openStream();
258    
259                                    readResource(configuration, inputStream);
260                            }
261                    }
262                    else {
263                            InputStream inputStream = classLoader.getResourceAsStream(resource);
264    
265                            readResource(configuration, inputStream);
266                    }
267            }
268    
269            protected void setDB(Dialect dialect) {
270                    DBFactoryUtil.setDB(dialect);
271            }
272    
273            private static final String[] _PRELOAD_CLASS_NAMES =
274                    PropsValues.SPRING_HIBERNATE_CONFIGURATION_PROXY_FACTORY_PRELOAD_CLASSLOADER_CLASSES;
275    
276            private static final Log _log = LogFactoryUtil.getLog(
277                    PortalHibernateConfiguration.class);
278    
279            private static final Map<ProxyFactory, ClassLoader>
280                    _proxyFactoryClassLoaders = new WeakHashMap<>();
281    
282            static {
283                    ProxyFactory.classLoaderProvider =
284                            new ProxyFactory.ClassLoaderProvider() {
285    
286                                    @Override
287                                    public ClassLoader get(ProxyFactory proxyFactory) {
288                                            synchronized (_proxyFactoryClassLoaders) {
289                                                    ClassLoader classLoader = _proxyFactoryClassLoaders.get(
290                                                            proxyFactory);
291    
292                                                    if (classLoader != null) {
293                                                            return classLoader;
294                                                    }
295    
296                                                    classLoader = ClassLoaderUtil.getPortalClassLoader();
297    
298                                                    ClassLoader contextClassLoader =
299                                                            ClassLoaderUtil.getContextClassLoader();
300    
301                                                    if (classLoader != contextClassLoader) {
302                                                            classLoader = new PreloadClassLoader(
303                                                                    contextClassLoader,
304                                                                    getPreloadClassLoaderClasses());
305                                                    }
306    
307                                                    _proxyFactoryClassLoaders.put(
308                                                            proxyFactory, classLoader);
309    
310                                                    return classLoader;
311                                            }
312                                    }
313    
314                            };
315            }
316    
317            private Converter<String> _hibernateConfigurationConverter;
318            private boolean _mvccEnabled = true;
319            private boolean _shardEnabled;
320    
321    }