Index: topia2/src/java/org/codelutin/topia/framework/TopiaContextImpl.java
diff -u /dev/null topia2/src/java/org/codelutin/topia/framework/TopiaContextImpl.java:1.1
--- /dev/null Wed Jan 4 13:24:40 2006
+++ topia2/src/java/org/codelutin/topia/framework/TopiaContextImpl.java Wed Jan 4 13:24:35 2006
@@ -0,0 +1,445 @@
+/*
+ * *##% Copyright (C) 2005 Code Lutin, Cédric Pineau, Benjamin Poussin
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 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 Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA. ##%
+ */
+
+/*******************************************************************************
+ * TopiaContextImpl.java
+ *
+ * Created: 23 déc. 2005 16:58:50
+ *
+ * @author poussin
+ *
+ * @version $Revision: 1.1 $
+ *
+ * Last update: $Date: 2006/01/04 13:24:35 $ by : $Author: bpoussin $
+ */
+
+package org.codelutin.topia.framework;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codelutin.topia.TopiaContext;
+import org.codelutin.topia.TopiaException;
+import org.codelutin.topia.TopiaNotFoundException;
+import org.codelutin.topia.event.TopiaEntityEvent;
+import org.codelutin.topia.event.TopiaEntityListener;
+import org.codelutin.topia.persistence.TopiaDAO;
+import org.codelutin.topia.persistence.TopiaDAODelegator;
+import org.codelutin.topia.persistence.TopiaEntity;
+import org.codelutin.util.CategorisedListenerSet;
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.type.Type;
+
+/**
+ * Le TopiaContextImpl est le point d'entre pour acceder aux donnees. Il est
+ * configurer par un fichier de propriete
+ *
+ * List des proprietes disponible
+ *
+ * - topia.persistence.properties.file
+ *
- le fichier de propriété a utiliser pour configurer hibernate
+ *
+ *
- topia.persistence.directories
+ *
- la liste des repertoires contenant les mappings hibernates (.hbm.xml) la
+ * liste de repertoire est separer par des virgules ','
+ *
+ *
- topia.persistence.classes
+ *
- la liste des classes que doit géré hibernate. On peut tres bien utiliser
+ * topia.persistence.directories pour un ensemble d'entié du meme repertoire et
+ * topia.persistence.classes pour d'autres classes
+ *
+ *
+ * @author poussin
+ *
+ */
+public class TopiaContextImpl implements TopiaContext, TopiaContextImplementor {
+
+ /** to use log facility, just put in your code: log.info(\"...\"); */
+ static private Log log = LogFactory.getLog(TopiaContextImpl.class);
+
+ static final private String TOPIA_PERSISTENCE_DIRECTORIES = "topia.persistence.directories";
+
+ static final private String TOPIA_PERSISTENCE_CLASSES = "topia.persistence.classes";
+
+ static final private String TOPIA_PERSISTENCE_PROPERTIES_FILE = "topia.persistence.properties.file";
+
+ /**
+ * Le pere de ce context, les contexts initaux n'ont pas de context pere
+ */
+ protected TopiaContextImplementor parentContext = null;
+
+ /**
+ * la factory permettant de recuperer la session hibernate. Seul les
+ * TopiaContextImpl initiaux contiennent un hibernateFactory
+ */
+ protected SessionFactory hibernateFactory = null;
+
+ /**
+ * La session utilisé par le TopiaContextImpl
+ */
+ protected Session hibernate = null;
+
+ /**
+ * Propriete de configuration
+ */
+ protected Properties config = null;
+
+ /**
+ * cache des DAO deja chargé pour ce context
+ */
+ protected Map daoCache = new HashMap();
+
+ /**
+ * Set des sous context creer avec un beginTransaction et donc sur lequel
+ * nous sommes listener
+ */
+ protected Set childContext = new HashSet();
+
+ protected CategorisedListenerSet listeners = new CategorisedListenerSet(
+ TopiaEntityListener.class);
+
+
+ /**
+ * constructeur utilisé par la factory pour creer les contexts initiaux
+ *
+ * @param config
+ */
+ public TopiaContextImpl(Properties config) {
+ this.config = config;
+ }
+
+ /**
+ * Constructeur utilisé par le beginTransaction pour créer le context fils.
+ *
+ * @param config la configuration du
+ * @param parentContext
+ * @throws HibernateException
+ * @throws TopiaNotFoundException
+ */
+ protected TopiaContextImpl(TopiaContextImplementor parentContext)
+ throws HibernateException, TopiaNotFoundException {
+ this.parentContext = parentContext;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getParentContext()
+ */
+ public TopiaContextImplementor getParentContext() {
+ return parentContext;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getRootContext()
+ */
+ public TopiaContextImplementor getRootContext() {
+ TopiaContextImplementor result = this;
+ if (getParentContext() != null) {
+ result = getParentContext().getRootContext();
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getConfig()
+ */
+ public Properties getConfig() {
+ if (config == null && getParentContext() != null) {
+ config = getParentContext().getConfig();
+ }
+ return config;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getHibernate()
+ */
+ public Session getHibernate() throws TopiaException {
+ if (hibernate == null) {
+ throw new TopiaException(
+ "No hibernate session available, you must start transaction with beginTransaction");
+ }
+ return hibernate;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getHibernateFactory()
+ */
+ public SessionFactory getHibernateFactory()
+ throws TopiaNotFoundException {
+ if (hibernateFactory == null) {
+ if (getParentContext() != null) {
+ hibernateFactory = getParentContext().getHibernateFactory();
+ } else {
+ Configuration cfg = new Configuration();
+
+ // ajout des repertoires contenant les mappings hibernate
+ String[] dirs = getConfig().getProperty(
+ TOPIA_PERSISTENCE_DIRECTORIES, "").split(",");
+ for (String dir : dirs) {
+ dir = dir.trim();
+ if (!"".equals(dir)) {
+ cfg.addDirectory(new File(dir));
+ }
+ }
+
+ // ajout des classes dites persistentes
+ String[] classes = getConfig().getProperty(
+ TOPIA_PERSISTENCE_CLASSES, "").split(",");
+ for (String classname : classes) {
+ classname = classname.trim();
+ if (!"".equals(classname)) {
+ Class clazz;
+ try {
+ clazz = Class.forName(classname);
+ } catch (ClassNotFoundException eee) {
+ throw new TopiaNotFoundException(
+ "Persistent class " + classname
+ + " not found");
+ }
+ cfg.addClass(clazz);
+ }
+ }
+
+ Properties prop = new Properties();
+ prop.putAll(cfg.getProperties());
+ prop.putAll(getConfig());
+ prop.putAll(TopiaUtil.getProperties(getConfig().getProperty(
+ TOPIA_PERSISTENCE_PROPERTIES_FILE)));
+ cfg.setProperties(prop);
+
+ hibernateFactory = cfg.buildSessionFactory();
+ }
+ }
+ return hibernateFactory;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getDAO(java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ public TopiaDAO getDAO(Class entityClass) throws TopiaException {
+ if (getRootContext() == this) {
+ throw new TopiaException("Vous êtes sur le root context vous devez ouvrir une transaction pour pouvoir accèder aux données");
+ }
+ TopiaDAO result = (TopiaDAO) daoCache.get(entityClass);
+ if (result == null) {
+ // recherche du type de DAO a instancier pour cette entity
+ String defaultDAOClassname = getConfig().getProperty("topia.dao.default.class", "hibernate");
+ String daoClassname = getConfig().getProperty("topia.dao." + entityClass.getName(), defaultDAOClassname);
+ if ("hibernate".equals(daoClassname)) {
+ daoClassname = "org.codelutin.topia.persistence.hibernate.TopiaDAOHibernate";
+ } else if ("flatfile".equals(daoClassname)) {
+ daoClassname = "org.codelutin.topia.persistence.flatfile.TopiaDAOFlatFile";
+ }
+
+ try {
+ Class> resultClass = (Class>)Class.forName(daoClassname);
+ result = resultClass.newInstance();
+ result.init(this, entityClass);
+ } catch (ClassNotFoundException eee) {
+ throw new TopiaException("Can't find DAO class " + daoClassname);
+ } catch (InstantiationException eee) {
+ throw new TopiaException("Can't instanciate DAO class " + daoClassname);
+ } catch (IllegalAccessException eee) {
+ throw new TopiaException("Can't access DAO class " + daoClassname);
+ }
+
+ // looking for specialized DAO
+ // normalement il en existe un car il est généré automatiquement
+ // si on utilise la génération
+ daoClassname = entityClass.getName() + "DAO";
+ try {
+ Class> daoClass = (Class>) Class
+ .forName(daoClassname);
+ TopiaDAODelegator spe = daoClass.newInstance();
+ spe.setParentDAO(result);
+ result = spe;
+ } catch (Exception eee) {
+ log.warn("specialized DAO " + daoClassname
+ + " not found, use default TopiaDAOHibernate");
+ }
+ daoCache.put(entityClass, result);
+ // si quelqu'un se met listener sur le TopiaContext, il faut qu'il
+ // soit prevenu des evenements de tout type d'entite
+ getListeners().addCategory(TopiaContext.class, entityClass);
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#getListeners()
+ */
+ public CategorisedListenerSet getListeners() {
+ return listeners;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.TopiaContext#addTopiaEntityListener(org.codelutin.topia.event.TopiaEntityListener)
+ */
+ public void addTopiaEntityListener(TopiaEntityListener l) {
+ getListeners().add(this.getClass(), l);
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.TopiaContext#removeTopiaEntityListener(org.codelutin.topia.event.TopiaEntityListener)
+ */
+ public void removeTopiaEntityListener(TopiaEntityListener l) {
+ getListeners().remove(this.getClass(), l);
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.TopiaContext#beginTransaction()
+ */
+ public TopiaContext beginTransaction() throws TopiaNotFoundException {
+ TopiaContextImpl result = new TopiaContextImpl(this);
+ childContext.add(result);
+ result.hibernate = getHibernateFactory().openSession(new TopiaInterceptor(result));
+ // on ne synchronise jamais les données avec la base tant que
+ // l'utilisateur n'a pas fait de commit du context
+ result.hibernate.setFlushMode(FlushMode.NEVER);
+
+ // TODO se mettre listener sur ce context
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.TopiaContext#commitTransaction()
+ */
+ public void commitTransaction() throws TopiaException {
+ try {
+ for(TopiaDAO dao : daoCache.values()) {
+ dao.commitTransaction();
+ }
+ Transaction tx = hibernate.beginTransaction();
+ hibernate.flush();
+ tx.commit();
+ fireOnCommited();
+ } catch (HibernateException eee) {
+ throw new TopiaException(eee);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.TopiaContext#rollbackTransaction()
+ */
+ public void rollbackTransaction() throws TopiaException {
+ try {
+ for(TopiaDAO dao : daoCache.values()) {
+ dao.rollbackTransaction();
+ }
+ Transaction tx = hibernate.beginTransaction();
+ hibernate.clear();
+ tx.rollback();
+ fireOnRollbacked();
+ } catch (HibernateException eee) {
+ throw new TopiaException(eee);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#fireOnCreated(java.lang.Object)
+ */
+ public void fireOnCreated(Object entity) {
+ log.info("onCreated " + entity);
+ try {
+ getListeners().fire(entity.getClass(), "entityCreated", new TopiaEntityEvent(this, entity));
+ } catch (Exception eee) {
+ if (log.isWarnEnabled()) {
+ log.warn("Can't fire event created for entity: " + entity, eee);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#fireOnUpdated(java.lang.Object)
+ */
+ public void fireOnUpdated(Object entity) {
+ log.info("onUpdated " + entity);
+ try {
+ getListeners().fire(entity.getClass(), "entityUpdated", new TopiaEntityEvent(this, entity));
+ } catch (Exception eee) {
+ if (log.isWarnEnabled()) {
+ log.warn("Can't fire event updated for entity: " + entity, eee);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#fireOnDeleted(java.lang.Object)
+ */
+ public void fireOnDeleted(Object entity) {
+ log.info("onDeleted " + entity);
+ try {
+ getListeners().fire(entity.getClass(), "entityDeleted", new TopiaEntityEvent(this, entity));
+ } catch (Exception eee) {
+ if (log.isWarnEnabled()) {
+ log.warn("Can't fire event deleted for entity: " + entity, eee);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#fireOnCommited()
+ */
+ public void fireOnCommited() {
+ log.info("onCommited");
+ // TODO
+ }
+
+ /* (non-Javadoc)
+ * @see org.codelutin.topia.framework.TopiaContextImplementor#fireOnRollbacked()
+ */
+ public void fireOnRollbacked() {
+ log.info("onRollbacked");
+ // TODO
+ }
+
+ static protected class TopiaInterceptor extends EmptyInterceptor {
+
+ protected TopiaContextImplementor context = null;
+
+ private static final long serialVersionUID = -6787010517746197446L;
+
+ public TopiaInterceptor(TopiaContextImplementor context) {
+ this.context = context;
+ }
+
+ public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types){
+ super.onDelete(entity, id, state, propertyNames, types);
+ context.fireOnDeleted(entity);
+ }
+ public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
+ boolean result = super.onSave(entity, id, state, propertyNames, types);
+ context.fireOnUpdated(entity);
+ return result;
+ }
+ }
+}
Index: topia2/src/java/org/codelutin/topia/framework/TopiaContextImplementor.java
diff -u /dev/null topia2/src/java/org/codelutin/topia/framework/TopiaContextImplementor.java:1.1
--- /dev/null Wed Jan 4 13:24:40 2006
+++ topia2/src/java/org/codelutin/topia/framework/TopiaContextImplementor.java Wed Jan 4 13:24:35 2006
@@ -0,0 +1,104 @@
+/* *##%
+ * Copyright (C) 2006
+ * Code Lutin, Cédric Pineau, Benjamin Poussin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *##%*/
+
+/* *
+ * TopiaContextImplementor.java
+ *
+ * Created: 3 janv. 2006 21:27:24
+ *
+ * @author poussin
+ * @version $Revision: 1.1 $
+ *
+ * Last update: $Date: 2006/01/04 13:24:35 $
+ * by : $Author: bpoussin $
+ */
+
+package org.codelutin.topia.framework;
+
+import java.util.Properties;
+
+import org.codelutin.topia.TopiaContext;
+import org.codelutin.topia.TopiaException;
+import org.codelutin.topia.TopiaNotFoundException;
+import org.codelutin.topia.persistence.TopiaDAO;
+import org.codelutin.topia.persistence.TopiaEntity;
+import org.codelutin.util.CategorisedListenerSet;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+/**
+ * @author poussin
+ *
+ */
+
+public interface TopiaContextImplementor extends TopiaContext {
+
+ /**
+ * @return Returns the parentContext.
+ */
+ public TopiaContextImplementor getParentContext();
+
+ public TopiaContextImplementor getRootContext();
+
+ /**
+ * @return Returns the config.
+ */
+ public Properties getConfig();
+
+ /**
+ * @return Returns the hibernate.
+ * @throws TopiaException si aucune transaction n'est ouverte
+ */
+ public Session getHibernate() throws TopiaException;
+
+ /**
+ * @return Returns the hibernateFactory.
+ * @throws TopiaNotFoundException
+ */
+ public SessionFactory getHibernateFactory() throws TopiaNotFoundException;
+
+ /**
+ * Get DAO for specified class. If Specialized DAO exists then it returned
+ * otherwize TopiaDAO<entityClass> is returned
+ *
+ * @param
+ * @param entityClass
+ * @return
+ * @throws TopiaException
+ */
+ @SuppressWarnings("unchecked")
+ public TopiaDAO getDAO(Class entityClass)
+ throws TopiaException;
+
+ /**
+ * Retourne tous les listeners
+ */
+ public CategorisedListenerSet getListeners();
+
+ public void fireOnCreated(Object entity);
+
+ public void fireOnUpdated(Object entity);
+
+ public void fireOnDeleted(Object entity);
+
+ public void fireOnCommited();
+
+ public void fireOnRollbacked();
+
+}
Index: topia2/src/java/org/codelutin/topia/framework/TopiaUtil.java
diff -u /dev/null topia2/src/java/org/codelutin/topia/framework/TopiaUtil.java:1.1
--- /dev/null Wed Jan 4 13:24:40 2006
+++ topia2/src/java/org/codelutin/topia/framework/TopiaUtil.java Wed Jan 4 13:24:35 2006
@@ -0,0 +1,95 @@
+/*
+ * *##% Copyright (C) 2005 Code Lutin, Cédric Pineau, Benjamin Poussin
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 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 Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA. ##%
+ */
+
+/*******************************************************************************
+ * TopiaUtil.java
+ *
+ * Created: 28 déc. 2005 20:28:57
+ *
+ * @author poussin
+ *
+ * @version $Revision: 1.1 $
+ *
+ * Last update: $Date: 2006/01/04 13:24:35 $ by : $Author: bpoussin $
+ */
+
+package org.codelutin.topia.framework;
+
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codelutin.topia.TopiaNotFoundException;
+import org.codelutin.util.RecursiveProperties;
+import org.codelutin.util.Resource;
+
+/**
+ * @author poussin
+ *
+ */
+public class TopiaUtil {
+
+ /** to use log facility, just put in your code: log.info(\"...\"); */
+ static private Log log = LogFactory.getLog(TopiaUtil.class);
+
+ /**
+ * Permet de récupérer le fichier de propriété ayant le nom passé
+ * en argument.
+ *
+ * @param pathOrUrl le nom du fichier de propriété à charger, s'il est null
+ * ou vide retourne un objet Properties vide.
+ * @return Un nouvel objet de propriete
+ * @throws TopiaNotFoundException Si pathOrUrl n'est pas null ou vide et que
+ * le fichier devant contenir les propriétés n'est pas retrouvé.
+ */
+ static public Properties getProperties(String pathOrUrl) throws TopiaNotFoundException {
+ return getProperties(null, pathOrUrl);
+ }
+
+ /**
+ * Permet de récupérer le fichier de propriété ayant le nom passé
+ * en argument.
+ *
+ * @param parent l'objet properties utilisé comme parent de l'objet retourné
+ * @param pathOrUrl le nom du fichier de propriété à charger, s'il est null
+ * ou vide retourne un objet Properties vide.
+ * @return Un nouvel objet de propriete
+ * @throws TopiaNotFoundException Si pathOrUrl n'est pas null ou vide et que
+ * le fichier devant contenir les propriétés n'est pas retrouvé.
+ */
+ static public Properties getProperties(Properties parent, String pathOrUrl)
+ throws TopiaNotFoundException {
+ Properties result = new RecursiveProperties(parent);
+
+ // load properties for helper
+ if (pathOrUrl != null && !pathOrUrl.equals("")) {
+ try {
+ URL propURL = Resource.getURL(pathOrUrl);
+ log.info("Properties file used for " + pathOrUrl + " is: "
+ + propURL);
+ result.load(propURL.openStream());
+ } catch (Exception eee) {
+ throw new TopiaNotFoundException(
+ "Properties file can't be found: " + pathOrUrl, eee);
+ }
+ }
+ return result;
+ }
+
+}