Author: athimel Date: 2013-10-11 18:47:08 +0200 (Fri, 11 Oct 2013) New Revision: 2841 Url: http://nuiton.org/projects/topia/repository/revisions/2841 Log: Implement TopiaServiceSupport and initialize it Improve AbstractTopiaPersistenceContext documentation and transaction creation Added: trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaSqlSupport.java trunk/topia-persistence/src/main/java/org/nuiton/topia/TopiaServiceSupportImpl.java Modified: 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/HibernateTopiaJpaSupport.java Modified: trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java 2013-10-11 15:13:30 UTC (rev 2840) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaApplicationContext.java 2013-10-11 16:47:08 UTC (rev 2841) @@ -31,7 +31,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; -import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; @@ -84,6 +83,16 @@ this((Map) ImmutableMap.copyOf(properties)); } + public AbstractTopiaApplicationContext(Map<String, String> configuration) { + Map<String, String> configurationCopy = Maps.newHashMap(); + configurationCopy.putAll(configuration); + if ( ! configuration.containsKey(TopiaContextFactory.CONFIG_PERSISTENCE_CLASSES)) { + configurationCopy.put(TopiaContextFactory.CONFIG_PERSISTENCE_CLASSES, getImplementationClassesAsString()); + } + this.configuration = ImmutableMap.copyOf(configurationCopy); + this.topiaServiceSupport = new TopiaServiceSupportImpl(this); + } + protected abstract Class<? extends TopiaEntity>[] getImplementationClasses(); protected String getImplementationClassesAsString() { @@ -94,15 +103,6 @@ return buffer.substring(1); } - public AbstractTopiaApplicationContext(Map<String, String> configuration) { - Map<String, String> configurationCopy = Maps.newHashMap(); - configurationCopy.putAll(configuration); - if ( ! configuration.containsKey(TopiaContextFactory.CONFIG_PERSISTENCE_CLASSES)) { - configurationCopy.put(TopiaContextFactory.CONFIG_PERSISTENCE_CLASSES, getImplementationClassesAsString()); - } - this.configuration = ImmutableMap.copyOf(configurationCopy); - } - protected HibernateProvider getHibernateProvider() { if (hibernateProvider == null) { hibernateProvider = new HibernateProvider(configuration, topiaServiceSupport); @@ -110,10 +110,6 @@ return hibernateProvider; } - protected SessionFactory getSessionFactory() { - return getHibernateProvider().getSessionFactory(); - } - protected TopiaListenableSupport getTopiaListenableSupport() { return topiaFiresSupport; } Modified: trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java 2013-10-11 15:13:30 UTC (rev 2840) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/AbstractTopiaPersistenceContext.java 2013-10-11 16:47:08 UTC (rev 2841) @@ -58,61 +58,79 @@ /** * Already loaded DAO cache within this persistence context */ - protected Map<Class<? extends TopiaEntity>, TopiaDAO<? extends TopiaEntity>> daoCache = Maps.newHashMap(); // TODO AThimel 27/09/13 Concurrent map ? + protected Map<Class<? extends TopiaEntity>, TopiaDAO<? extends TopiaEntity>> daoCache = Maps.newConcurrentMap(); // TODO AThimel 27/09/13 Javadoc + protected TopiaListenableSupport listenableSupport; + + /** + * Used to affect a new topiaId when create is called. + */ + protected TopiaIdFactory topiaIdFactory; + + // TODO AThimel 27/09/13 Javadoc protected TopiaFiresSupport firesSupport; - // TODO AThimel 27/09/13 Javadoc + /** + * This subclass of TopiaHibernateSupport is made to be used only internally within this persistence context. This + * instance is created by the persistence context itself. + */ protected InternalTopiaHibernateSupport hibernateSupport; - // TODO AThimel 27/09/13 Javadoc + /** + * This instance of TopiaJpaSupport is created by the persistence context itself. It is actually using the + * TopiaHibernateSupport instance. + */ protected TopiaJpaSupport jpaSupport; - // TODO AThimel 27/09/13 Javadoc + /** + * This instance of TopiaSqlSupport is created by the persistence context itself. It is actually using the + * TopiaHibernateSupport instance. + */ protected TopiaSqlSupport sqlSupport; - // TODO AThimel 27/09/13 Javadoc - protected TopiaListenableSupport listenableSupport; - /** - * Used to affect a new topiaId when create is called. - * - * @since 3.0 + * Flog used to check if this persistence context is closed */ - protected TopiaIdFactory topiaIdFactory; - protected boolean closed = false; /** * Creating a new TopiaPersistenceContext is equivalent to creating a new transaction * - * @param hibernateProvider - * @param listenableSupport - * @param topiaIdFactory // * @param config + * @param hibernateProvider holds the Hibernate configuration and session factory + * @param listenableSupport the listenableSupport instance to use within this persistence context + * @param topiaIdFactory the TopiaIdFactory instance created according to the application's configuration */ public AbstractTopiaPersistenceContext(HibernateProvider hibernateProvider, TopiaListenableSupport listenableSupport, TopiaIdFactory topiaIdFactory) { - Session hibernateSession = startTransaction(hibernateProvider); - this.hibernateSupport = new InternalTopiaHibernateSupport(hibernateProvider, hibernateSession); - // TODO brendan 11/10/13 init this.sqlSupport this.listenableSupport = listenableSupport; this.topiaIdFactory = topiaIdFactory; + // Hibernate support can be created using the given hibernateProvider + this.hibernateSupport = new InternalTopiaHibernateSupport(hibernateProvider); + + // Now starts the transaction, as this persistenceContext IS the TopiaTransaction + startTransaction(); + + // Create the different supports that may be needed by the DAOs this.firesSupport = new TopiaFiresSupport(); this.jpaSupport = new HibernateTopiaJpaSupport(hibernateSupport, firesSupport); + this.sqlSupport = new HibernateTopiaSqlSupport(hibernateSupport); } + /** + * This subclass of TopiaHibernateSupport is made to be used only internally within this persistence context. This + * class only acts as an information container (as a structure does). + */ protected class InternalTopiaHibernateSupport implements TopiaHibernateSupport { protected HibernateProvider hibernateProvider; protected Session hibernateSession; - protected InternalTopiaHibernateSupport(HibernateProvider hibernateProvider, Session hibernateSession) { + protected InternalTopiaHibernateSupport(HibernateProvider hibernateProvider) { this.hibernateProvider = hibernateProvider; - this.hibernateSession = hibernateSession; } public void setHibernateSession(Session hibernateSession) { @@ -121,6 +139,7 @@ @Override public Session getHibernateSession() { + Preconditions.checkState(hibernateSession != null, "Session is not yet initialized"); return hibernateSession; } @@ -135,10 +154,11 @@ } } - protected Session startTransaction(HibernateProvider hibernateProvider) throws TopiaException { + protected void startTransaction() throws TopiaException { - SessionFactory factory = hibernateProvider.getSessionFactory(); + SessionFactory factory = hibernateSupport.getHibernateFactory(); Session result = factory.openSession(); + hibernateSupport.setHibernateSession(result); // new TopiaInterceptor(result)); // on ne synchronise jamais les données avec la base tant que @@ -173,7 +193,6 @@ // fire event getFiresSupport().fireOnBeginTransaction(this); - return result; } protected void checkClosed() throws TopiaException { @@ -216,10 +235,6 @@ public <E extends TopiaEntity> TopiaDAO<E> getDAO(Class<E> entityClass) { Preconditions.checkArgument(entityClass != null, "The method 'getDAO' requires a non null 'entityClass' parameter"); -// if (equals(getRootContext())) { -// throw new TopiaException( -// "You are on root context, you MUST open a transaction to perform any database access."); -// } SessionFactory hibernateFactory = hibernateSupport.getHibernateFactory(); if (hibernateFactory.getClassMetadata(entityClass) == null && hibernateFactory.getClassMetadata(entityClass.getName() + "Impl") == null && Modified: trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaJpaSupport.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaJpaSupport.java 2013-10-11 15:13:30 UTC (rev 2840) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaJpaSupport.java 2013-10-11 16:47:08 UTC (rev 2841) @@ -74,13 +74,6 @@ this.firesSupport = firesSupport; } - protected void checkClosed() throws TopiaException { - // TODO AThimel 27/09/13 IS it still useful ? -// if (closed) { -// throw new TopiaException("This jpaSupport is closed, it is not possible to use it anymore"); -// } - } - @Override public void setUseFlushMode(boolean useFlushMode) { this.useFlushMode = useFlushMode; @@ -108,8 +101,6 @@ @Override public <T> List<T> findAll(String jpaql, Map<String, Object> parameters) { - checkClosed(); - try { Query query = prepareQuery(jpaql, parameters); @@ -129,8 +120,6 @@ @Override public <T> List<T> find(String jpaql, int startIndex, int endIndex, Map<String, Object> parameters) { - checkClosed(); - try { Query query = prepareQuery(jpaql, parameters); @@ -154,8 +143,6 @@ @Override public int execute(String jpaql, Map<String, Object> parameters) { - checkClosed(); - try { Query query = prepareQuery(jpaql, parameters); Added: trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaSqlSupport.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaSqlSupport.java (rev 0) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaSqlSupport.java 2013-10-11 16:47:08 UTC (rev 2841) @@ -0,0 +1,73 @@ +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.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.hibernate.HibernateException; +import org.hibernate.jdbc.Work; + +/** + * @author Arnaud Thimel <thimel@codelutin.com> + */ +public class HibernateTopiaSqlSupport implements TopiaSqlSupport { + + protected TopiaHibernateSupport hibernateSupport; + + public HibernateTopiaSqlSupport(TopiaHibernateSupport hibernateSupport) { + this.hibernateSupport = hibernateSupport; + } + + @Override + public void executeSQL(String sqlScript) { + SQLWork sqlWork = new SQLWork(sqlScript); + try { + hibernateSupport.getHibernateSession().doWork(sqlWork); + } catch (HibernateException e) { + throw new TopiaException("Could not execute sql code", e); + } + } + + public static class SQLWork implements Work { + private final String script; + + public SQLWork(String script) { + this.script = script; + } + + @Override + public void execute(Connection connection) throws SQLException { + PreparedStatement sta = connection.prepareStatement(script); + try { + sta.execute(); + } finally { + sta.close(); + } + } + } + +} Property changes on: trunk/topia-persistence/src/main/java/org/nuiton/topia/HibernateTopiaSqlSupport.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Added: trunk/topia-persistence/src/main/java/org/nuiton/topia/TopiaServiceSupportImpl.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/TopiaServiceSupportImpl.java (rev 0) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/TopiaServiceSupportImpl.java 2013-10-11 16:47:08 UTC (rev 2841) @@ -0,0 +1,173 @@ +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.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.framework.TopiaService; + +import com.google.common.collect.ImmutableMap; + +/** + * FIXME AThimel 11/10/13 All this life-cycle has to be reviewed + * + * @author Arnaud Thimel <thimel@codelutin.com> + */ +public class TopiaServiceSupportImpl implements TopiaServiceSupport { + + private static final Log log = LogFactory.getLog(TopiaServiceSupportImpl.class); + + protected ImmutableMap<String, TopiaService> services; + protected AbstractTopiaApplicationContext applicationContext; + + public TopiaServiceSupportImpl(AbstractTopiaApplicationContext applicationContext) { + this.applicationContext = applicationContext; + this.services = loadServices(applicationContext.getConfiguration()); + preInitServices(this.services); + applicationContext.getHibernateProvider().getHibernateConfiguration(); // force mapping loading + postInitServices(this.services); + } + + protected void preInitServices(Map<String, TopiaService> services) { + for (TopiaService service : services.values()) { + if (!service.preInit(null)) { // TODO AThimel 11/10/13 was: this (aka TopiaContext) + log.warn(String.format("The service named '%1$s' could not be post-initialized (service not activated)", + service.getServiceName())); + } + } + } + + protected void postInitServices(Map<String, TopiaService> services) { + for (TopiaService service : services.values()) { + if (!service.postInit(null)) { // TODO AThimel 11/10/13 was: this (aka TopiaContext) + log.warn(String.format("The service named '%1$s' could not be pre-initialized (service not activated)", + service.getServiceName())); + } + } + } + + /** + * Retrieve service name using SERVICE_NAME static field on service + * interface. + * + * @param interfaceService class of the service + * @param <E> type of the service that extends {@link + * TopiaService} + * @return the service name + * @throws IllegalAccessException if field SERVICE_NAME can't be accessed + * @throws NoSuchFieldException if no field SERVICE_NAME is defined + */ + protected <E extends TopiaService> String getServiceName( + Class<E> interfaceService) + throws IllegalAccessException, NoSuchFieldException { + Field f = interfaceService.getField("SERVICE_NAME"); + String name = (String) f.get(null); + return name; + } + + protected String getProperExceptionMessage(Throwable eee) { + return eee.getClass().getSimpleName() + " : " + eee.getMessage(); + } + + protected ImmutableMap<String, TopiaService> loadServices(ImmutableMap<String, String> configuration) { + Map<String, TopiaService> result = new HashMap<String, TopiaService>(); + // recherche des services present dans la config + for (String key : result.keySet()) { + if (key.matches("^topia\\.service\\.\\w+$")) { + String serviceClass = configuration.get(key); + try { + Class<?> forName = Class.forName(serviceClass); + Object newInstance = forName.getConstructor().newInstance(); + TopiaService service = (TopiaService) newInstance; + if (key.equals("topia.service." + service.getServiceName())) { + result.put(service.getServiceName(), service); + log.info(String.format("Service '%1$s' loaded (implementation %2$s)", + key, serviceClass)); + } else { + log.warn(String.format("The service with key '%1$s' has a different name '%2$s'! (service not activated)", + key, service.getServiceName())); + } + } catch (Throwable eee) { + String message = + String.format("The service %1$s of type %2$s was not found.", + key, serviceClass); + if (log.isDebugEnabled()) { + log.debug(message, eee); + } else if (log.isErrorEnabled()) { + log.error(message); + } + } + } + } + return ImmutableMap.copyOf(result); + } + + + @Override + public <E extends TopiaService> boolean serviceEnabled(Class<E> interfaceService) { + boolean result = false; + try { + String name = getServiceName(interfaceService); + result = getServices().containsKey(name); + } catch (Exception eee) { + String format = "The service named '%1$s' could not be found for following reason: %2$s"; + String message = String.format(format, interfaceService, getProperExceptionMessage(eee)); + if (log.isDebugEnabled()) { + log.debug(message, eee); + } else if (log.isWarnEnabled()) { + log.warn(message); + } + } + return result; + } + + @Override + public <E extends TopiaService> E getService(Class<E> interfaceService) throws TopiaNotFoundException { + E result; + try { + String name = getServiceName(interfaceService); + result = (E) getServices().get(name); + } catch (Exception eee) { + String format = "Could not retreave service %1$s for following reason: %2$s"; + String message = String.format(format, interfaceService, getProperExceptionMessage(eee)); + throw new TopiaNotFoundException(message, eee); + } + if (result == null) { + String message = String.format("The service %1$s was not found.", interfaceService); + throw new TopiaNotFoundException(message); + } + return result; + } + + @Override + public Map<String, TopiaService> getServices() { + return services; + } + +} Property changes on: trunk/topia-persistence/src/main/java/org/nuiton/topia/TopiaServiceSupportImpl.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native