001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.spring.hibernate;
016    
017    import com.liferay.portal.dao.shard.ShardSpringSessionContext;
018    import com.liferay.portal.kernel.dao.db.DB;
019    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
020    import com.liferay.portal.kernel.dao.shard.ShardUtil;
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.resiliency.spi.SPIUtil;
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.ClassLoaderUtil;
031    import com.liferay.portal.util.PropsUtil;
032    import com.liferay.portal.util.PropsValues;
033    
034    import java.io.InputStream;
035    
036    import java.net.URL;
037    
038    import java.util.Enumeration;
039    import java.util.HashMap;
040    import java.util.Map;
041    import java.util.Properties;
042    import java.util.WeakHashMap;
043    
044    import javassist.util.proxy.ProxyFactory;
045    
046    import org.hibernate.HibernateException;
047    import org.hibernate.SessionFactory;
048    import org.hibernate.cfg.Configuration;
049    import org.hibernate.cfg.Environment;
050    import org.hibernate.dialect.Dialect;
051    
052    import org.springframework.beans.factory.BeanFactory;
053    import org.springframework.beans.factory.BeanFactoryAware;
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
063            extends LocalSessionFactoryBean implements BeanFactoryAware {
064    
065            @Override
066            public SessionFactory buildSessionFactory() throws Exception {
067                    setBeanClassLoader(getConfigurationClassLoader());
068    
069                    return super.buildSessionFactory();
070            }
071    
072            @Override
073            public void destroy() throws HibernateException {
074                    setBeanClassLoader(null);
075    
076                    super.destroy();
077            }
078    
079            @Override
080            public void setBeanFactory(BeanFactory beanFactory) {
081                    _beanFactory = beanFactory;
082            }
083    
084            public void setShardEnabled(boolean shardEnabled) {
085                    _shardEnabled = shardEnabled;
086            }
087    
088            public void setHibernateConfigurationConverter(
089                    Converter<String> hibernateConfigurationConverter) {
090    
091                    _hibernateConfigurationConverter = hibernateConfigurationConverter;
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                    catch (Exception e1) {
178                            _log.error(e1, e1);
179                    }
180    
181                    Properties hibernateProperties = getHibernateProperties();
182    
183                    if (_shardEnabled &&
184                            _beanFactory.containsBean(ShardUtil.class.getName())) {
185    
186                            hibernateProperties.setProperty(
187                                    Environment.CURRENT_SESSION_CONTEXT_CLASS,
188                                    ShardSpringSessionContext.class.getName());
189                    }
190    
191                    for (Map.Entry<Object, Object> entry : hibernateProperties.entrySet()) {
192                            String key = (String)entry.getKey();
193                            String value = (String)entry.getValue();
194    
195                            configuration.setProperty(key, value);
196                    }
197    
198                    return configuration;
199            }
200    
201            @Override
202            protected void postProcessConfiguration(Configuration configuration) {
203    
204                    // Make sure that the Hibernate settings from PropsUtil are set. See the
205                    // buildSessionFactory implementation in the LocalSessionFactoryBean
206                    // class to understand how Spring automates a lot of configuration for
207                    // Hibernate.
208    
209                    String connectionReleaseMode = PropsUtil.get(
210                            Environment.RELEASE_CONNECTIONS);
211    
212                    if (Validator.isNotNull(connectionReleaseMode)) {
213                            configuration.setProperty(
214                                    Environment.RELEASE_CONNECTIONS, connectionReleaseMode);
215                    }
216            }
217    
218            protected void readResource(
219                            Configuration configuration, InputStream inputStream)
220                    throws Exception {
221    
222                    if (inputStream == null) {
223                            return;
224                    }
225    
226                    if (_hibernateConfigurationConverter != null) {
227                            String configurationString = StringUtil.read(inputStream);
228    
229                            configurationString = _hibernateConfigurationConverter.convert(
230                                    configurationString);
231    
232                            inputStream = new UnsyncByteArrayInputStream(
233                                    configurationString.getBytes());
234                    }
235    
236                    configuration = configuration.addInputStream(inputStream);
237    
238                    inputStream.close();
239            }
240    
241            protected void readResource(Configuration configuration, String resource)
242                    throws Exception {
243    
244                    ClassLoader classLoader = getConfigurationClassLoader();
245    
246                    if (resource.startsWith("classpath*:")) {
247                            String name = resource.substring("classpath*:".length());
248    
249                            Enumeration<URL> enu = classLoader.getResources(name);
250    
251                            if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
252                                    _log.debug("No resources found for " + name);
253                            }
254    
255                            while (enu.hasMoreElements()) {
256                                    URL url = enu.nextElement();
257    
258                                    InputStream inputStream = url.openStream();
259    
260                                    readResource(configuration, inputStream);
261                            }
262                    }
263                    else {
264                            InputStream inputStream = classLoader.getResourceAsStream(resource);
265    
266                            readResource(configuration, inputStream);
267                    }
268            }
269    
270            protected void setDB(Dialect dialect) {
271                    DBFactoryUtil.setDB(dialect);
272            }
273    
274            private static final String[] _PRELOAD_CLASS_NAMES =
275                    PropsValues.SPRING_HIBERNATE_CONFIGURATION_PROXY_FACTORY_PRELOAD_CLASSLOADER_CLASSES;
276    
277            private static Log _log = LogFactoryUtil.getLog(
278                    PortalHibernateConfiguration.class);
279    
280            private static Map<ProxyFactory, ClassLoader> _proxyFactoryClassLoaders =
281                    new WeakHashMap<ProxyFactory, ClassLoader>();
282    
283            static {
284                    ProxyFactory.classLoaderProvider =
285                            new ProxyFactory.ClassLoaderProvider() {
286    
287                                    @Override
288                                    public ClassLoader get(ProxyFactory proxyFactory) {
289                                            synchronized (_proxyFactoryClassLoaders) {
290                                                    ClassLoader classLoader = _proxyFactoryClassLoaders.get(
291                                                            proxyFactory);
292    
293                                                    if (classLoader != null) {
294                                                            return classLoader;
295                                                    }
296    
297                                                    classLoader = ClassLoaderUtil.getPortalClassLoader();
298    
299                                                    ClassLoader contextClassLoader =
300                                                            ClassLoaderUtil.getContextClassLoader();
301    
302                                                    if (classLoader != contextClassLoader) {
303                                                            classLoader = new PreloadClassLoader(
304                                                                    contextClassLoader,
305                                                                    getPreloadClassLoaderClasses());
306                                                    }
307    
308                                                    _proxyFactoryClassLoaders.put(
309                                                            proxyFactory, classLoader);
310    
311                                                    return classLoader;
312                                            }
313                                    }
314    
315                            };
316            }
317    
318            private BeanFactory _beanFactory;
319            private Converter<String> _hibernateConfigurationConverter;
320            private boolean _shardEnabled = true;
321    
322    }