Index: topia/src/java/org/codelutin/topia/persistence/PersistenceStorage.java diff -u topia/src/java/org/codelutin/topia/persistence/PersistenceStorage.java:1.2 topia/src/java/org/codelutin/topia/persistence/PersistenceStorage.java:1.3 --- topia/src/java/org/codelutin/topia/persistence/PersistenceStorage.java:1.2 Wed Jul 20 12:49:52 2005 +++ topia/src/java/org/codelutin/topia/persistence/PersistenceStorage.java Thu Jul 21 16:51:39 2005 @@ -23,9 +23,9 @@ * Created: 16 juillet 2005 23:40:21 CEST * * @author Benjamin POUSSIN - * @version $Revision: 1.2 $ + * @version $Revision: 1.3 $ * - * Last update: $Date: 2005/07/20 12:49:52 $ + * Last update: $Date: 2005/07/21 16:51:39 $ * by : $Author: bpoussin $ */ @@ -51,37 +51,37 @@ /** * Demande la sauvegarde de l'entité dans le context de la transaction */ - public void store(TopiaTransaction tt, TopiaPersistenceObject tpo); + public void store(TopiaTransaction tt, TopiaPersistenceObject tpo) throws TopiaPersistenceException; /** * Demande la restauration de l'entité dans le context de la transaction */ - public void restore(TopiaTransaction tt, TopiaPersistenceObject tpo); + public void restore(TopiaTransaction tt, TopiaPersistenceObject tpo) throws TopiaPersistenceException; /** * Retourne tous les id de tous les objets encore existant dans le * context de la transaction */ - public Collection getAllId(TopiaTransaction tt); + public Collection getAllId(TopiaTransaction tt) throws TopiaPersistenceException; /** * Permet d'indiquer au storage le debut d'une transaction */ - public void beginTransaction(TopiaTransaction tt); + public void beginTransaction(TopiaTransaction tt) throws TopiaPersistenceException; /** * Indique au storage de commiter la transaction passé en paramètre. * @return la nouvelle transaction utilisable pour de futurs appels au storage * car l'ancienne transaction n'est plus valide */ - public TopiaTransaction commitTransaction(TopiaTransaction tt); + public TopiaTransaction commitTransaction(TopiaTransaction tt) throws TopiaPersistenceException; /** * Indique au storage de faire un rollback de la transaction passé en paramètre. * @return la nouvelle transaction utilisable pour de futurs appels au storage * car l'ancienne transaction n'est plus valide */ - public TopiaTransaction rollbackTransaction(TopiaTransaction tt); + public TopiaTransaction rollbackTransaction(TopiaTransaction tt) throws TopiaPersistenceException; /** * Indique si le storage implante une methode de recherche rapide @@ -95,12 +95,12 @@ * il faut que haveFindImplemented return false, et que cette méthode * leve l'exception UnsupportedOperationException */ - public List find(TopiaTransaction tt, TopiaQuery query); + public List find(TopiaTransaction tt, TopiaQuery query) throws TopiaPersistenceException; /** * Retourne l'historique de l'objet ayant l'id passé en paramètre */ - public List getHistory(TopiaTransaction tt, String id); + public List getHistory(TopiaTransaction tt, String id) throws TopiaPersistenceException; /** * Nettoie l'historique pour ne conserver qu'une profondeur d'historique @@ -108,12 +108,12 @@ * en cours doit avoir toujours au moins la vision convenable de toutes * les entités. */ - public void cleanHistory(int depth); + public void cleanHistory(int depth) throws TopiaPersistenceException; /** * Permet de savoir si un id existe encore dans le context de la transaction */ - public boolean exists(TopiaTransaction tt, String id); + public boolean exists(TopiaTransaction tt, String id) throws TopiaPersistenceException; } // PersistenceStorage Index: topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceHelper.java diff -u topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceHelper.java:1.2 topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceHelper.java:1.3 --- topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceHelper.java:1.2 Wed Jul 20 12:49:52 2005 +++ topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceHelper.java Thu Jul 21 16:51:39 2005 @@ -23,9 +23,9 @@ * Created: Jul 16, 2005 * * @author Benjamin POUSSIN - * @version $Revision: 1.2 $ + * @version $Revision: 1.3 $ * - * Last update : $Date: 2005/07/20 12:49:52 $ + * Last update : $Date: 2005/07/21 16:51:39 $ * by : $Author: bpoussin $ */ @@ -159,7 +159,7 @@ // il faut remettre le meme id tpo.getManagement().setId(entity.get_topiaId_()); // l'objet n'est plus supprimé s'il l'etait - tpo.getManagement().setDelete(false); + tpo.getManagement().setDeleted(false); getStorage().store(getContext().getTransaction(), tpo); return result; @@ -205,7 +205,7 @@ } TopiaPersistenceObject tpo = tpp.getObject(); - tpo.getManagement().setDelete(true); + tpo.getManagement().setDeleted(true); getStorage().store(getContext().getTransaction(), tpo); } @@ -271,7 +271,7 @@ if(result == null){ Class entityClass = TopiaId.getClassName(id); TopiaPersistenceObject tpo = new TopiaPersistenceObject(id); - tpo.getManagement().setDate(getContext().getTransaction().getId()); + tpo.getManagement().setSchemaVersion(getSchemaVersion(entityClass)); result = TopiaPersistenceProxy.newProxy(this, entityClass, tpo); getCache().put(id, result); } Index: topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObject.java diff -u topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObject.java:1.2 topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObject.java:1.3 --- topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObject.java:1.2 Wed Jul 20 12:49:52 2005 +++ topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObject.java Thu Jul 21 16:51:39 2005 @@ -23,9 +23,9 @@ * Created: 16 juillet 2005 23:44:18 CEST * * @author Benjamin POUSSIN - * @version $Revision: 1.2 $ + * @version $Revision: 1.3 $ * - * Last update: $Date: 2005/07/20 12:49:52 $ + * Last update: $Date: 2005/07/21 16:51:39 $ * by : $Author: bpoussin $ */ @@ -107,11 +107,13 @@ } public void setField(String fieldName, Object value){ - getData().setField(fieldName, value); - // on vient de modifier le champs donc s'il etait demandé ce n'est plus - // la peine de le recuperer - modifiedFields.add(fieldName); - askedFields.remove(fieldName); + synchronized(getModifiedFields()){ + getData().setField(fieldName, value); + // on vient de modifier le champs donc s'il etait demandé + //ce n'est plus la peine de le recuperer + modifiedFields.add(fieldName); + askedFields.remove(fieldName); + } } } // TopiaPersistenceObject Index: topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObjectManagementData.java diff -u topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObjectManagementData.java:1.2 topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObjectManagementData.java:1.3 --- topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObjectManagementData.java:1.2 Wed Jul 20 12:49:52 2005 +++ topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceObjectManagementData.java Thu Jul 21 16:51:39 2005 @@ -23,9 +23,9 @@ * Created: 16 juillet 2005 23:46:51 CEST * * @author Benjamin POUSSIN - * @version $Revision: 1.2 $ + * @version $Revision: 1.3 $ * - * Last update: $Date: 2005/07/20 12:49:52 $ + * Last update: $Date: 2005/07/21 16:51:39 $ * by : $Author: bpoussin $ */ @@ -83,7 +83,7 @@ public boolean isDeleted(){ return state.contains(State.DELETED); } - public void setDelete(boolean v){ + public void setDeleted(boolean v){ if(v){ state.add(State.DELETED); } else { @@ -102,7 +102,7 @@ } } - public boolean Unloaded(){ + public boolean isUnloaded(){ return state.isEmpty(); } Index: topia/src/java/org/codelutin/topia/persistence/PersistenceStorageJDBC.java diff -u /dev/null topia/src/java/org/codelutin/topia/persistence/PersistenceStorageJDBC.java:1.1 --- /dev/null Thu Jul 21 16:51:44 2005 +++ topia/src/java/org/codelutin/topia/persistence/PersistenceStorageJDBC.java Thu Jul 21 16:51:39 2005 @@ -0,0 +1,553 @@ +/* *##% + * 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. + *##%*/ + +/* * + * PersistenceStorageJDBC.java + * + * Created: 20 juillet 2005 15:25:06 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/07/21 16:51:39 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.topia.persistence; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.Properties; +import org.apache.commons.dbcp.ConnectionFactory; +import org.apache.commons.dbcp.DriverManagerConnectionFactory; +import org.apache.commons.dbcp.PoolableConnectionFactory; +import org.apache.commons.dbcp.PoolingDriver; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.apache.commons.pool.impl.StackKeyedObjectPoolFactory; +import org.codelutin.topia.TopiaConst; +import org.codelutin.topia.TopiaException; +import org.codelutin.topia.TopiaId; +import org.codelutin.topia.TopiaQuery; +import org.codelutin.topia.Util; + +/** +* Storage implante sur JDBC. +*

+* propriétés: +*

  • persistence.storage.jdbc.driver +*
  • persistence.storage.jdbc.url +*
  • persistence.storage.jdbc.login +*
  • persistence.storage.jdbc.password +*/ +public class PersistenceStorageJDBC implements PersistenceStorage { // PersistenceStorageJDBC + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Logger log = Logger.getLogger("org.codelutin.topia.persistence.PersistenceStorageJDBC"); + + static private final String TABLE_MANAGEMENT = "management"; + static private final String TABLE_MANAGEMENT_FIELD_ID = "id"; + static private final String TABLE_MANAGEMENT_FIELD_DATE = "date"; + static private final String TABLE_MANAGEMENT_FIELD_CLASS = "class"; + static private final String TABLE_MANAGEMENT_FIELD_ISNEW = "isNew"; + static private final String TABLE_MANAGEMENT_FIELD_ISDELETED = "isDeleted"; + static private final String TABLE_MANAGEMENT_FIELD_SCHEMAVERSION = "schemaVersion"; + + static private final String TABLE_DATA = "data"; + static private final String TABLE_DATA_FIELD_ID = "id"; + static private final String TABLE_DATA_FIELD_DATE = "date"; + static private final String TABLE_DATA_FIELD_FIELD = "field"; + static private final String TABLE_DATA_FIELD_VALUE = "value"; + + /** charge tous les management existant pour un id, tri de facon a avoir + * la version la plus recente en premier dans le ResultSet. Le premier + * est celui de la transaction s'il exist sinon celui qui a la date la + * plus elevé mais ne depassant pas la transaction */ + static private final String SQL_LOAD_HISTORY = "SELECT * FROM " + TABLE_MANAGEMENT + " WHERE id=? AND ((date > 0 and date<=?) or date=?) order by abs(date) desc;"; + /** supprime les données de la table data */ + static private final String SQL_REMOVE_DATA = "DELETE " + TABLE_DATA + " WHERE id=? and date=?"; + /** retourne tous les id des objets existant non delete */ + static private final String SQL_GET_ALL_ID = "SELECT DISTINCT(id) FROM " + TABLE_MANAGEMENT + " WHERE (date=? OR (date>0 AND date<=?)) AND id NOT IN (SELECT id FROM " + TABLE_MANAGEMENT + " WHERE (date=? OR (date>0 AND date<=?)) AND isDeleted=true);"; + static private final String SQL_INSERT_DATA = "INSERT INTO " + TABLE_DATA + " VALUES (?, ?, ?, ?);"; + static private final String SQL_INSERT_MANAGEMENT = "INSERT INTO " + TABLE_MANAGEMENT + " VALUES (?, ?, ?, ?, ?, ?);"; + static private final String SQL_LOAD_DATA = "SELECT * FROM " + TABLE_DATA + " WHERE id=? AND date=?"; + static private final String SQL_LOAD_MANAGEMENT = "SELECT * FROM " + TABLE_MANAGEMENT + " WHERE id=? AND date=?"; + static private final String SQL_UPDATE_DATA = "UPDATE " + TABLE_DATA + " SET value=? WHERE id=? AND date=? AND filed=?;"; + static private final String SQL_UPDATE_SCHEMAVERSION = "UPDATE " + TABLE_MANAGEMENT + " SET schemaVersion=? WHERE id=? AND date=?;"; + static private final String SQL_ROLLBACK_MANAGEMENT = "DELETE " + TABLE_MANAGEMENT + " WHERE date=?"; + static private final String SQL_ROLLBACK_DATA = "DELETE " + TABLE_DATA + " WHERE date=?"; + static private final String SQL_COMMIT_MANAGEMENT = "UODATE " + TABLE_MANAGEMENT + "SET date=? WHERE date=?"; + static private final String SQL_COMMIT_DATA = "UODATE " + TABLE_DATA + "SET date=? WHERE date=?"; + + protected Properties properties = null; + protected DriverManagerConnectionFactory connectionPool = null; + + public PersistenceStorageJDBC(Properties properties) throws TopiaException { + this.properties = properties; + String driver = properties.getProperty(TopiaConst.PERSISTENCE_STORAGE_JDBC_DRIVER); + String url = properties.getProperty(TopiaConst.PERSISTENCE_STORAGE_JDBC_URL); + String login = properties.getProperty(TopiaConst.PERSISTENCE_STORAGE_JDBC_LOGIN); + String password = properties.getProperty(TopiaConst.PERSISTENCE_STORAGE_JDBC_PASSWORD); + + GenericObjectPool connectionPool = new GenericObjectPool(null); + ConnectionFactory connectionFactory = + new DriverManagerConnectionFactory(url, login, password); + StackKeyedObjectPoolFactory statementPool = + new StackKeyedObjectPoolFactory(); + PoolableConnectionFactory poolableConnectionFactory = + new PoolableConnectionFactory(connectionFactory, connectionPool, + statementPool, null, false, false); + PoolingDriver poolDriver = new PoolingDriver(); + poolDriver.registerPool("topia",connectionPool); + } + + protected Connection getConnection() throws SQLException { + return DriverManager.getConnection("jdbc:apache:commons:dbcp:topia"); + } + + /** + * Demande la sauvegarde de l'entité dans le context de la transaction + */ + public void store(TopiaTransaction tt, TopiaPersistenceObject tpo) throws TopiaPersistenceException { + try{ + Connection conn = getConnection(); + PreparedStatement sta = conn.prepareStatement(SQL_LOAD_MANAGEMENT); + try{ + sta.setString(1, tpo.getManagement().getId()); + sta.setLong(2, tt.getId()); + ResultSet rr = sta.executeQuery(); + // si l'objet n'etait pas encore dans la transaction, on le met + tpo.getManagement().setDate(tt.getId()); + if(rr.next()){ + // l'objet existait on le met a jour + rr.updateBoolean("isDeleted", tpo.getManagement().isDeleted()); + rr.updateLong("date", tpo.getManagement().getDate()); + saveData(conn, tt, tpo, false); + } else { + // l'objet n'existait pas, on le creer + PreparedStatement insert = conn.prepareStatement(SQL_INSERT_MANAGEMENT); + try{ + insert.setString(1, tpo.getManagement().getId()); + insert.setLong(2, tpo.getManagement().getDate()); + insert.setString(3, TopiaId.getClassNameAsString(tpo.getManagement().getId())); + insert.setBoolean(4, tpo.getManagement().isNew()); + insert.setBoolean(5, tpo.getManagement().isDeleted()); + insert.setLong(6, tpo.getManagement().getSchemaVersion()); + insert.execute(); + } finally { + insert.close(); + } + saveData(conn, tt, tpo, true); + } + } finally { + sta.close(); + } + conn.commit(); + conn.close(); + } catch(SQLException eee) { + throw new TopiaPersistenceException("Erreur durant la sauvegarde de l'entite: " + tpo.getManagement().getId(), eee); + } + } + + /** + * Demande la restauration de l'entité dans le context de la transaction + */ + public void restore(TopiaTransaction tt, TopiaPersistenceObject tpo) throws TopiaPersistenceException { + if(!(tpo.getManagement().isUnloaded() || tpo.getAskedFields().size() != 0)){ + // deja chargé et pas de champs a charger on sort tout de suite + return; + } + try{ + Connection conn = getConnection(); + try{ + PreparedStatement sta = conn.prepareStatement(SQL_LOAD_MANAGEMENT); + try{ + sta.setString(1, tpo.getManagement().getId()); + sta.setLong(2, tt.getId()); + ResultSet management = sta.executeQuery(); + if(!management.next()){ + // on a pas trouve un management specifique pour la + // transaction on recherche le plus recent des objet + // commit pour cette transaction + sta.close(); + sta = conn.prepareStatement(SQL_LOAD_HISTORY); + sta.setString(1, tpo.getManagement().getId()); + sta.setLong(2, tt.getId()); + sta.setLong(3, -tt.getId()); + sta.setLong(4, tt.getId()); + sta.setLong(5, -tt.getId()); + management = sta.executeQuery(); + if(!management.next()){ + // on a pas trouvé d'objet sattisfaisant la demande + throw new TopiaPersistenceException("This object(" + + tpo.getManagement().getId() + ") don't exist in this transaction(" + + tt.getId() + ")"); + } + } + + long storedSchemaVersion = management.getLong("schemaVersion"); + if(tpo.getManagement().isUnloaded()){ + tpo.getManagement().setDate(management.getLong("date")); + tpo.getManagement().setStored(true); + tpo.getManagement().setDeleted(management.getBoolean("isDeleted")); + // l'objet quoi qu'il arrive ne sera plus nouveau + } + if(storedSchemaVersion != tpo.getManagement().getSchemaVersion()){ + // il faut faire un changement de schema, on charge donc + // tous les champs dans un nouveau TopiaPersistenceObjectData + // et on fait un changement de schema dessus. + TopiaPersistenceObjectData oldData = new TopiaPersistenceObjectData(); + loadData(conn, tt, tpo, oldData, true); + + // on fait la conversion des données + TopiaPersistenceObjectData newData = + convert(tpo.getManagement(), storedSchemaVersion, oldData); + + // on fusionne les données modifiées et les données lues + newData.putAll(tpo.getData()); + tpo.getData().putAll(newData); + + // on commence par supprimer toutes les anciennes + // car des champs on pu disparaitre et d'autre apparaitre + PreparedStatement delete = conn.prepareStatement(SQL_REMOVE_DATA); + delete.setString(1, tpo.getManagement().getId()); + delete.setLong(2, tpo.getManagement().getDate()); + delete.execute(); + delete.close(); + + // On sauve les nouvelles valeur pour l'objet + saveData(conn, tt, tpo, true); + + // on change le numero de schema des données + PreparedStatement updateSchema = conn.prepareStatement(SQL_UPDATE_SCHEMAVERSION); + try{ + updateSchema.setLong(1, tpo.getManagement().getSchemaVersion()); + updateSchema.setString(2, tpo.getManagement().getId()); + updateSchema.setLong(3, tpo.getManagement().getDate()); + updateSchema.execute(); + } finally { + updateSchema.close(); + } + } else { + // pas de changement de schema, on charge directement + // dans l'objet data du tpo + loadData(conn, tt, tpo, tpo.getData(), false); + } + + } finally { + sta.close(); + } + } finally { + conn.commit(); + conn.close(); + } + } catch(SQLException eee) { + throw new TopiaPersistenceException("Erreur durant la restauration de l'objet: " + tpo.getManagement().getId(), eee); + } + } + + /** + * Fait la conversion des datas, l'objet retourné peut etre un nouvel objet + * on l'objet data passé en paramètre modifié pour eviter une creation + * d'objet. + * La version du schema souhaité est la version dans management + * management.getSchemaVersion(). + * La version des datas est donné par le paramètre actualSchemaVersion + * @param management pour avoir l'id, la version souhaité + * @param actualSchemaVersion la version actuelle des datas + * @param data les données a convertir + * @return l'objet data passé en paramètre une fois modifier ou un nouveau + */ + protected TopiaPersistenceObjectData convert(TopiaPersistenceObjectManagementData management, long actualSchemaVersion, TopiaPersistenceObjectData data){ + // FIXME appeler l'objet qui fait la conversion + return data; + } + + /** + * Charge les champs demandé dans management.getAskedFields(). Si le champs + * existe déja dans data, alors il n'est pas chargé meme s'il est demandé + * et vide la liste des champs demandée. + * @param conn la connection a utiliser pour acceder a la base + * @param tt la transaction pour lequel la demande est faite + * @param tpo le tpo pour lequel il faut charger les données + * @param data l'objet data a charger, on utilise pas l'objet data de tpo + * car quelque fois il faut charger des données sans faire + * attention a ce qu'il y a deja dans le tpo + * @param forceLoadAllField force le chargement de tous les champs meme ceux + * non demandé + */ + protected void loadData(Connection conn, TopiaTransaction tt, + TopiaPersistenceObject tpo, + TopiaPersistenceObjectData data, + boolean forceLoadAllField) throws SQLException { + PreparedStatement sta = conn.prepareStatement(SQL_LOAD_DATA); + try{ + sta.setString(1, tpo.getManagement().getId()); + sta.setLong(2, tpo.getManagement().getDate()); + ResultSet rr = sta.executeQuery(); + while(rr.next()){ + String field = rr.getString("field"); + if(data.getField(field) == data.UNLOADED){ + // on verife qu'il n'y ait pas deja + // car cela voudrait dire que l'utilisateur a fait un set + // avant le chargement des données + if(forceLoadAllField || tpo.getAskedFields().contains(field)){ + // on le charge que si on a besoin + Object value = rr.getObject("value"); + data.setField(field, value); + // on vient de le charger, donc plus besoin de le faire + tpo.getAskedFields().remove(field); + } + } + } + }finally{ + sta.close(); + } + } + + /** + * Sauve tous les champs modifier et vide la liste des champs modifiée + * @param forceInsert si vrai fait un insert, sinon fait un update + */ + protected void saveData(Connection conn, TopiaTransaction tt, + TopiaPersistenceObject tpo, boolean forceInsert) throws SQLException { + synchronized(tpo.getModifiedFields()){ + if(forceInsert){ + PreparedStatement insert = conn.prepareStatement(SQL_INSERT_DATA); + try{ + insert.setString(1, tpo.getManagement().getId()); + insert.setLong(2, tpo.getManagement().getDate()); + for(String field: tpo.getData().keySet()){ + insert.setString(3, field); + insert.setObject(4, tpo.getData().get(field)); + insert.execute(); + } + } finally { + insert.close(); + } + } else { + PreparedStatement update = conn.prepareStatement(SQL_UPDATE_DATA); + try{ + update.setString(2, tpo.getManagement().getId()); + update.setLong(3, tpo.getManagement().getDate()); + for(String field: tpo.getData().keySet()){ + update.setString(4, field); + update.setObject(1, tpo.getData().get(field)); + update.execute(); + } + } finally { + update.close(); + } + } + tpo.getModifiedFields().clear(); + } + } + + /** + * Retourne tous les id de tous les objets encore existant dans le + * context de la transaction + */ + public Collection getAllId(TopiaTransaction tt) throws TopiaPersistenceException { + List result = new ArrayList(); + try{ + Connection conn = getConnection(); + try{ + PreparedStatement sta = conn.prepareStatement(SQL_GET_ALL_ID); + try{ + sta.setLong(1, tt.getId()); + sta.setLong(2, -tt.getId()); + sta.setLong(3, tt.getId()); + sta.setLong(4, -tt.getId()); + ResultSet rr = sta.executeQuery(); + while(rr.next()){ + result.add(rr.getString("id")); + } + } finally { + sta.close(); + } + conn.commit(); + } finally { + conn.close(); + } + } catch(SQLException eee) { + throw new TopiaPersistenceException("Erreur durant la recherche des objets existant", eee); + } + return result; + } + + /** + * Permet d'indiquer au storage le debut d'une transaction + */ + public void beginTransaction(TopiaTransaction tt) throws TopiaPersistenceException { + // FIXME + } + + /** + * Indique au storage de commiter la transaction passé en paramètre. + * @return la nouvelle transaction utilisable pour de futurs appels au storage + * car l'ancienne transaction n'est plus valide + * @todo pour l'instant on commit tous les objets meme les nouveaux && supprimé + * pour optimiser un peu on pourrait ne pas les commiter. Ca demande un peu + * plus de travaille pour les data, car il faut voir si dans le management + * il sont supprimé on non. Ensuite, il faut supprimer avec les meme requete + * que rollback ces objets. + */ + public TopiaTransaction commitTransaction(TopiaTransaction tt) throws TopiaPersistenceException { + try{ + TopiaTransaction newtt = tt.regenerateTransaction(); + Connection conn = getConnection(); + try{ + PreparedStatement sta = conn.prepareStatement(SQL_COMMIT_MANAGEMENT); + try{ + sta.setLong(1, -newtt.getId()); + sta.setLong(2, tt.getId()); + sta.execute(); + } finally { + sta.close(); + } + sta = conn.prepareStatement(SQL_COMMIT_DATA); + try{ + sta.setLong(1, -newtt.getId()); + sta.setLong(2, tt.getId()); + sta.execute(); + } finally { + sta.close(); + } + } finally { + conn.close(); + } + // peut-etre faire quelque chose comme dans beginTransaction ? + return newtt; + } catch(SQLException eee){ + throw new TopiaPersistenceException("Erreur durant le rollback transaction: " + tt.getId(), eee); + } + } + + /** + * Indique au storage de faire un rollback de la transaction passé en paramètre. + * @return la nouvelle transaction utilisable pour de futurs appels au storage + * car l'ancienne transaction n'est plus valide + */ + public TopiaTransaction rollbackTransaction(TopiaTransaction tt) throws TopiaPersistenceException { + try{ + Connection conn = getConnection(); + try{ + PreparedStatement sta = conn.prepareStatement(SQL_ROLLBACK_MANAGEMENT); + try{ + sta.setLong(1, tt.getId()); + sta.execute(); + } finally { + sta.close(); + } + sta = conn.prepareStatement(SQL_ROLLBACK_DATA); + try{ + sta.setLong(1, tt.getId()); + sta.execute(); + } finally { + sta.close(); + } + } finally { + conn.close(); + } + // creation d'un nouvelle transation + tt = tt.regenerateTransaction(); + // peut-etre faire quelque chose comme dans beginTransaction ? + return tt; + } catch(SQLException eee){ + throw new TopiaPersistenceException("Erreur durant le rollback transaction: " + tt.getId(), eee); + } + } + + /** + * Indique si le storage implante une methode de recherche rapide + * @return vrai si la methode find est implanté + */ + public boolean haveFindImplemented(){ + return false; + } + + /** + * Permet de faire une recherche dans le storage dans le context de la + * transaction passée en argument. Si cette méthode n'est pas implantée + * il faut que haveFindImplemented return false, et que cette méthode + * leve l'exception UnsupportedOperationException + */ + public List find(TopiaTransaction tt, TopiaQuery query) throws TopiaPersistenceException { + throw new UnsupportedOperationException("Find method is not implemented for PersistenceStorageJDBC"); + } + + /** + * Retourne l'historique de l'objet ayant l'id passé en paramètre + */ + public List getHistory(TopiaTransaction tt, String id) throws TopiaPersistenceException { + // TODO + return new ArrayList(); + } + + /** + * Nettoie l'historique pour ne conserver qu'une profondeur d'historique + * egal à depth. Doit prendre en compte le fait que toutes les transactions + * en cours doit avoir toujours au moins la vision convenable de toutes + * les entités. + */ + public void cleanHistory(int depth) throws TopiaPersistenceException { + // TODO + } + + /** + * Permet de savoir si un id existe encore dans le context de la transaction + */ + public boolean exists(TopiaTransaction tt, String id) throws TopiaPersistenceException { + boolean result = false; + try{ + Connection conn = getConnection(); + try{ + PreparedStatement sta = conn.prepareStatement(SQL_LOAD_HISTORY); + try{ + sta.setString(1, id); + sta.setLong(2, tt.getId()); + sta.setLong(3, -tt.getId()); + sta.setLong(4, tt.getId()); + sta.setLong(5, -tt.getId()); + ResultSet rr = sta.executeQuery(); + if(rr.next()){ + result = !rr.getBoolean("isDeleted"); + } + } finally { + sta.close(); + } + conn.commit(); + } finally { + conn.close(); + } + } catch(SQLException eee){ + throw new TopiaPersistenceException("Erreur durant le test d'existance de l'entite: " + id, eee); + } + return result; + } + +} // PersistenceStorageJDBC + Index: topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceException.java diff -u /dev/null topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceException.java:1.1 --- /dev/null Thu Jul 21 16:51:44 2005 +++ topia/src/java/org/codelutin/topia/persistence/TopiaPersistenceException.java Thu Jul 21 16:51:39 2005 @@ -0,0 +1,52 @@ +/* *##% + * 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. + *##%*/ + +/* * + * TopiaPersistenceException.java + * + * Created: 21 juillet 2005 12:50:07 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/07/21 16:51:39 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.topia.persistence; + +import java.util.logging.Level; +import java.util.logging.Logger; +import org.codelutin.topia.TopiaException; + +public class TopiaPersistenceException extends TopiaException{ // TopiaPersistenceException + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Logger log = Logger.getLogger("org.codelutin.topia.persistence.TopiaPersistenceException"); + + public TopiaPersistenceException(String msg){ + super(msg); + } + + public TopiaPersistenceException(String msg, Throwable eee){ + super(msg, eee); + } + +} // TopiaPersistenceException +