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