/* * Created on 13 juin 2004 * * * */ package fr.mch.mdo.restaurant.dao.hibernate; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.collection.internal.PersistentBag; import org.hibernate.collection.internal.PersistentList; import org.hibernate.collection.internal.PersistentMap; import org.hibernate.collection.internal.PersistentSet; import org.hibernate.collection.internal.PersistentSortedMap; import org.hibernate.collection.internal.PersistentSortedSet; import org.hibernate.internal.util.xml.DTDEntityResolver; import org.hibernate.proxy.HibernateProxy; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.w3c.dom.Document; import org.xml.sax.SAXException; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.collections.CollectionConverter; import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.CGLIBMapper; import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.MapperWrapper; import fr.mch.mdo.logs.ILogger; import fr.mch.mdo.logs.ILoggerBean; import fr.mch.mdo.restaurant.dao.ISessionFactory; import fr.mch.mdo.restaurant.exception.MdoDataBeanException; import fr.mch.mdo.restaurant.resources.IResources; import fr.mch.mdo.restaurant.services.logs.LoggerServiceImpl; /** * @author Mathieu MA * * To change the template for this generated type comment go to Window - * Preferences - Java - Code Generation - Code and Comments */ public class DefaultSessionFactory implements ISessionFactory, ILoggerBean { private ILogger logger; /** * The session factories cache with files configuration as key. * Maybe we have to change the computing key. */ private Map<String, SessionFactory> sessionFactoryCache = new HashMap<String, SessionFactory>(); /** * The configurations cache with files configuration as key. * Maybe we have to change the computing key. */ private Map<String, Configuration> configurationCache = new HashMap<String, Configuration>(); private boolean xstreamRegistered = false; //private Configuration configuration; private final XStream xstream = new XStream() { protected MapperWrapper wrapMapper(MapperWrapper next) { return new CGLIBMapper(next); } }; private static class LazyHolder { private static ISessionFactory instance = new DefaultSessionFactory(LoggerServiceImpl.getInstance().getLogger(DefaultSessionFactory.class.getName())); } private DefaultSessionFactory(ILogger logger) { this.logger = logger; } public static ISessionFactory getInstance() { return LazyHolder.instance; } public DefaultSessionFactory() { } @Override public Session currentSession() throws MdoDataBeanException { Session s = getSessionFactory().getCurrentSession(); return s; } @Override public void closeSession() throws MdoDataBeanException { getSessionFactory().getCurrentSession().close(); } private Configuration loadConfiguration(String configFile, Configuration config) throws MdoDataBeanException { Configuration result = null; if (config == null) { result = new Configuration(); } else { result = config; } // Configuration with configuration path file InputStream is = IResources.class.getResourceAsStream(configFile); if (is != null) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); // Use Hibernate Entity Resolver in case of off-line(without // Internet) application builder.setEntityResolver(new DTDEntityResolver()); Document document = builder.parse(is); result.configure(document); } catch (ParserConfigurationException e) { logger.error("message.error.dao.configuration.buid.document", new Object[] { configFile }, e); throw new MdoDataBeanException("message.error.dao.configuration.buid.document", new Object[] { configFile }, e); } catch (SAXException e) { logger.error("message.error.dao.configuration.parse.document", new Object[] { configFile }, e); throw new MdoDataBeanException("message.error.dao.configuration.parse.document", new Object[] { configFile }, e); } catch (IOException e) { logger.error("message.error.dao.configuration.read.document", new Object[] { configFile }, e); throw new MdoDataBeanException("message.error.dao.configuration.read.document", new Object[] { configFile }, e); } finally { try { is.close(); } catch (Exception e) { logger.warn("message.error.dao.configuration.close.document", new Object[] { configFile }, e); throw new MdoDataBeanException("message.error.dao.configuration.read.document", new Object[] { configFile }, e); } } } else { logger.error("message.error.dao.configuration.read.document"); throw new MdoDataBeanException("message.error.dao.configuration.read.document"); } return result; } /** * This method will sort the configFiles array will be changed and return a string from the sorted array. * @param configFiles the configuration files to be converted. * @return a converted string. */ private String getCacheKey(final String... configFiles) { String result = null; // Sort the array: the original configFiles array will be changed. Arrays.sort(configFiles); // Get the string array. result = Arrays.toString(configFiles); return result; } public SessionFactory getSessionFactory() throws MdoDataBeanException { return getSessionFactory(IResources.HIBERNATE_CONFIGURATION_FILE); } /** * Be careful, the array of configuration files maybe not contain a file with <session-factory> tag. * If all files are in this case then the session factory could not be built. * @param configFiles the array of configuration files. * @return a session factory. * @throws MdoDataBeanException when any exception occur. */ public SessionFactory getSessionFactory(String... configFiles) throws MdoDataBeanException { // Create key for sessionFactoryCache and configurationCache. String cacheKey = this.getCacheKey(configFiles); // Get the sessionFactory in cache SessionFactory sessionFactory = sessionFactoryCache.get(cacheKey); if (sessionFactory == null) { // The sessionFactory is not yet in cache try { Configuration configuration = null; // Loop to load all configuration files for (String configFile : configFiles) { configuration = loadConfiguration(configFile, configuration); } if (configuration != null) { // Define Hibernate Interceptor configuration.setInterceptor(MdoHibernateInterceptor.getInstance()); // Create the SessionFactory //sessionFactory = configuration.buildSessionFactory(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); /* ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().configure().buildServiceRegistry(); MetadataSources metadataSources = new MetadataSources(serviceRegistry); sessionFactory = metadataSources.buildMetadata().buildSessionFactory(); */ // Put in the cache sessionFactoryCache.put(cacheKey, sessionFactory); configurationCache.put(cacheKey, configuration); } else { logger.error("message.error.dao.configuration.initialize"); throw new MdoDataBeanException("message.error.dao.configuration.initialize"); } } catch (HibernateException e) { logger.error("message.error.dao.configuration.session.factory", e); throw new MdoDataBeanException("message.error.dao.configuration.session.factory", e); } } return sessionFactory; } /** * @return the sqlDialect */ public String getSqlDialect() { return getSqlDialect(IResources.HIBERNATE_CONFIGURATION_FILE); } /** * @return the sqlDialect */ public String getSqlDialect(String... configFiles) { String result = null; // Create key for sessionFactoryCache and configurationCache. String cacheKey = this.getCacheKey(configFiles); // Get the configuration in cache Configuration configuration = configurationCache.get(cacheKey); if (configuration != null) { // Get the SQL dialect result = configuration.getProperty("hibernate.dialect"); } return result; } /** * Use XStream to initialize Hibernate objects * * @param object * @throws ClassCastException */ public void initialize(Object object) throws MdoDataBeanException { xstreamRegisterHibernateConverter(xstream); /* * if (object instanceof IMdoBean) { Hibernate.initialize(object); Class * clazz = object.getClass(); Method[] methods = clazz.getMethods(); for * (int i = 0; i < methods.length; i++) { if * (methods[i].getName().startsWith("get")) { try { if * (methods[i].getReturnType() != void.class && * methods[i].getParameterTypes().length == 0) { if ( * IMdoBean.class.isAssignableFrom(methods[i].getReturnType()) || * Collection.class.isAssignableFrom(methods[i].getReturnType()) || * Map.class.isAssignableFrom(methods[i].getReturnType()) ) { * logger.debug("methods[i].getName() " + i + " = " + * methods[i].getName()); logger.debug("methods[i].getReturnType() " + i * + " = " + methods[i].getReturnType()); try { * initialize(methods[i].invoke(object, new Object[] {})); } catch * (Exception e) { } } } } catch (ClassCastException e) { } } } } else * if (object instanceof Collection<?>) { Hibernate.initialize(object); * } else if (object instanceof Map<?, ?>) { * Hibernate.initialize(object); } else { try { object = (IMdoBean) * object; } catch (ClassCastException e) { * logger.error("message.error.dao.initialize.lazy.loading", new * Object[] { object }, e); throw new ClassCastException(); } } */ // XStream is used for initialize collection String xml = xstream.toXML(object); logger.debug(xml); } @SuppressWarnings("unchecked") public void xstreamRegisterHibernateConverter(XStream xstream) { // Register Once if (xstreamRegistered) { return; } else { xstreamRegistered = true; } xstream.registerConverter(new CollectionConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return type == PersistentSet.class; } }); xstream.aliasType("java.util.Set", PersistentSet.class); xstream.registerConverter(new CollectionConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return type == PersistentBag.class; } }); xstream.aliasType("java.util.ArrayList", PersistentBag.class); xstream.registerConverter(new CollectionConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return type == PersistentList.class; } }); xstream.aliasType("java.util.ArrayList", PersistentList.class); xstream.registerConverter(new MapConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return type == PersistentMap.class; } }); xstream.aliasType("java.util.HashMap", PersistentMap.class); xstream.registerConverter(new MapConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return type == PersistentSortedMap.class; } }); xstream.aliasType("java.util.SortedMap", PersistentSortedMap.class); xstream.registerConverter(new CollectionConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return type == PersistentSortedSet.class; } }); xstream.aliasType("java.util.SortedSet", PersistentSortedSet.class); xstream.registerConverter(new HibernateProxyConverter(xstream.getMapper(), new PureJavaReflectionProvider()), XStream.PRIORITY_VERY_HIGH); // xstream.registerConverter(new CGLIBEnhancedConverter(xstream.getMapper(), xstream.getReflectionProvider()) { // public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { // Hibernate.initialize(source); // // The CGLIBEnhancedConverter of Xstream version 1.3.1 is changed by MMA to be compliant with Hibernate CGLIB lazy loading // super.marshal(source, writer, context); // } // }); } public XStream getXstream() { return xstream; } @Override public ILogger getLogger() { return logger; } @Override public void setLogger(ILogger logger) { this.logger = logger; } public Connection getConnection() throws MdoDataBeanException { return this.getConnection(IResources.HIBERNATE_CONFIGURATION_FILE); } private Connection getConnection(String... configFiles) throws MdoDataBeanException { Connection result = null; this.getSessionFactory(configFiles); // Create key for sessionFactoryCache and configurationCache. String cacheKey = this.getCacheKey(configFiles); // Get the configuration in cache Configuration configuration = configurationCache.get(cacheKey); String hibernateConnectionUrl = configuration.getProperty("hibernate.connection.url"); String hibernateConnectionUsername = configuration.getProperty("hibernate.connection.username"); String hibernateConnectionPassword = configuration.getProperty("hibernate.connection.password"); try { result = DriverManager.getConnection(hibernateConnectionUrl, hibernateConnectionUsername, hibernateConnectionPassword); } catch (SQLException e) { logger.error("message.error.dao.provider.connection"); throw new MdoDataBeanException("message.error.dao.provider.connection"); } /** this.getSessionFactory(configFiles); // Create key for sessionFactoryCache and configurationCache. String cacheKey = this.getCacheKey(configFiles); // Get the configuration in cache Configuration configuration = configurationCache.get(cacheKey); if (configuration != null) { ConnectionProvider provider = configuration.buildSettings().getConnectionProvider(); try { result = provider.getConnection(); } catch (SQLException e) { logger.error("message.error.dao.provider.connection"); throw new MdoDataBeanException("message.error.dao.provider.connection"); } } **/ return result; } class HibernateProxyConverter extends ReflectionConverter { public HibernateProxyConverter(Mapper arg0, ReflectionProvider arg1) { super(arg0, arg1); } /** * be responsible for hibernate proxy */ public boolean canConvert(Class clazz) { logger.debug("Converter says can convert " + clazz + ":" + HibernateProxy.class.isAssignableFrom(clazz)); return HibernateProxy.class.isAssignableFrom(clazz); } public void marshal(Object arg0, HierarchicalStreamWriter arg1, MarshallingContext arg2) { logger.debug("Converter marshalls: " + ((HibernateProxy) arg0).getHibernateLazyInitializer().getImplementation()); super.marshal(((HibernateProxy) arg0).getHibernateLazyInitializer().getImplementation(), arg1, arg2); } } }