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