r2897 - in trunk: topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest topia-junit/src/main/java/org/nuiton/topia/junit topia-persistence/src/main/java/org/nuiton/topia topia-persistence/src/main/java/org/nuiton/topia/framework topia-persistence/src/main/java/org/nuiton/topia/persistence topia-service-migration/src/main/java/org/nuiton/topia/migration topia-templates/src/main/java/org/nuiton/topia/templates
Author: athimel Date: 2013-11-27 12:11:51 +0100 (Wed, 27 Nov 2013) New Revision: 2897 Url: http://nuiton.org/projects/topia/repository/revisions/2897 Log: Introduce TopiaHibernateSessionRegistry in order to make possible to get the PersistenceContext from Hibernate's events (this will be reused for Topia's event firing) Move some internal classes to o.n.t.persistence Added: trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/CascadeSaveTest.java trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/HibernateProvider.java trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSessionRegistry.java Removed: trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/beangen/ trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/persistence/ trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateProvider.java Modified: trunk/topia-junit/src/main/java/org/nuiton/topia/junit/AbstractDatabaseResource.java trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java trunk/topia-persistence/src/main/java/org/nuiton/topia/framework/TopiaHibernateEventListener.java trunk/topia-service-migration/src/main/java/org/nuiton/topia/migration/TopiaMigrationEngine.java trunk/topia-templates/src/main/java/org/nuiton/topia/templates/ApplicationContextTransformer.java trunk/topia-templates/src/main/java/org/nuiton/topia/templates/PersistenceContextTransformer.java Added: trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/CascadeSaveTest.java =================================================================== --- trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/CascadeSaveTest.java (rev 0) +++ trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/CascadeSaveTest.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -0,0 +1,64 @@ +package org.nuiton.topia.it.legacy.topiatest; + +/* + * #%L + * ToPIA :: IT + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import org.junit.Rule; +import org.junit.Test; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.it.legacy.TopiaDatabase; +import org.nuiton.topia.it.legacy.TopiaTestTopiaPersistenceContext; + +/** + * @author Arnaud Thimel <thimel@codelutin.com> + */ +public class CascadeSaveTest { + + @Rule + public final TopiaDatabase db = new TopiaDatabase(); + + /** + * The following test will fail if no topiaId is injected on cascade save. This will test code within this method : + * org.nuiton.topia.framework.TopiaHibernateEventListener#onSaveOrUpdate(org.hibernate.event.spi.SaveOrUpdateEvent) + * + * @throws TopiaException + */ + @Test + public void testSaveCascade() { + + TopiaTestTopiaPersistenceContext persistenceContext = db.beginTransaction(); + + CompanyTopiaDao companyDao = persistenceContext.getCompanyDao(); + DepartmentTopiaDao departmentDao = persistenceContext.getDepartmentDao(); + Company company = companyDao.newInstance(); + company.setName("Toto corp."); + Department department = departmentDao.newInstance(); + department.setName("Jokes"); + company.addDepartment(department); + + companyDao.create(company); + + } + +} Property changes on: trunk/topia-it/src/test/java/org/nuiton/topia/it/legacy/topiatest/CascadeSaveTest.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/topia-junit/src/main/java/org/nuiton/topia/junit/AbstractDatabaseResource.java =================================================================== --- trunk/topia-junit/src/main/java/org/nuiton/topia/junit/AbstractDatabaseResource.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-junit/src/main/java/org/nuiton/topia/junit/AbstractDatabaseResource.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -31,7 +31,7 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.nuiton.topia.AbstractTopiaApplicationContext; -import org.nuiton.topia.HibernateProvider; +import org.nuiton.topia.persistence.HibernateProvider; import org.nuiton.topia.TopiaContextFactory; import org.nuiton.topia.TopiaException; import org.nuiton.topia.TopiaPersistenceContext; Modified: trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -44,7 +44,9 @@ import org.nuiton.topia.framework.TopiaService; import org.nuiton.topia.framework.TopiaUtil; import org.nuiton.topia.persistence.DefaultTopiaIdFactory; +import org.nuiton.topia.persistence.HibernateProvider; import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaHibernateSessionRegistry; import org.nuiton.topia.persistence.TopiaIdFactory; import java.beans.PropertyChangeListener; @@ -77,6 +79,8 @@ protected HibernateProvider hibernateProvider; + protected TopiaHibernateSessionRegistry sessionRegistry = new TopiaHibernateSessionRegistry(); + protected boolean closed = false; protected Set<TopiaPersistenceContext> persistenceContexts = Collections.newSetFromMap( @@ -118,7 +122,7 @@ // TODO AThimel 25/11/13 I don't like it to be public, but necessary for services. Review it public HibernateProvider getHibernateProvider() { if (hibernateProvider == null) { - hibernateProvider = new HibernateProvider(configuration, topiaServiceSupport); + hibernateProvider = new HibernateProvider(configuration, topiaServiceSupport, sessionRegistry); } return hibernateProvider; } @@ -158,6 +162,10 @@ return topiaIdFactory; } + public TopiaHibernateSessionRegistry getSessionRegistry() { + return sessionRegistry; + } + @Override public void addTopiaEntityListener(TopiaEntityListener listener) { topiaFiresSupport.addTopiaEntityListener(listener); Modified: trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -36,8 +36,10 @@ import org.hibernate.cfg.Configuration; import org.nuiton.topia.framework.TopiaFiresSupport; import org.nuiton.topia.persistence.AbstractTopiaDao; +import org.nuiton.topia.persistence.HibernateProvider; import org.nuiton.topia.persistence.TopiaDao; import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaHibernateSessionRegistry; import org.nuiton.topia.persistence.TopiaIdFactory; import java.lang.reflect.InvocationTargetException; @@ -70,6 +72,11 @@ */ protected TopiaIdFactory topiaIdFactory; + /** + * The shared instance of TopiaHibernateSessionRegistry + */ + protected TopiaHibernateSessionRegistry sessionRegistry; + // TODO AThimel 27/09/13 Javadoc protected TopiaFiresSupport firesSupport; @@ -105,10 +112,12 @@ */ public AbstractTopiaPersistenceContext(HibernateProvider hibernateProvider, TopiaListenableSupport listenableSupport, - TopiaIdFactory topiaIdFactory) { + TopiaIdFactory topiaIdFactory, + TopiaHibernateSessionRegistry sessionRegistry) { this.listenableSupport = listenableSupport; this.topiaIdFactory = topiaIdFactory; + this.sessionRegistry = sessionRegistry; this.firesSupport = new TopiaFiresSupport(); // Hibernate support can be created using the given hibernateProvider @@ -170,6 +179,8 @@ // tchemit 2010-12-06 propagates the value of the flag // result.useFlushMode = useFlushMode; + sessionRegistry.register(result, this); + // 20060926 poussin ajouter pour voir si ca regle les problemes de // deadlock h2. Conclusion, il faut bien ouvrir une transaction // maintenant, sinon lorsque l'on fait des acces a la base, une @@ -183,6 +194,7 @@ // et declancher une exception try { result.close(); + sessionRegistry.unregister(result); } catch (HibernateException e1) { if (log.isErrorEnabled()) { log.error("Could not close hibernate session", e1); @@ -314,9 +326,9 @@ Session hibernateSession = hibernateSupport.getHibernateSession(); - Transaction tx = hibernateSession.getTransaction(); + Transaction transaction = hibernateSession.getTransaction(); hibernateSession.flush(); - tx.commit(); + transaction.commit(); getFiresSupport().fireOnPostCommit(this); // TopiaContextImplementor parent = getParentContext(); @@ -343,17 +355,21 @@ try { Session hibernateSession = hibernateSupport.getHibernateSession(); - Transaction tx = hibernateSession.getTransaction(); + Transaction transaction = hibernateSession.getTransaction(); hibernateSession.clear(); - tx.rollback(); + transaction.rollback(); hibernateSession.close(); + sessionRegistry.unregister(hibernateSession); + // it's very important to change the session after rollback // otherwise there are many error during next Entity's modification hibernateSession = hibernateSupport.getHibernateFactory().openSession(); hibernateSupport.setHibernateSession(hibernateSession); hibernateSession.setFlushMode(FlushMode.MANUAL); + sessionRegistry.register(hibernateSession, this); + hibernateSession.beginTransaction(); getFiresSupport().fireOnPostRollback(this); @@ -374,7 +390,10 @@ closed = true; // Now close the current Hibernate session - hibernateSupport.getHibernateSession().close(); + Session hibernateSession = hibernateSupport.getHibernateSession(); + hibernateSession.close(); + + sessionRegistry.unregister(hibernateSession); } @Override Deleted: trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateProvider.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateProvider.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateProvider.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -1,241 +0,0 @@ -package org.nuiton.topia; - -/* - * #%L - * ToPIA :: Persistence - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2013 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -import java.io.File; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.SessionFactory; -import org.hibernate.cfg.Configuration; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.event.service.spi.EventListenerRegistry; -import org.hibernate.event.spi.EventType; -import org.hibernate.service.ServiceRegistry; -import org.hibernate.service.ServiceRegistryBuilder; -import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.service.spi.Stoppable; -import org.nuiton.topia.framework.TopiaHibernateEventListener; -import org.nuiton.topia.framework.TopiaService; -import org.nuiton.topia.framework.TopiaUtil; - -import com.google.common.collect.Lists; - -/** - * @author Arnaud Thimel <thimel@codelutin.com> - */ -public class HibernateProvider { - - private static final Log log = LogFactory.getLog(HibernateProvider.class); - - protected SessionFactory hibernateSessionFactory; - protected Configuration hibernateConfiguration; - - protected Map<String, String> configuration; - protected TopiaServiceSupport topiaServiceSupport; - - /** - * List of persistent classes - */ - protected List<Class<?>> persistentClasses = Lists.newArrayList(); - - public HibernateProvider(Map<String, String> configuration, TopiaServiceSupport topiaServiceSupport) { - this.configuration = configuration; - this.topiaServiceSupport = topiaServiceSupport; - } - - protected String getProperty(String key) { - return getProperty(key, null); - } - - protected String getProperty(String key, String defaultValue) { - String result = defaultValue; - if (configuration.containsKey(key)) { - result = configuration.get(key); - } - - return result; - } - - public List<Class<?>> getPersistentClasses() { - if (persistentClasses.isEmpty()) { - // Force configuration load - getHibernateConfiguration(); - } - return persistentClasses; - } - - public Configuration getHibernateConfiguration() { - if (hibernateConfiguration == null) { - hibernateConfiguration = new Configuration(); - - // ajout des repertoires contenant les mappings hibernate - String[] dirs = getProperty( - TopiaContextFactory.CONFIG_PERSISTENCE_DIRECTORIES, "").split(","); - for (String dir : dirs) { - dir = dir.trim(); - if (StringUtils.isNotEmpty(dir)) { - if (log.isDebugEnabled()) { - log.debug("Load persistence from dir : " + dir); - } - hibernateConfiguration.addDirectory(new File(dir)); - } - } - - // ajout des classes dites persistentes - Set<Class<?>> hibernatePersistanceClasses = new HashSet<Class<?>>(); - for (TopiaService service : topiaServiceSupport.getServices().values()) { - Class<?>[] classes = service.getPersistenceClasses(); - - // certains service n'ont pas de classe persistantes - if (classes != null) { - // sletellier 20110411 : http://www.nuiton.org/issues/show/1454 - hibernatePersistanceClasses.addAll(Arrays.asList(classes)); -// for (Class<?> clazz : classes) { -// hibernateConfiguration.addClass(clazz); -// } - } - } - - String listPersistenceClasses = getProperty( - TopiaContextFactory.CONFIG_PERSISTENCE_CLASSES, ""); - - String[] classes = listPersistenceClasses.split(","); - for (String classname : classes) { - classname = classname.trim(); - if (StringUtils.isNotEmpty(classname)) { - if (log.isDebugEnabled()) { - log.debug("Load persistent class : " + classname); - } - - // XXX echatellier 20111007 ce qui est dommage ici, c'est - // la definition de cette classe ne sert a rien (apart security) - // car pour hibernate hibernateConfiguration.addClass(persistanceClass) - // il ne se sert pas de la classe en fait et fait seulement - // un classname.replace( '.', '/' ) + ".hbm.xml"; - // pour obtenir le mapping et la reinstancier ensuite - - Class<?> clazz; - try { - clazz = Class.forName(classname); - } catch (ClassNotFoundException eee) { - if (log.isDebugEnabled()) { - log.debug("Class " + classname + " not found"); - } - throw new TopiaNotFoundException( - String.format("Persistence class %1$s not found", - classname)); - } - persistentClasses.add(clazz); - - // sletellier 20110411 : http://www.nuiton.org/issues/show/1454 -// hibernateConfiguration.addClass(clazz); - hibernatePersistanceClasses.add(clazz); - } - } - - // sletellier 20110411 : http://www.nuiton.org/issues/show/1454 - // Add persistance classes in hibernate config - for (Class<?> persistanceClass : hibernatePersistanceClasses) { - hibernateConfiguration.addClass(persistanceClass); - } - - Properties prop = new Properties(); - prop.putAll(hibernateConfiguration.getProperties()); - prop.putAll(configuration); - - // Strange behavior, all properties are already loaded from - // constructor. Difficult to use this behavior, need to have - // TOPIA_PERSISTENCE_PROPERTIES_FILE in config. - Properties propertiesFromClasspath = - TopiaUtil.getProperties(getProperty(TopiaContextFactory.CONFIG_PERSISTENCE_PROPERTIES_FILE)); - - if (!propertiesFromClasspath.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug("Load properties from file : " + - propertiesFromClasspath); - } - prop.putAll(propertiesFromClasspath); - } - - hibernateConfiguration.setProperties(prop); - - // tchemit 2011-05-26 When using hibernate > 3.3, need to make sure all mappings are loaded (the one from directory files are not still done). - hibernateConfiguration.buildMappings(); - } - return hibernateConfiguration; - } - - public void close() { - if (hibernateSessionFactory != null) { - hibernateSessionFactory.close(); - // close connection provider if possible (http://nuiton.org/issues/2757) - ConnectionProvider service = ((SessionFactoryImplementor) hibernateSessionFactory).getServiceRegistry().getService(ConnectionProvider.class); - if (service instanceof Stoppable) { - Stoppable stoppable = (Stoppable) service; - stoppable.stop(); - } - } - } - - public SessionFactory getSessionFactory() { - - if (hibernateSessionFactory == null) { - - // init service registry - ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings( - getHibernateConfiguration().getProperties()).buildServiceRegistry(); - - hibernateSessionFactory = getHibernateConfiguration().buildSessionFactory(serviceRegistry); - - // we can't reuse original serviceRegistry instance - // we must call getServiceRegistry on factory to get a working one - ServiceRegistry serviceRegistryInit = ((SessionFactoryImplementor) hibernateSessionFactory).getServiceRegistry(); - EventListenerRegistry eventListenerRegistry = serviceRegistryInit.getService(EventListenerRegistry.class); -// TopiaFiresSupport.TopiaHibernateEvent listener = new TopiaFiresSupport.TopiaHibernateEvent(this); - TopiaHibernateEventListener listener = new TopiaHibernateEventListener(null); // FIXME AThimel 11/10/13 Give a correct instance - eventListenerRegistry.appendListeners(EventType.PRE_INSERT, listener); - eventListenerRegistry.appendListeners(EventType.PRE_LOAD, listener); - eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, listener); - eventListenerRegistry.appendListeners(EventType.PRE_DELETE, listener); - eventListenerRegistry.appendListeners(EventType.POST_INSERT, listener); - eventListenerRegistry.appendListeners(EventType.POST_LOAD, listener); - eventListenerRegistry.appendListeners(EventType.POST_UPDATE, listener); - eventListenerRegistry.appendListeners(EventType.POST_DELETE, listener); - - // following listeners must be called before hibernate - eventListenerRegistry.prependListeners(EventType.SAVE_UPDATE, listener); - } - return hibernateSessionFactory; - } - -} Modified: trunk/topia-persistence/src/main/java/org/nuiton/topia/framework/TopiaHibernateEventListener.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/framework/TopiaHibernateEventListener.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/framework/TopiaHibernateEventListener.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -28,7 +28,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; -import org.hibernate.Session; +import org.hibernate.event.spi.AbstractEvent; +import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.PostDeleteEvent; import org.hibernate.event.spi.PostDeleteEventListener; import org.hibernate.event.spi.PostInsertEvent; @@ -47,14 +48,15 @@ import org.hibernate.event.spi.PreUpdateEventListener; import org.hibernate.event.spi.SaveOrUpdateEvent; import org.hibernate.event.spi.SaveOrUpdateEventListener; -import org.nuiton.topia.AbstractTopiaApplicationContext; import org.nuiton.topia.TopiaDaoSupplier; import org.nuiton.topia.TopiaException; +import org.nuiton.topia.persistence.TopiaHibernateSessionRegistry; import org.nuiton.topia.TopiaPersistenceContext; -import org.nuiton.topia.persistence.AbstractTopiaDao; import org.nuiton.topia.persistence.TopiaEntity; import org.nuiton.topia.persistence.TopiaEntityContextable; +import com.google.common.base.Preconditions; + /** * @author Arnaud Thimel <thimel@codelutin.com> */ @@ -66,55 +68,22 @@ private static final long serialVersionUID = -9206039888626756924L; - protected AbstractTopiaApplicationContext rootContext; + protected TopiaHibernateSessionRegistry registry; - public TopiaHibernateEventListener(AbstractTopiaApplicationContext rootContext) { - this.rootContext = rootContext; + public TopiaHibernateEventListener(TopiaHibernateSessionRegistry registry) { + Preconditions.checkArgument(registry != null); + this.registry = registry; } /** - * Recherche le context utilisant la session hibernate passe en - * parametre + * Look for the TopiaPersistenceContext based on the given Hibernate session * - * @param parent le context parent - * @param hibernate la session hibernate que doit utiliser le - * TopiaContext pour etre retourne - * @return le TopiaContext utilisant cette session hibernate ou null si - * aucun TopiaContext n'utilise cette session. + * @param event the Hibernate event that contains the Session to use + * @return the TopiaPersistenceContext using this Session, or null if not found */ - protected TopiaPersistenceContext getContext( - AbstractTopiaApplicationContext parent, Session hibernate) { - TopiaPersistenceContext result = null; - // FIXME AThimel 23/11/13 Find a way to implement it - -// // FD-20100421 : Ano #546 : no need to copy childContext, the -// // {@link #getChildContext()} provides a thread-safe copy to iterate -// // on it. -//// Set<TopiaContextImplementor> contextChilds = new HashSet<TopiaContextImplementor>(parent.getChildContext()); -// if (parent != null) { // TODO AThimel 11/10/13 It should never be null, fix it -// for (TopiaPersistenceContext context : parent.getChildContext()) { -// -// // by sletellier 24/09/09 : Fix concurent acces error -// // ArrayList<TopiaContextImplementor> children = new ArrayList(parent.getChildContext()); -// // for (TopiaContextImplementor context : children) { -// try { -// if (context.getHibernate() == hibernate) { -// result = context; -// } else { -// // TODO: poussin 20090706 on pourrait ameliorer en ne faisant pas un parcours recursif, en utilisant la liste children (sans doute a transformer en stack) -// result = getContext(context, hibernate); -// } -// if (result != null) { -// break; -// } -// } catch (TopiaException eee) { -// if (log.isWarnEnabled()) { -// log.warn("Error durant la recherche d'un context pour" -// + " lancer un event", eee); -// } -// } -// } -// } + protected TopiaPersistenceContext getContext(AbstractEvent event) { + EventSource session = event.getSession(); + TopiaPersistenceContext result = registry.getPersistenceContext(session); return result; } @@ -140,10 +109,10 @@ @Override public boolean onPreInsert(PreInsertEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { TopiaEntity entity = (TopiaEntity) event.getEntity(); - + context.getTopiaFiresSupport().fireOnPreCreate(context, entity, event.getState()); // when using composition, hibernate will persist entities by him self @@ -160,7 +129,7 @@ @Override public void onPostInsert(PostInsertEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { context.getTopiaFiresSupport().fireOnPostCreate(context, (TopiaEntity) event.getEntity(), event.getState()); } @@ -170,7 +139,7 @@ @Override public void onPreLoad(PreLoadEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { // try { context.getTopiaFiresSupport().fireOnPreLoad(context, (TopiaEntity) event.getEntity(), event.getState()); @@ -184,7 +153,7 @@ @Override public void onPostLoad(PostLoadEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { attachContext(event.getEntity(), context); TopiaEntity entity = (TopiaEntity) event.getEntity(); @@ -196,7 +165,7 @@ @Override public boolean onPreUpdate(PreUpdateEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { context.getTopiaFiresSupport().fireOnPreUpdate(context, (TopiaEntity) event.getEntity(), event.getOldState()); } @@ -205,7 +174,7 @@ @Override public void onPostUpdate(PostUpdateEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { context.getTopiaFiresSupport().fireOnPostUpdate(context, (TopiaEntity) event.getEntity(), event.getState()); } @@ -219,7 +188,7 @@ @Override public boolean onPreDelete(PreDeleteEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { context.getTopiaFiresSupport().fireOnPreDelete(context, (TopiaEntity) event.getEntity(), event.getDeletedState()); } @@ -228,7 +197,7 @@ @Override public void onPostDelete(PostDeleteEvent event) { - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + TopiaPersistenceContext context = getContext(event); if (context != null && event.getEntity() instanceof TopiaEntity) { context.getTopiaFiresSupport().fireOnPostDelete(context, (TopiaEntity) event.getEntity(), event.getDeletedState()); } @@ -241,12 +210,13 @@ @Override public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { try { - // this event is called when hibernate try to persist entities - // using cascade (save) - TopiaPersistenceContext context = getContext(rootContext, event.getSession()); + // this event is called when hibernate try to persist entities using cascade (save) + TopiaPersistenceContext context = getContext(event); // warning, event.getEntity() return null here :( + if (event.getObject() instanceof TopiaEntity) { TopiaEntity entity = (TopiaEntity) event.getObject(); + if (StringUtils.isBlank(entity.getTopiaId())) { if (log.isDebugEnabled()) { log.debug("Adding topiaId into entity " + entity.getClass()); Copied: trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/HibernateProvider.java (from rev 2895, trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateProvider.java) =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/HibernateProvider.java (rev 0) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/HibernateProvider.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -0,0 +1,248 @@ +package org.nuiton.topia.persistence; + +/* + * #%L + * ToPIA :: Persistence + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.EventType; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.service.ServiceRegistryBuilder; +import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.service.spi.Stoppable; +import org.nuiton.topia.TopiaContextFactory; +import org.nuiton.topia.TopiaNotFoundException; +import org.nuiton.topia.TopiaServiceSupport; +import org.nuiton.topia.framework.TopiaHibernateEventListener; +import org.nuiton.topia.framework.TopiaService; +import org.nuiton.topia.framework.TopiaUtil; + +import com.google.common.collect.Lists; + +/** + * @author Arnaud Thimel <thimel@codelutin.com> + */ +public class HibernateProvider { + + private static final Log log = LogFactory.getLog(HibernateProvider.class); + + protected SessionFactory hibernateSessionFactory; + protected Configuration hibernateConfiguration; + + protected Map<String, String> configuration; + protected TopiaServiceSupport topiaServiceSupport; + protected TopiaHibernateSessionRegistry sessionRegistry; + + /** + * List of persistent classes + */ + protected List<Class<?>> persistentClasses = Lists.newArrayList(); + + public HibernateProvider(Map<String, String> configuration, + TopiaServiceSupport topiaServiceSupport, + TopiaHibernateSessionRegistry sessionRegistry) { + this.configuration = configuration; + this.topiaServiceSupport = topiaServiceSupport; + this.sessionRegistry = sessionRegistry; + } + + protected String getProperty(String key) { + return getProperty(key, null); + } + + protected String getProperty(String key, String defaultValue) { + String result = defaultValue; + if (configuration.containsKey(key)) { + result = configuration.get(key); + } + + return result; + } + + public List<Class<?>> getPersistentClasses() { + if (persistentClasses.isEmpty()) { + // Force configuration load + getHibernateConfiguration(); + } + return persistentClasses; + } + + public Configuration getHibernateConfiguration() { + if (hibernateConfiguration == null) { + hibernateConfiguration = new Configuration(); + + // ajout des repertoires contenant les mappings hibernate + String[] dirs = getProperty( + TopiaContextFactory.CONFIG_PERSISTENCE_DIRECTORIES, "").split(","); + for (String dir : dirs) { + dir = dir.trim(); + if (StringUtils.isNotEmpty(dir)) { + if (log.isDebugEnabled()) { + log.debug("Load persistence from dir : " + dir); + } + hibernateConfiguration.addDirectory(new File(dir)); + } + } + + // ajout des classes dites persistentes + Set<Class<?>> hibernatePersistanceClasses = new HashSet<Class<?>>(); + for (TopiaService service : topiaServiceSupport.getServices().values()) { + Class<?>[] classes = service.getPersistenceClasses(); + + // certains service n'ont pas de classe persistantes + if (classes != null) { + // sletellier 20110411 : http://www.nuiton.org/issues/show/1454 + hibernatePersistanceClasses.addAll(Arrays.asList(classes)); +// for (Class<?> clazz : classes) { +// hibernateConfiguration.addClass(clazz); +// } + } + } + + String listPersistenceClasses = getProperty( + TopiaContextFactory.CONFIG_PERSISTENCE_CLASSES, ""); + + String[] classes = listPersistenceClasses.split(","); + for (String classname : classes) { + classname = classname.trim(); + if (StringUtils.isNotEmpty(classname)) { + if (log.isDebugEnabled()) { + log.debug("Load persistent class : " + classname); + } + + // XXX echatellier 20111007 ce qui est dommage ici, c'est + // la definition de cette classe ne sert a rien (apart security) + // car pour hibernate hibernateConfiguration.addClass(persistanceClass) + // il ne se sert pas de la classe en fait et fait seulement + // un classname.replace( '.', '/' ) + ".hbm.xml"; + // pour obtenir le mapping et la reinstancier ensuite + + Class<?> clazz; + try { + clazz = Class.forName(classname); + } catch (ClassNotFoundException eee) { + if (log.isDebugEnabled()) { + log.debug("Class " + classname + " not found"); + } + throw new TopiaNotFoundException( + String.format("Persistence class %1$s not found", + classname)); + } + persistentClasses.add(clazz); + + // sletellier 20110411 : http://www.nuiton.org/issues/show/1454 +// hibernateConfiguration.addClass(clazz); + hibernatePersistanceClasses.add(clazz); + } + } + + // sletellier 20110411 : http://www.nuiton.org/issues/show/1454 + // Add persistance classes in hibernate config + for (Class<?> persistanceClass : hibernatePersistanceClasses) { + hibernateConfiguration.addClass(persistanceClass); + } + + Properties prop = new Properties(); + prop.putAll(hibernateConfiguration.getProperties()); + prop.putAll(configuration); + + // Strange behavior, all properties are already loaded from + // constructor. Difficult to use this behavior, need to have + // TOPIA_PERSISTENCE_PROPERTIES_FILE in config. + Properties propertiesFromClasspath = + TopiaUtil.getProperties(getProperty(TopiaContextFactory.CONFIG_PERSISTENCE_PROPERTIES_FILE)); + + if (!propertiesFromClasspath.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("Load properties from file : " + + propertiesFromClasspath); + } + prop.putAll(propertiesFromClasspath); + } + + hibernateConfiguration.setProperties(prop); + + // tchemit 2011-05-26 When using hibernate > 3.3, need to make sure all mappings are loaded (the one from directory files are not still done). + hibernateConfiguration.buildMappings(); + } + return hibernateConfiguration; + } + + public void close() { + if (hibernateSessionFactory != null) { + hibernateSessionFactory.close(); + // close connection provider if possible (http://nuiton.org/issues/2757) + ConnectionProvider service = ((SessionFactoryImplementor) hibernateSessionFactory).getServiceRegistry().getService(ConnectionProvider.class); + if (service instanceof Stoppable) { + Stoppable stoppable = (Stoppable) service; + stoppable.stop(); + } + } + } + + public SessionFactory getSessionFactory() { + + if (hibernateSessionFactory == null) { + + // init service registry + ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings( + getHibernateConfiguration().getProperties()).buildServiceRegistry(); + + hibernateSessionFactory = getHibernateConfiguration().buildSessionFactory(serviceRegistry); + + // we can't reuse original serviceRegistry instance + // we must call getServiceRegistry on factory to get a working one + ServiceRegistry serviceRegistryInit = ((SessionFactoryImplementor) hibernateSessionFactory).getServiceRegistry(); + EventListenerRegistry eventListenerRegistry = serviceRegistryInit.getService(EventListenerRegistry.class); + + TopiaHibernateEventListener listener = new TopiaHibernateEventListener(sessionRegistry); + eventListenerRegistry.appendListeners(EventType.PRE_INSERT, listener); + eventListenerRegistry.appendListeners(EventType.PRE_LOAD, listener); + eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, listener); + eventListenerRegistry.appendListeners(EventType.PRE_DELETE, listener); + eventListenerRegistry.appendListeners(EventType.POST_INSERT, listener); + eventListenerRegistry.appendListeners(EventType.POST_LOAD, listener); + eventListenerRegistry.appendListeners(EventType.POST_UPDATE, listener); + eventListenerRegistry.appendListeners(EventType.POST_DELETE, listener); + + // following listeners must be called before hibernate + eventListenerRegistry.prependListeners(EventType.SAVE_UPDATE, listener); + } + return hibernateSessionFactory; + } + +} Added: trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSessionRegistry.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSessionRegistry.java (rev 0) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSessionRegistry.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -0,0 +1,95 @@ +package org.nuiton.topia.persistence; + +/* + * #%L + * ToPIA :: Persistence + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2013 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import java.lang.ref.WeakReference; +import java.util.WeakHashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.Session; +import org.nuiton.topia.TopiaPersistenceContext; + +import com.google.common.base.Preconditions; + +/** + * Class used to keep an association between an Hibernate Session and a TopiaPersistenceContext + * + * @author Arnaud Thimel <thimel@codelutin.com> + * @since 3.0 + */ +public class TopiaHibernateSessionRegistry { + + private static final Log log = LogFactory.getLog(TopiaHibernateSessionRegistry.class); + + protected WeakHashMap<Session, WeakReference<TopiaPersistenceContext>> registry = + new WeakHashMap<Session, WeakReference<TopiaPersistenceContext>>(); + + /** + * Register the Session<->TopiaPersistenceContext couple + * + * @param session the currently used Session + * @param persistenceContext the current TopiaPersistenceContext using this Session + */ + public void register(Session session, TopiaPersistenceContext persistenceContext) { + if (log.isDebugEnabled()) { + log.debug("New Session<->TopiaPersistenceContext registration"); + } + Preconditions.checkArgument(session != null); + Preconditions.checkArgument(persistenceContext != null); + WeakReference<TopiaPersistenceContext> reference = new WeakReference<TopiaPersistenceContext>(persistenceContext); + registry.put(session, reference); + } + + /** + * Look for the TopiaPersistenceContext based on the given Hibernate session + * + * @param session the Hibernate Session to use + * @return the TopiaPersistenceContext using this Session, or null if not found + */ + public TopiaPersistenceContext getPersistenceContext(Session session) { + Preconditions.checkArgument(session != null); + WeakReference<TopiaPersistenceContext> reference = registry.get(session); + TopiaPersistenceContext result = reference.get(); + if (log.isDebugEnabled()) { + log.debug("Get TopiaPersistenceContext from Session : " + (result == null ? "Not found" : "HIT !")); + } + return result; + } + + /** + * Removes the Session<->TopiaPersistenceContext association from the registry + * + * @param session the Hibernate Session to remove + */ + public void unregister(Session session) { + Preconditions.checkArgument(session != null); + WeakReference<TopiaPersistenceContext> reference = registry.remove(session); + if (log.isDebugEnabled()) { + log.debug("Remove TopiaPersistenceContext from Session : " + (reference != null)); + } + } + +} Property changes on: trunk/topia-persistence/src/main/java/org/nuiton/topia/persistence/TopiaHibernateSessionRegistry.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/topia-service-migration/src/main/java/org/nuiton/topia/migration/TopiaMigrationEngine.java =================================================================== --- trunk/topia-service-migration/src/main/java/org/nuiton/topia/migration/TopiaMigrationEngine.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-service-migration/src/main/java/org/nuiton/topia/migration/TopiaMigrationEngine.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -34,7 +34,7 @@ import org.hibernate.cfg.Configuration; import org.nuiton.topia.AbstractTopiaApplicationContext; import org.nuiton.topia.AbstractTopiaPersistenceContext; -import org.nuiton.topia.HibernateProvider; +import org.nuiton.topia.persistence.HibernateProvider; import org.nuiton.topia.TopiaException; import org.nuiton.topia.TopiaHibernateSupport; import org.nuiton.topia.TopiaNotFoundException; Modified: trunk/topia-templates/src/main/java/org/nuiton/topia/templates/ApplicationContextTransformer.java =================================================================== --- trunk/topia-templates/src/main/java/org/nuiton/topia/templates/ApplicationContextTransformer.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-templates/src/main/java/org/nuiton/topia/templates/ApplicationContextTransformer.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -167,7 +167,7 @@ setOperationBody(op, "" /*{ <%=persistenceContextConcreteName%> newContext = new <%=persistenceContextConcreteName%>( - getHibernateProvider(), getTopiaListenableSupport(), getTopiaIdFactory()); + getHibernateProvider(), getTopiaListenableSupport(), getTopiaIdFactory(), getSessionRegistry()); registerPersistenceContext(newContext); return newContext; }*/ Modified: trunk/topia-templates/src/main/java/org/nuiton/topia/templates/PersistenceContextTransformer.java =================================================================== --- trunk/topia-templates/src/main/java/org/nuiton/topia/templates/PersistenceContextTransformer.java 2013-11-27 07:38:49 UTC (rev 2896) +++ trunk/topia-templates/src/main/java/org/nuiton/topia/templates/PersistenceContextTransformer.java 2013-11-27 11:11:51 UTC (rev 2897) @@ -34,7 +34,8 @@ import org.nuiton.eugene.models.object.ObjectModelJavaModifier; import org.nuiton.eugene.models.object.ObjectModelOperation; import org.nuiton.topia.AbstractTopiaPersistenceContext; -import org.nuiton.topia.HibernateProvider; +import org.nuiton.topia.persistence.HibernateProvider; +import org.nuiton.topia.persistence.TopiaHibernateSessionRegistry; import org.nuiton.topia.TopiaListenableSupport; import org.nuiton.topia.persistence.TopiaEntity; import org.nuiton.topia.persistence.TopiaIdFactory; @@ -148,9 +149,10 @@ addParameter(constructor, HibernateProvider.class, "hibernateProvider"); addParameter(constructor, TopiaListenableSupport.class, "listenableSupport"); addParameter(constructor, TopiaIdFactory.class, "topiaIdFactory"); + addParameter(constructor, TopiaHibernateSessionRegistry.class, "sessionRegistry"); setOperationBody(constructor, "" /*{ - super(hibernateProvider, listenableSupport, topiaIdFactory); + super(hibernateProvider, listenableSupport, topiaIdFactory, sessionRegistry); }*/ ); @@ -274,9 +276,10 @@ addParameter(constructor, HibernateProvider.class, "hibernateProvider"); addParameter(constructor, TopiaListenableSupport.class, "listenableSupport"); addParameter(constructor, TopiaIdFactory.class, "topiaIdFactory"); + addParameter(constructor, TopiaHibernateSessionRegistry.class, "sessionRegistry"); setOperationBody(constructor, "" /*{ - super(hibernateProvider, listenableSupport, topiaIdFactory); + super(hibernateProvider, listenableSupport, topiaIdFactory, sessionRegistry); }*/ );
participants (1)
-
athimelï¼ users.nuiton.org