Author: tchemit Date: 2014-01-15 09:43:26 +0100 (Wed, 15 Jan 2014) New Revision: 1486 Url: http://forge.codelutin.com/projects/tutti/repository/revisions/1486 Log: refs #4124: [TECH] Mise ?\195?\160 jour de r?\195?\169f?\195?\169rentiel - Erreur sur les donn?\195?\169es suite ?\195?\160 la mise ?\195?\160 jour (rewrite synchro service) Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroDatabaseMetadata.java trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroResult.java trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroService.java trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroServiceImpl.java trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTable.java trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadata.java trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableTool.java trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/ trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/ trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/ trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/ trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/synchro/ trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadataTest.java Removed: trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/service/synchro/ trunk/tutti-persistence/src/test/java/fr/ifremer/tutti/persistence/service/synchro/ Modified: trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/service/TuttiPersistenceServiceLocator.java trunk/tutti-service/src/license/THIRD-PARTY.properties trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/referential/TuttiReferentialSynchronizeService.java trunk/tutti-ui-swing/src/license/THIRD-PARTY.properties trunk/tutti-ui-swing/src/main/filtered-resources/log4j.properties trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiApplicationUpdaterCallBack.java trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiDbUpdaterCallBack.java trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroDatabaseMetadata.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroDatabaseMetadata.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroDatabaseMetadata.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,136 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import fr.ifremer.shared.application.ApplicationTechnicalException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.HibernateException; +import org.hibernate.dialect.Dialect; +import org.hibernate.mapping.Table; +import org.hibernate.tool.hbm2ddl.DatabaseMetadata; +import org.hibernate.tool.hbm2ddl.TableMetadata; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.Map; +import java.util.Set; + +import static org.nuiton.i18n.I18n._; + +/** + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +public class ReferentialSynchroDatabaseMetadata { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(ReferentialSynchroDatabaseMetadata.class); + + /** + * Load the datasource schema for the given connection and dialect. + * + * @param connection connection of the data source + * @param dialect dialect to use + * @return the datasource schema + */ + public static ReferentialSynchroDatabaseMetadata loadDatabaseMetadata(Connection connection, + Dialect dialect) { + ReferentialSynchroDatabaseMetadata result = new ReferentialSynchroDatabaseMetadata(connection, dialect); + for (ReferentialSynchroTable tuttiTable : ReferentialSynchroTable.values()) { + + String tableName = tuttiTable.name(); + if (log.isDebugEnabled()) { + log.debug("Load metas of table: " + tableName); + } + result.getTable(tableName); + } + return result; + } + + protected final DatabaseMetadata delegate; + + protected final Map<String, ReferentialSynchroTableMetadata> tables; + + protected final DatabaseMetaData meta; + + public ReferentialSynchroDatabaseMetadata(Connection connection, Dialect dialect) { + Preconditions.checkNotNull(connection); + Preconditions.checkNotNull(dialect); + try { + this.delegate = new DatabaseMetadata(connection, dialect, true); + this.meta = connection.getMetaData(); + } catch (SQLException e) { + throw new ApplicationTechnicalException(_("tutti.persistence.dbMetadata.instanciation.error", connection), e); + } + tables = Maps.newTreeMap(); + } + + public ReferentialSynchroTableMetadata getTable(String name) throws HibernateException { + return getTable(name, "PUBLIC", null, false); + } + + public int getTableCount() { + return tables.size(); + } + + public Set<String> getTableNames() { + Set<String> result = Sets.newHashSet(); + for (ReferentialSynchroTableMetadata tableMetadata : tables.values()) { + result.add(tableMetadata.getName()); + } + return result; + } + + protected ReferentialSynchroTableMetadata getTable(String name, + String schema, + String catalog, + boolean isQuoted) throws HibernateException { + String key = Table.qualify(catalog, schema, name); + ReferentialSynchroTableMetadata tuttiTableMetadata = tables.get(key); + if (tuttiTableMetadata == null) { + + TableMetadata tableMetadata = delegate.getTableMetadata( + name, schema, catalog, isQuoted); + Preconditions.checkNotNull(tableMetadata, + "Could not find db table " + name); + ReferentialSynchroTable tuttiTable = ReferentialSynchroTable.valueOf(name); + Preconditions.checkNotNull(tuttiTable, + "Could not find db table " + tuttiTable); + tuttiTableMetadata = new ReferentialSynchroTableMetadata(tableMetadata, meta); + Preconditions.checkNotNull(tuttiTableMetadata, + "Could not find db table " + name); + tables.put(key, tuttiTableMetadata); + } + return tuttiTableMetadata; + } +} \ No newline at end of file Property changes on: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroDatabaseMetadata.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Copied: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroResult.java (from rev 1477, trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/service/synchro/ReferentialSynchronizeResult.java) =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroResult.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroResult.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,208 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence API + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2012 - 2013 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import fr.ifremer.tutti.persistence.ProgressionModel; + +import java.sql.Timestamp; +import java.util.Map; +import java.util.Set; + +/** + * Result of a referential synchronize operation. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.0 + */ +public class ReferentialSynchroResult { + + protected Exception error; + + /** + * Number of rows detected to update (per table). + * + * @since 1.0 + */ + protected final Map<String, Integer> rowHits = Maps.newTreeMap(); + + /** + * Number of insert done (per table). + * + * @since 1.0 + */ + protected final Map<String, Integer> insertHits = Maps.newTreeMap(); + + /** + * Number of update done (per table). + * + * @since 1.0 + */ + protected final Map<String, Integer> updateHits = Maps.newTreeMap(); + + /** + * timestamp of last update date (per table). + * + * @since 1.0 + */ + protected final Map<String, Timestamp> updateDateHits = Maps.newTreeMap(); + + /** + * All table treated. + * + * @since 1.0 + */ + protected final Set<String> tableNames = Sets.newHashSet(); + + protected String localUrl; + + protected String remoteUrl; + + protected final ProgressionModel progressionModel = new ProgressionModel(); + + public ReferentialSynchroResult() { + } + + public ReferentialSynchroResult(String localUrl, String remoteUrl) { + this.localUrl = localUrl; + this.remoteUrl = remoteUrl; + } + + public void setLocalUrl(String localUrl) { + this.localUrl = localUrl; + } + + public void setRemoteUrl(String remoteUrl) { + this.remoteUrl = remoteUrl; + } + + public boolean isSuccess() { + return error == null; + } + + public Exception getError() { + return error; + } + + public void setError(Exception error) { + this.error = error; + } + + public ProgressionModel getProgressionModel() { + return progressionModel; + } + + public Set<String> getTableNames() { + return ImmutableSet.copyOf(tableNames); + } + + public int getTotalRows() { + int result = 0; + for (Integer nb : rowHits.values()) { + result += nb; + } + return result; + } + + public int getTotalInserts() { + int result = 0; + for (Integer nb : insertHits.values()) { + result += nb; + } + return result; + } + + public int getTotalUpdates() { + int result = 0; + for (Integer nb : updateHits.values()) { + result += nb; + } + return result; + } + + public int getNbRows(String tableName) { + Integer result = rowHits.get(tableName); + if (result == null) { + result = 0; + } + return result; + } + + public int getNbInserts(String tableName) { + Integer result = insertHits.get(tableName); + if (result == null) { + result = 0; + } + return result; + } + + public int getNbUpdates(String tableName) { + Integer result = updateHits.get(tableName); + if (result == null) { + result = 0; + } + return result; + } + + public void addRows(String tableName, int nb) { + if (nb > 0) { + rowHits.put(tableName, getNbRows(tableName) + nb); + } + } + + public void addUpdates(String tableName, int nb) { + if (nb > 0) { + updateHits.put(tableName, getNbUpdates(tableName) + nb); + } + } + + public void addInserts(String tableName, int nb) { + if (nb > 0) { + insertHits.put(tableName, getNbInserts(tableName) + nb); + } + } + + public Timestamp getUpdateDate(String tableName) { + return updateDateHits.get(tableName); + } + + public void setUpdateDate(String tableName, Timestamp t) { + updateDateHits.put(tableName, t); + } + + public void addTableName(String tableName) { + tableNames.add(tableName); + } + + public String getLocalUrl() { + return localUrl; + } + + public String getRemoteUrl() { + return remoteUrl; + } +} Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroService.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroService.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroService.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,78 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import org.hibernate.dialect.Dialect; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Properties; + +/** + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED) +public interface ReferentialSynchroService { + + /** + * Get the db connexion informations for the internal data source. + * + * @return the db connexion for the internal data source + */ + Properties getLocalConnectionProperties(); + + /** + * Gets the dialect used by the local database. + * + * @return the dialect used by the local database. + */ + Dialect getLocalDialect(); + + /** + * Prepare the synchronize operation from the local data database supported + * by this service, says just compute nb rows to update for each table and + * update the result model. + * + * @param remoteConnectionProperties connection properties of the remote + * database used to synchronize referential + * @param result result of the operation + */ + void prepare(Properties remoteConnectionProperties, + ReferentialSynchroResult result); + + /** + * Launch the synchronize operation from the local data database supported + * by this service. + * + * @param remoteConnectionProperties connection properties of the remote + * database used to synchronize referential + * @param result model + */ + void synchronize(Properties remoteConnectionProperties, + ReferentialSynchroResult result); +} Property changes on: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroService.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroServiceImpl.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroServiceImpl.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroServiceImpl.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,646 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.google.common.io.Closeables; +import fr.ifremer.tutti.persistence.ProgressionModel; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.tool.hbm2ddl.ColumnMetadata; +import org.nuiton.util.TimeLog; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataRetrievalFailureException; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import static org.nuiton.i18n.I18n._; + +/** + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +@Service("referentialSynchroService") +public class ReferentialSynchroServiceImpl implements ReferentialSynchroService { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(ReferentialSynchroServiceImpl.class); + + private static final TimeLog TIME = + new TimeLog(ReferentialSynchroServiceImpl.class); + + @Autowired + protected DriverManagerDataSource dataSource; + + @Autowired + protected SessionFactory sessionFactory; + + protected Dialect localDialect; + + protected Properties dbconnexionProperties; + + @Override + public Properties getLocalConnectionProperties() { + if (dbconnexionProperties == null) { + dbconnexionProperties = new Properties(); + + dbconnexionProperties.put(Environment.URL, dataSource.getUrl()); + dbconnexionProperties.put(Environment.USER, dataSource.getUsername()); + dbconnexionProperties.put(Environment.PASS, dataSource.getPassword()); + } + return dbconnexionProperties; + } + + @Override + public Dialect getLocalDialect() { + if (localDialect == null) { + localDialect = ((SessionFactoryImplementor) sessionFactory).getSettings().getDialect(); + } + return localDialect; + } + + @Override + public void prepare(Properties remoteConnectionProperties, ReferentialSynchroResult result) { + Preconditions.checkNotNull(result); + Preconditions.checkNotNull(remoteConnectionProperties); + + + result.setLocalUrl(getUrl(getLocalConnectionProperties())); + result.setRemoteUrl(getUrl(remoteConnectionProperties)); + + dbconnexionProperties = null; + localDialect = null; + + Connection localConnection = null; + Connection remoteConnection = null; + try { + + ProgressionModel progressionModel = result.getProgressionModel(); + progressionModel.setMessage(_("tutti.persistence.synchronizeReferential.prepare.step1")); + + // create local connection + localConnection = createConnection(getLocalConnectionProperties()); + + progressionModel.setMessage(_("tutti.persistence.synchronizeReferential.prepare.step2")); + + // create remote Connection + remoteConnection = createConnection(remoteConnectionProperties); + + // load metas + ReferentialSynchroDatabaseMetadata localMeta = + ReferentialSynchroDatabaseMetadata.loadDatabaseMetadata(localConnection, getLocalDialect()); + + ReferentialSynchroDatabaseMetadata remoteMeta = + ReferentialSynchroDatabaseMetadata.loadDatabaseMetadata(remoteConnection, getLocalDialect()); + + progressionModel.setMessage(_("tutti.persistence.synchronizeReferential.prepare.step3")); + + // check schema + try { + checkSchemas(localMeta, remoteMeta); + } catch (DataRetrievalFailureException e) { + result.setError(e); + } + + if (result.isSuccess()) { + + // prepare model (compute update date, count rows to update,...) + + for (ReferentialSynchroTable tuttiTable : ReferentialSynchroTable.values()) { + + long t0 = TimeLog.getTime(); + + String tableName = tuttiTable.name(); + + progressionModel.setMessage(_("tutti.persistence.synchronizeReferential.prepare.step4", tableName)); + + ReferentialSynchroTableMetadata table = remoteMeta.getTable(tableName); + + if (log.isDebugEnabled()) { + log.debug("Prepare table: " + tableName); + } + prepareTable(table, + localConnection, + remoteConnection, + result); + + TIME.log(t0, "prepare table " + tableName); + } + + long totalRows = result.getTotalRows(); + if (log.isInfoEnabled()) { + log.info("Total rows to update: " + totalRows); + } + localConnection.rollback(); + } + } catch (SQLException e) { + try { + if (localConnection != null) { + localConnection.rollback(); + } + } catch (SQLException e1) { + + // ignore the rolback error + } + result.setError(e); + } finally { + JdbcUtils.closeConnection(remoteConnection); + JdbcUtils.closeConnection(localConnection); + } + } + + @Override + public void synchronize(Properties remoteConnectionProperties, ReferentialSynchroResult result) { + Preconditions.checkNotNull(result); + Preconditions.checkNotNull(remoteConnectionProperties); + + Connection localConnection = null; + Connection remoteConnection = null; + try { + + // create local connection + localConnection = createConnection(getLocalConnectionProperties()); + + // create remote Connection + remoteConnection = createConnection(remoteConnectionProperties); + + // load metas + ReferentialSynchroDatabaseMetadata remoteMeta = + ReferentialSynchroDatabaseMetadata.loadDatabaseMetadata(remoteConnection, getLocalDialect()); + + // set total in progression model + ProgressionModel progressionModel = result.getProgressionModel(); + progressionModel.setTotal(result.getTotalRows()); + + // prepare target (desactivate constraints) + prepareSynch(localConnection); + + try { + + for (ReferentialSynchroTable tuttiTable : ReferentialSynchroTable.values()) { + + long t0 = TimeLog.getTime(); + + String tableName = tuttiTable.name(); + + progressionModel.setMessage(_("tutti.persistence.synchronizeReferential.synchronize.step1", tableName)); + + ReferentialSynchroTableMetadata table = remoteMeta.getTable(tableName); + + if (log.isInfoEnabled()) { + log.info("Synchronize table: " + tableName); + } + long countToUpdate = result.getNbRows(tableName); + + if (countToUpdate > 0) { + + synchronizeTable(table, + localConnection, + remoteConnection, + result); + } + + TIME.log(t0, "synchronize table " + tableName); + } + if (log.isInfoEnabled()) { + long totalInserts = result.getTotalInserts(); + long totalUpdates = result.getTotalUpdates(); + log.info("Total rows to treat: " + result.getTotalRows()); + log.info("Total rows inserted: " + totalInserts); + log.info("Total rows updated: " + totalUpdates); + log.info("Total rows treated: " + (totalInserts + totalUpdates)); + } + } finally { + releaseSynch(localConnection); + } + + progressionModel.setMessage(_("tutti.persistence.synchronizeReferential.synchronize.step2")); + + localConnection.commit(); + + } catch (SQLException e) { + try { + if (localConnection != null) { + localConnection.rollback(); + } + } catch (SQLException e1) { + + // ignore the rolback error + } + result.setError(e); + } finally { + JdbcUtils.closeConnection(remoteConnection); + JdbcUtils.closeConnection(localConnection); + } + } + + /** + * Check that the tow given datasource shemas are compatible for a + * synchronize operation (same tables with same columns). + * <p/> + * If schemas are incompatible, then a + * {@link DataRetrievalFailureException} exception will be thrown. + * + * @param schema1 schema 1 to check + * @param schema2 schema 2 to check + */ + protected void checkSchemas(ReferentialSynchroDatabaseMetadata schema1, + ReferentialSynchroDatabaseMetadata schema2) { + Set<String> internalSchemaTableNames = schema1.getTableNames(); + Set<String> externalSchemaTableNames = schema2.getTableNames(); + if (!internalSchemaTableNames.equals(externalSchemaTableNames)) { + throw new DataRetrievalFailureException("Incompatible schemas"); + } + for (String tableName : internalSchemaTableNames) { + ReferentialSynchroTableMetadata internalTable = schema1.getTable(tableName); + ReferentialSynchroTableMetadata externalTable = schema2.getTable(tableName); + Set<String> internalColumnNames = internalTable.getColumnNames(); + Set<String> externalColumnNames = externalTable.getColumnNames(); + if (!internalColumnNames.equals(externalColumnNames)) { + throw new DataRetrievalFailureException("Incompatible schema of table: " + tableName); + } + for (String columnName : internalColumnNames) { + ColumnMetadata internalColumn = internalTable.getColumnMetadata(columnName); + ColumnMetadata externalColumn = externalTable.getColumnMetadata(columnName); + String internalColumnTypeName = internalColumn.getTypeName(); + String externalColumnTypeName = externalColumn.getTypeName(); + if (!internalColumnTypeName.equals(externalColumnTypeName)) { + throw new DataRetrievalFailureException("Incompatible column type of table / column: " + tableName + " / " + columnName); + } + } + } + } + + protected void prepareTable(ReferentialSynchroTableMetadata table, + Connection localConnection, + Connection remoteConnection, + ReferentialSynchroResult result) throws SQLException { + + String tablePrefix = table.getTableLogPrefix(); + + String tableName = table.getName(); + + ReferentialSynchroTableTool localDao = new ReferentialSynchroTableTool(localConnection, table); + + long localCount = localDao.count(); + + // get last updateDate used by local db + Timestamp updateDate = null; + + if (localCount < 50000) { + + // only use the update date on small table, for big table we will re-insert all the table content + updateDate = localDao.getLastUpdateDate(); + + if (updateDate != null) { + + // just inscrements of 1 milisecond to not having same + updateDate = new Timestamp(DateUtils.setMilliseconds(updateDate, 0).getTime()); + updateDate = new Timestamp(DateUtils.addSeconds(updateDate, 1).getTime()); + } + } + + ReferentialSynchroTableTool remoteDao = new ReferentialSynchroTableTool(remoteConnection, table); + + long countToUpdate = remoteDao.getCountDataToUpdate(updateDate); + + if (log.isInfoEnabled()) { + log.info(String.format("%s nb rows to update: %s", tablePrefix, countToUpdate)); + } + + result.setUpdateDate(tableName, updateDate); + result.addRows(tableName, (int) countToUpdate); + } + + protected void synchronizeTable(ReferentialSynchroTableMetadata table, + Connection localConnection, + Connection remoteConnection, + ReferentialSynchroResult result) throws SQLException { + + String tableName = table.getName(); + + result.getProgressionModel().setMessage(_("tutti.persistence.synchronizeReferential.synchronizeTable", tableName)); + + String tablePrefix = table.getTableLogPrefix(); + + ReferentialSynchroTableTool localDao = new ReferentialSynchroTableTool(localConnection, table); + ReferentialSynchroTableTool remoteDao = new ReferentialSynchroTableTool(remoteConnection, table); + + // get last updateDate used by local db + Date updateDate = result.getUpdateDate(tableName); + + // get table count + long count = localDao.count(); + + // get existing ids in the local db + Set<String> existingIds = localDao.getExistingPrimaryKeys(); + + if (log.isDebugEnabled()) { + log.debug(tablePrefix + " existingIds: " + existingIds.size()); + } + + boolean bigTable = count > 50000; + + // get data to update from remote db + ResultSet dataToUpdate = remoteDao.getDataToUpdate( + bigTable ? null : updateDate); + + try { + + if (bigTable) { + + // big table update strategy + updateBigTable(localDao, + remoteDao, + table, + dataToUpdate, + result); + } else { + + // small table update strategy + updateTable(localDao, + table, + dataToUpdate, + result); + } + dataToUpdate.close(); + } finally { + + Closeables.closeQuietly(localDao); + Closeables.closeQuietly(remoteDao); + JdbcUtils.closeResultSet(dataToUpdate); + } + } + + /** + * To update the content of the given {@code table} on the local db, + * from the given {@code incomingData} of the remote db. + * <p/> + * The algorithm is pretty simple, for each row of the {@code incomingData}, + * if exists on local table, then do an update, otherwise do a insert. + * <p/> + * As an update query is more expensive, we won't use this method for table + * with a lot of rows, we will prefer to use the {@code updateBigTable} + * method instead. + * + * @param localDao connection on the local db + * @param table table to update + * @param incomingData data to update from the remote db + * @param result where to store operation results + * @throws SQLException if any sql errors + */ + protected void updateTable(ReferentialSynchroTableTool localDao, + ReferentialSynchroTableMetadata table, + ResultSet incomingData, + ReferentialSynchroResult result) throws SQLException { + + // get existing ids in the local db + Set<String> existingIds = localDao.getExistingPrimaryKeys(); + + String tableName = table.getName(); + String tablePrefix = table.getTableLogPrefix() + " - " + result.getNbRows(tableName); + + result.addTableName(tableName); + + int countR = 0; + + while (incomingData.next()) { + + List<Object> pk = table.getPk(incomingData); + String pkStr = table.toPkStr(pk); + + boolean doUpdate = existingIds.contains(pkStr); + + if (doUpdate) { + + localDao.executeUpdate(pk, incomingData); + + } else { + + localDao.executeInsert(pk, incomingData); + } + + countR++; + + reportProgress(result, localDao, countR, tablePrefix); + } + + localDao.flushQueries(); + + int insertCount = localDao.getInsertCount(); + int updateCount = localDao.getUpdateCount(); + + result.addInserts(tableName, insertCount); + result.addUpdates(tableName, updateCount); + if (log.isInfoEnabled()) { + log.info(String.format("%s done: %s (inserts: %s, updates: %s)", tablePrefix, countR, insertCount, updateCount)); + } + + if (log.isDebugEnabled()) { + log.debug(String.format("%s INSERT count: %s", tablePrefix, result.getNbInserts(tableName))); + log.debug(String.format("%s UPDATE count: %s", tablePrefix, result.getNbUpdates(tableName))); + } + + result.getProgressionModel().increments(countR % 1000); + } + + /** + * To update the content of the given {@code table} (with a lot of rows) on + * the local db, from the given {@code incomingData} of the remote db. + * <p/> + * We can't use the simple algorithm, since update queries cost too much + * and is not acceptable when talking on huge numbers of rows. + * <p/> + * Here is what to do : + * <ul> + * <li>Get form the local db the data which are not in remote db, keep them</li> + * <li>Delete local table content</li> + * <li>Insert remote table in local table</li> + * <li>Insert the saved extra rows from original table</li> + * </ul> + * In that way we will only perform some insert queries. + * + * @param localDao connection on the local db + * @param remoteDao connection on the local db + * @param table table to update + * @param incomingData data to update from the remote db + * @param result where to store operation results + * @throws SQLException if any sql errors + */ + protected void updateBigTable(ReferentialSynchroTableTool localDao, + ReferentialSynchroTableTool remoteDao, + ReferentialSynchroTableMetadata table, + ResultSet incomingData, + ReferentialSynchroResult result) throws SQLException { + + String tableName = table.getName(); + + result.addTableName(tableName); + + String tablePrefix = table.getTableLogPrefix() + " - " + result.getNbRows(tableName); + + // get existing ids in the local db + Set<String> existingIds = localDao.getExistingPrimaryKeys(); + + if (log.isDebugEnabled()) { + log.debug(tablePrefix + " local existingIds: " + existingIds.size()); + } + + Set<String> remoteExistingIds = remoteDao.getExistingPrimaryKeys(); + + if (log.isDebugEnabled()) { + log.debug(tablePrefix + " remote existingIds: " + existingIds.size()); + } + + existingIds.removeAll(remoteExistingIds); + + if (log.isDebugEnabled()) { + log.debug(tablePrefix + " local data existingIds not in remote: " + existingIds); + } + + + // copy extra rows from local + + Map<List<Object>, Object[]> extraRows = Maps.newLinkedHashMap(); + + for (String pkStr : existingIds) { + + List<Object> pk = table.fromPkStr(pkStr); + + Object[] extraRow = localDao.findByPk(pk); + + extraRows.put(pk, extraRow); + } + + // delete table + localDao.deleteAll(); + + int countR = 0; + + // add all data from remote + while (incomingData.next()) { + + List<Object> pk = table.getPk(incomingData); + + localDao.executeInsert(pk, incomingData); + + countR++; + + reportProgress(result, localDao, countR, tablePrefix); + } + + // re-add extra local rows + for (Map.Entry<List<Object>, Object[]> entry : extraRows.entrySet()) { + + List<Object> pk = entry.getKey(); + Object[] row = entry.getValue(); + localDao.executeInsert(pk, row); + + countR++; + + reportProgress(result, localDao, countR, tablePrefix); + } + + localDao.flushQueries(); + + int insertCount = localDao.getInsertCount(); + result.addInserts(tableName, insertCount); + if (log.isInfoEnabled()) { + log.info(String.format("%s done: %s (inserts: %s)", tablePrefix, countR, insertCount)); + } + + if (log.isDebugEnabled()) { + log.debug(String.format("%s INSERT count: %s", tablePrefix, result.getNbInserts(tableName))); + } + + result.getProgressionModel().increments(countR % 1000); + } + + protected void reportProgress(ReferentialSynchroResult result, ReferentialSynchroTableTool dao, int countR, String tablePrefix) { + if (countR % 1000 == 0) { + result.getProgressionModel().increments(1000); + } + + if (countR % 10000 == 0) { + if (log.isInfoEnabled()) { + log.info(String.format("%s Done: %s (inserts: %s, updates: %s)", tablePrefix, countR, dao.getInsertCount(), dao.getUpdateCount())); + } + } + } + + Connection createConnection(Properties connectionProperties) throws SQLException { + return createConnection( + connectionProperties.getProperty(Environment.URL), + connectionProperties.getProperty(Environment.USER), + connectionProperties.getProperty(Environment.PASS) + ); + } + + String getUrl(Properties connectionProperties) { + return connectionProperties.getProperty(Environment.URL); + } + + Connection createConnection(String jdbcUrl, + String user, + String password) throws SQLException { + Connection connection = DriverManager.getConnection(jdbcUrl, + user, + password); + connection.setAutoCommit(false); + return connection; + } + + void prepareSynch(Connection connection) throws SQLException { + PreparedStatement statement = connection.prepareStatement("SET REFERENTIAL_INTEGRITY FALSE;"); + statement.executeUpdate(); + } + + void releaseSynch(Connection connection) throws SQLException { + PreparedStatement statement = connection.prepareStatement("SET REFERENTIAL_INTEGRITY TRUE;"); + statement.executeUpdate(); + } +} Property changes on: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroServiceImpl.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTable.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTable.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTable.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,116 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +/** + * List of all tables we want to synchronize. + * <p/> + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +public enum ReferentialSynchroTable { + + STATUS, + QUALITY_FLAG, + + // PMFM + UNIT, + AGGREGATION_LEVEL, + PARAMETER_GROUP, + QUALITATIVE_VALUE, + PARAMETER, + MATRIX, + FRACTION, + FRACTION2MATRIX, + METHOD, + PMFM, + PMFM2QUALITATIVE_VALUE, + + // GEAR + GEAR_CLASSIFICATION, + GEAR_CLASSIFICATION_ASSOCIATIO, + GEAR, + GEAR_ASSOCIATION, + + // LOCATION + LOCATION_CLASSIFICATION, + LOCATION_LEVEL, + LOCATION_ASSOCIATION, + LOCATION, + LOCATION_HIERARCHY, + LOCATION_HIERARCHY_EXCEPTION, + + // TAXON + TAXONOMIC_LEVEL, + REFERENCE_TAXON, + TAXON_NAME, + TAXON_INFORMATION, + TAXON_INFORMATION_HISTORY, + VIRTUAL_COMPONENT, + TAXON_NAME_HISTORY, + REFERENCE_DOCUMENT, + AUTHOR, + CITATION, + + // TAXON GROUP + TAXON_GROUP_TYPE, + TAXON_GROUP, + TAXON_GROUP_HISTORICAL_RECORD, + TAXON_GROUP_INFORMATION, + + // CONVERSION + ROUND_WEIGHT_CONVERSION, + WEIGHT_LENGTH_CONVERSION, + UNIT_CONVERSION, + + // VESSEL + VESSEL_TYPE, + VESSEL_REGISTRATION_PERIOD, + VESSEL_FEATURES, + VESSEL, + + // PERSON + USER_PROFIL, + DEPARTMENT, + PERSON, + PERSON2USER_PROFIL, + + // VESSEL_PERSON_ROLE + VESSEL_PERSON_ROLE, + VESSEL_PERSON, + + //ORDER + ORDER_ITEM, + + //OTHER + PRECISION_TYPE, + NUMERICAL_PRECISION, + PHOTO_TYPE, + OBJECT_TYPE, + ORDER_TYPE, + ANALYSIS_INSTRUMENT +} Property changes on: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTable.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadata.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadata.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadata.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,425 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import fr.ifremer.shared.application.ApplicationTechnicalException; +import fr.ifremer.tutti.persistence.entities.TuttiEntities; +import org.hibernate.mapping.ForeignKey; +import org.hibernate.tool.hbm2ddl.ColumnMetadata; +import org.hibernate.tool.hbm2ddl.ForeignKeyMetadata; +import org.hibernate.tool.hbm2ddl.IndexMetadata; +import org.hibernate.tool.hbm2ddl.TableMetadata; + +import java.lang.reflect.Field; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; + +import static org.nuiton.i18n.I18n._; + +/** + * Overrides of the {@link TableMetadata} with some improvements: + * <ul> + * <li>Obtains number of columns via {@link #getColumnsCount()}</li> + * <li>Obtains all columns names available via {@link #getColumnNames()}</li> + * <li>Obtains primary key column names via {@link #getPkNames()}</li> + * </ul> + * <p/> + * And others methods used to synchronize referentials: + * <ul> + * <li>Obtains query to update a row of the table (column names order is the + * one introduced by method {@link #getColumnNames()}: {@link #getUpdateQuery()} + * </li> + * <li>Obtains query to insert a row in the table (column names order is the + * one introduced by method {@link #getColumnNames()}: {@link #getInsertQuery()} + * </li> + * </ul> + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +public class ReferentialSynchroTableMetadata { + + protected static final String QUERY_SELECT_MAX_UPDATE = "SELECT max(update_date) FROM %s"; + + protected static final String QUERY_INSERT = "INSERT INTO %s (%s) VALUES (%s)"; + + protected static final String QUERY_UPDATE = "UPDATE %s SET %s WHERE %s"; + + protected static final String QUERY_SELECT = "SELECT %s FROM %s WHERE %s"; + + protected static final String QUERY_SELECT_PRIMARY_KEYS = "SELECT %s FROM %s"; + + protected static final String QUERY_SELECT_COUNT = "SELECT count(*) FROM %s"; + + protected final String existingPrimaryKeysQuery; + + protected final String maxUpdateDateQuery; + + protected final String countQuery; + + protected final TableMetadata delegate; + + protected final Map<String, ColumnMetadata> columns; + + protected final Set<String> pkNames; + + protected final int[] pkIndexs; + + protected final String insertQuery; + + protected final String updateQuery; + + protected final boolean withUpdateDateColumn; + + protected final String countDataToUpdateQuery; + + protected final String countDataToUpdateQueryWithNull; + + protected final String dataToUpdateQuery; + + protected final String dataToUpdateQueryWithNull; + + protected final String selectDataQueryFromPk; + + protected final boolean simpleKey; + + public ReferentialSynchroTableMetadata(TableMetadata delegate, + DatabaseMetaData meta) { + + Preconditions.checkNotNull(delegate); + this.delegate = delegate; + + try { + Field field = TableMetadata.class.getDeclaredField("columns"); + field.setAccessible(true); + this.columns = (Map) field.get(delegate); + this.withUpdateDateColumn = columns.containsKey("update_date"); + this.pkNames = initPrimaryKeys(meta); + Preconditions.checkNotNull(pkNames); + this.pkIndexs = createPkIndex(); + + this.simpleKey = this.pkIndexs.length == 1; + + this.insertQuery = createInsertQuery(); + this.updateQuery = createUpdateQuery(); + this.maxUpdateDateQuery = String.format(QUERY_SELECT_MAX_UPDATE, getName()); + this.existingPrimaryKeysQuery = String.format(QUERY_SELECT_PRIMARY_KEYS, Joiner.on(',').join(pkNames), getName()); + this.countQuery = String.format(QUERY_SELECT_COUNT, getName()); + } catch (Exception e) { + throw new ApplicationTechnicalException(_("tutti.persistence.tableMetadata.instanciation.error", this), e); + } + + dataToUpdateQueryWithNull = "SELECT " + createSelectParams() + " FROM " + getName(); + countDataToUpdateQueryWithNull = "SELECT count(*) FROM " + getName(); + + this.selectDataQueryFromPk = createSelectQuery(); + String whereClause; + + if (isWithUpdateDateColumn()) { + + // add a filter + whereClause = " WHERE (update_date IS NULL OR update_date > ?)"; + } else { + whereClause = ""; + } + dataToUpdateQuery = dataToUpdateQueryWithNull + whereClause; + countDataToUpdateQuery = countDataToUpdateQueryWithNull + whereClause; + } + + // for tests purposes + ReferentialSynchroTableMetadata() { + + existingPrimaryKeysQuery = null; + + maxUpdateDateQuery = null; + + countQuery = null; + + delegate = null; + + columns = null; + + pkNames = null; + + pkIndexs = null; + + insertQuery = null; + + updateQuery = null; + + withUpdateDateColumn = false; + + countDataToUpdateQuery = null; + + countDataToUpdateQueryWithNull = null; + + dataToUpdateQuery = null; + + dataToUpdateQueryWithNull = null; + + selectDataQueryFromPk = null; + simpleKey = false; + } + + public Set<String> getPkNames() { + return pkNames; + } + + public boolean isWithUpdateDateColumn() { + return withUpdateDateColumn; + } + + public int getColumnsCount() { + return columns.size(); + } + + public SortedSet<String> getColumnNames() { + return Sets.newTreeSet(columns.keySet()); + } + + public String getName() { + return delegate.getName(); + } + + public ForeignKeyMetadata getForeignKeyMetadata(ForeignKey fk) { + return delegate.getForeignKeyMetadata(fk); + } + + public ColumnMetadata getColumnMetadata(String columnName) { + return delegate.getColumnMetadata(columnName); + } + + public String getSchema() { + return delegate.getSchema(); + } + + public String getCatalog() { + return delegate.getCatalog(); + } + + public ForeignKeyMetadata getForeignKeyMetadata(String keyName) { + return delegate.getForeignKeyMetadata(keyName); + } + + public IndexMetadata getIndexMetadata(String indexName) { + return delegate.getIndexMetadata(indexName); + } + + public String getInsertQuery() { + return insertQuery; + } + + public String getUpdateQuery() { + return updateQuery; + } + + public String getExistingPrimaryKeysQuery() { + return existingPrimaryKeysQuery; + } + + public String getMaxUpdateDateQuery() { + return maxUpdateDateQuery; + } + + public String getCountQuery() { + return countQuery; + } + + public String getSelectDataQueryFromPk() { + return selectDataQueryFromPk; + } + + public int[] getPkIndexs() { + return pkIndexs; + } + + public String getDataToUpdateQuery() { + return dataToUpdateQuery; + } + + public String getDataToUpdateQueryWithNull() { + return dataToUpdateQueryWithNull; + } + + public String getCountDataToUpdateQuery() { + return countDataToUpdateQuery; + } + + public String getCountDataToUpdateQueryWithNull() { + return countDataToUpdateQueryWithNull; + } + + public boolean isSimpleKey() { + return simpleKey; + } + + public List<Object> getPk(ResultSet incomingData) throws SQLException { + List<Object> result = Lists.newArrayListWithCapacity(pkIndexs.length); + for (int pkIndex : pkIndexs) { + Object pk = incomingData.getObject(pkIndex); + result.add(pk); + } + return result; + } + + public String toPkStr(List<Object> pkList) { + StringBuilder sb = new StringBuilder(); + for (Object pk : pkList) { + sb.append("~|").append(pk); + } + return sb.toString(); + } + + public List<Object> fromPkStr(String pk) { + List<Object> pkList = Lists.newArrayList(); + String[] split = pk.split("~\\|"); + for (String s : split) { + if ("null".equals(s)) { + s = null; + } + pkList.add(s); + } + pkList.remove(0); + return pkList; + } + + protected Set<String> initPrimaryKeys(DatabaseMetaData meta) throws SQLException { + + Set<String> result = Sets.newHashSet(); + ResultSet rs = meta.getPrimaryKeys(getCatalog(), getSchema(), getName()); + try { + + while (rs.next()) { + result.add(rs.getString("COLUMN_NAME")); + } + rs.close(); + return ImmutableSet.copyOf(result); + } finally { + TuttiEntities.closeSilently(rs); + } + } + + protected int[] createPkIndex() { + + int[] result = new int[pkNames.size()]; + + int pkI = 0; + for (String pkName : pkNames) { + String pkColumnName = pkName.toLowerCase(); + + int i = 1; + + int index = -1; + for (String columnName : getColumnNames()) { + if (pkColumnName.equals(columnName)) { + index = i; + } else { + i++; + } + } + result[pkI++] = index; + } + return result; + } + + + protected String createInsertQuery() { + + StringBuilder queryParams = new StringBuilder(); + StringBuilder valueParams = new StringBuilder(); + + for (String columnName : getColumnNames()) { + queryParams.append(", ").append(columnName); + valueParams.append(", ?"); + } + + String result = String.format(QUERY_INSERT, + getName(), + queryParams.substring(2), + valueParams.substring(2)); + return result; + } + + protected String createUpdateQuery() { + + StringBuilder updateParams = new StringBuilder(); + + for (String columnName : getColumnNames()) { + updateParams.append(", ").append(columnName).append(" = ?"); + } + + String result = String.format(QUERY_UPDATE, + getName(), + updateParams.substring(2), + createPkWhereClause()); + return result; + } + + protected String createSelectQuery() { + + String result = String.format(QUERY_SELECT, + createSelectParams(), + getName(), + createPkWhereClause()); + return result; + } + + protected String createPkWhereClause() { + + StringBuilder pkParams = new StringBuilder(); + + for (String columnName : getPkNames()) { + pkParams.append("AND ").append(columnName).append(" = ?"); + } + + return pkParams.substring(4); + } + + protected String createSelectParams() { + + StringBuilder queryParams = new StringBuilder(); + + for (String columnName : getColumnNames()) { + queryParams.append(", ").append(columnName); + } + + return queryParams.substring(2); + } + + public String getTableLogPrefix() { + return "[" + getName() + "]"; + } +} \ No newline at end of file Property changes on: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadata.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableTool.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableTool.java (rev 0) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableTool.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,365 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.Closeable; +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +public class ReferentialSynchroTableTool implements Closeable { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(ReferentialSynchroTableTool.class); + + protected final Connection connection; + + protected final ReferentialSynchroTableMetadata table; + + protected final PreparedStatement insertStatement; + + protected final PreparedStatement updateStatement; + + protected final int columnCount; + + protected final String tableName; + + protected int insertCount = 0; + + protected int updateCount = 0; + + protected boolean debug; + + public ReferentialSynchroTableTool(Connection connection, + ReferentialSynchroTableMetadata table) throws SQLException { + this.connection = connection; + this.table = table; + this.columnCount = table.getColumnsCount(); + this.tableName = table.getName(); + + String insertSql = table.getInsertQuery(); + String updateSql = table.getUpdateQuery(); + + insertStatement = connection.prepareStatement(insertSql); + updateStatement = connection.prepareStatement(updateSql); + + debug = log.isTraceEnabled(); + } + + + public void deleteAll() throws SQLException { + PreparedStatement deleteStatement = + connection.prepareStatement( + "DELETE FROM " + table.getName()); + deleteStatement.execute(); + } + + public Object[] findByPk(List<Object> pk) throws SQLException { + String selectDataSql = table.getSelectDataQueryFromPk(); + + PreparedStatement selectStatement = + connection.prepareStatement(selectDataSql); + + int columnCountIndex = 1; + + for (Object pkColumn : pk) { + selectStatement.setObject(columnCountIndex++, pkColumn); + } + + int columnsCount = table.getColumnsCount(); + ResultSet resultSet = selectStatement.executeQuery(); + resultSet.next(); + + Object[] result = new Object[columnsCount]; + + for (int i = 1; i <= columnsCount; i++) { + + result[i - 1] = resultSet.getObject(i); + } + return result; + } + + public Set<String> getExistingPrimaryKeys() throws SQLException { + + Set<String> pkNames = table.getPkNames(); + int pkCount = pkNames.size(); + String sql = table.getExistingPrimaryKeysQuery(); + + PreparedStatement statement = connection.prepareStatement(sql); + + Set<String> result = Sets.newHashSet(); + try { + ResultSet resultSet = statement.executeQuery(); + + + while (resultSet.next()) { + List<Object> pkList = Lists.newArrayListWithCapacity(pkNames.size()); + for (int i = 1; i <= pkCount; i++) { + Object pk = resultSet.getObject(i); + pkList.add(pk); + } + String pk = table.toPkStr(pkList); + result.add(pk); + } + statement.close(); + return result; + } finally { + closeSilently(statement); + } + } + + public ResultSet getDataToUpdate(Date fromDate) throws SQLException { + + String sql = fromDate == null ? + table.getDataToUpdateQueryWithNull() : + table.getDataToUpdateQuery(); + + PreparedStatement statement = connection.prepareStatement(sql); + if (table.isWithUpdateDateColumn() && + fromDate != null) { + statement.setTimestamp(1, new Timestamp(fromDate.getTime())); + } + statement.setFetchSize(1000); + + ResultSet result = statement.executeQuery(); +// // to be able to reward on resultSet +// ((RowSet)result).setType(ResultSet.TYPE_SCROLL_INSENSITIVE); + return result; + } + + @Override + public void close() throws IOException { + closeSilently(insertStatement); + closeSilently(updateStatement); + } + + public void executeInsert(List<Object> pk, ResultSet incomingData) throws SQLException { + + List<Object> params = null; + + if (debug) { + params = Lists.newArrayList(); + } + + for (int c = 1; c <= columnCount; c++) { + Object object = incomingData.getObject(c); + insertStatement.setObject(c, object); + if (debug) { + params.add(object); + } + } + insertCount++; + + insertStatement.addBatch(); + + if (debug) { + log.debug(String.format("%s Execute insert query (pk:%s), params: %s", tableName, pk, params)); + } + + if (insertCount > 0 && insertCount % 1000 == 0) { + insertStatement.executeBatch(); + insertStatement.clearBatch(); + } + } + + public void executeInsert(List<Object> pk, Object[] incomingData) throws SQLException { + + for (int c = 1; c <= columnCount; c++) { + Object object = incomingData[c - 1]; + insertStatement.setObject(c, object); + } + insertCount++; + + insertStatement.addBatch(); + + if (debug) { + log.debug(String.format("%s Execute insert query (pk:%s), params: %s", tableName, pk, Arrays.toString(incomingData))); + } + + if (insertCount > 0 && insertCount % 1000 == 0) { + insertStatement.executeBatch(); + insertStatement.clearBatch(); + } + } + + public void executeUpdate(List<Object> pk, ResultSet incomingData) throws SQLException { + + List<Object> params = null; + + if (debug) { + params = Lists.newArrayList(); + } + + for (int c = 1; c <= columnCount; c++) { + Object object = incomingData.getObject(c); + updateStatement.setObject(c, object); + if (debug) { + params.add(object); + } + } + + int columnCountIndex = columnCount + 1; + + for (Object pkColumn : pk) { + updateStatement.setObject(columnCountIndex++, pkColumn); + } + + updateCount++; + + updateStatement.addBatch(); + + if (debug) { + log.debug(String.format("%s Execute update query (pk:%s), params: %s", tableName, pk, params)); + } + + if (updateCount > 0 && updateCount % 1000 == 0) { + updateStatement.executeBatch(); + updateStatement.clearBatch(); + } + } + + public int getInsertCount() { + return insertCount; + } + + public int getUpdateCount() { + return updateCount; + } + + public void flushQueries() throws SQLException { + + if (insertCount > 0 && insertCount % 1000 != 0) { + insertStatement.executeBatch(); + } + if (updateCount > 0 && updateCount % 1000 != 0) { + updateStatement.executeBatch(); + } + } + + /** + * Gets the last updateDate for the given {@code table} using + * the given datasource. + * + * @return the last update date of the given table, or {@code null} + * if table does not use a updateDate columns or if there + * is no data in table. + */ + public Timestamp getLastUpdateDate() throws SQLException { + Timestamp result = null; + + if (table.isWithUpdateDateColumn()) { + + String sql = table.getMaxUpdateDateQuery(); + + PreparedStatement statement = connection.prepareStatement(sql); + try { + ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + result = resultSet.getTimestamp(1); + } + statement.close(); + } finally { + closeSilently(statement); + } + } + return result; + } + + public long getCountDataToUpdate(Date fromDate) throws SQLException { + + String sql = fromDate == null ? + table.getCountDataToUpdateQueryWithNull() : + table.getCountDataToUpdateQuery(); + + PreparedStatement statement = connection.prepareStatement(sql); + if (table.isWithUpdateDateColumn() && + fromDate != null) { + statement.setTimestamp(1, new Timestamp(fromDate.getTime())); + } + + ResultSet queryResult = statement.executeQuery(); + queryResult.next(); + long result = queryResult.getLong(1); + return result; + } + + public long count() throws SQLException { + + String sql = table.getCountQuery(); + + PreparedStatement statement = connection.prepareStatement(sql); + + try { + ResultSet resultSet = statement.executeQuery(); + resultSet.next(); + long result = resultSet.getLong(1); + statement.close(); + return result; + } finally { + closeSilently(statement); + } + } + + void closeSilently(Statement statement) { + try { + if (statement != null && !statement.isClosed()) { + + statement.close(); + } + } catch (AbstractMethodError e) { + if (log.isDebugEnabled()) { + log.debug("Fix this linkage error, damned hsqlsb 1.8.0.7:("); + } + } catch (IllegalAccessError e) { + if (log.isDebugEnabled()) { + log.debug("Fix this IllegalAccessError error, damned hsqlsb 1.8.0.7:("); + } + } catch (Exception e) { + if (log.isErrorEnabled()) { + log.error("Could not close statement, but do not care", e); + } + } + } +} Property changes on: trunk/tutti-persistence/src/main/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableTool.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/service/TuttiPersistenceServiceLocator.java =================================================================== --- trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/service/TuttiPersistenceServiceLocator.java 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/service/TuttiPersistenceServiceLocator.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -25,9 +25,9 @@ */ import fr.ifremer.adagio.core.service.ServiceLocator; +import fr.ifremer.adagio.core.service.technical.synchro.ReferentialSynchroService; import fr.ifremer.tutti.persistence.TuttiPersistence; import fr.ifremer.tutti.persistence.TuttiPersistenceServiceImplementor; -import fr.ifremer.tutti.persistence.service.synchro.ReferentialSynchronizeService; /** * To obtain services from spring context. @@ -115,9 +115,11 @@ ProtocolPersistenceService.class); } - public static ReferentialSynchronizeService getReferentialSynchronizeService() { - return getPersistenceService("referentialSynchronizeService", - ReferentialSynchronizeService.class); + //TODO Move this to adagio + public static ReferentialSynchroService getReferentialSynchroService() { + ReferentialSynchroService service = instance().getService( + "referentialSynchroService", ReferentialSynchroService.class); + return service; } public static AttachmentPersistenceService getAttachmentPersistenceService() { Added: trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadataTest.java =================================================================== --- trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadataTest.java (rev 0) +++ trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadataTest.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -0,0 +1,56 @@ +package fr.ifremer.adagio.core.service.technical.synchro; + +/* + * #%L + * Tutti :: Persistence + * $Id$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2014 Ifremer + * %% + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.google.common.collect.Lists; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +/** + * Created on 1/14/14. + * + * @author Tony Chemit <chemit@codelutin.com> + * @since 3.0 + */ +public class ReferentialSynchroTableMetadataTest { + + @Test + public void getPkStr() { + + List<Object> pk = Lists.<Object>newArrayList("a", null, 3); + + ReferentialSynchroTableMetadata table = new ReferentialSynchroTableMetadata(); + + String pkStr = table.toPkStr(pk); + Assert.assertEquals("~|a~|null~|3", pkStr); + + List<Object> fromPkStr = table.fromPkStr(pkStr); + + Assert.assertEquals(Lists.<Object>newArrayList("a", null, "3"), fromPkStr); + } + +} Property changes on: trunk/tutti-persistence/src/test/java/fr/ifremer/adagio/core/service/technical/synchro/ReferentialSynchroTableMetadataTest.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/tutti-service/src/license/THIRD-PARTY.properties =================================================================== --- trunk/tutti-service/src/license/THIRD-PARTY.properties 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-service/src/license/THIRD-PARTY.properties 2014-01-15 08:43:26 UTC (rev 1486) @@ -20,7 +20,6 @@ # - Lesser General Public License (LPGL) # - Lesser General Public License (LPGL) v 2.1 # - MIT License -# - MPL 1.1 # - Mozilla Public License # - New BSD License # - Public Domain @@ -31,7 +30,7 @@ # Please fill the missing licenses for dependencies : # # -#Sun Dec 08 20:03:42 CET 2013 +#Wed Jan 15 09:00:37 CET 2014 antlr--antlr--2.7.6=BSD License batik--batik-awt-util--1.6=The Apache Software License, Version 2.0 batik--batik-bridge--1.6=The Apache Software License, Version 2.0 @@ -48,4 +47,5 @@ batik--batik-xml--1.6=The Apache Software License, Version 2.0 commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0 dom4j--dom4j--1.6.1=BSD License +javassist--javassist--3.11.0.GA=The Apache Software License, Version 2.0 javax.transaction--jta--1.1=COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 Modified: trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java =================================================================== --- trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -120,8 +120,6 @@ protected Cruise cruise; -// protected TuttiProtocol protocol; - protected FishingOperation fishingOperation; protected List<Caracteristic> caracteristics; @@ -211,6 +209,7 @@ resetPersons(); resetSpecies(); resetValidationDataContext(); + resetCaracteristics(); } public void checkDbContext() { @@ -777,10 +776,14 @@ referentSpecies = null; referentSpeciesWithSurveyCode = null; referentBenthosWithSurveyCode = null; + } public void resetCaracteristics() { caracteristics = null; + caracteristicsWithProtected = null; + genderValues = null; + deadOrAliveValues = null; } public void loadSampleCategoryModel(SampleCategoryModel sampleCategoryModel) { Modified: trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/referential/TuttiReferentialSynchronizeService.java =================================================================== --- trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/referential/TuttiReferentialSynchronizeService.java 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-service/src/main/java/fr/ifremer/tutti/service/referential/TuttiReferentialSynchronizeService.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -24,11 +24,11 @@ * #L% */ +import fr.ifremer.adagio.core.service.technical.synchro.ReferentialSynchroResult; +import fr.ifremer.adagio.core.service.technical.synchro.ReferentialSynchroService; import fr.ifremer.tutti.TuttiConfiguration; import fr.ifremer.tutti.persistence.entities.TuttiEntities; import fr.ifremer.tutti.persistence.service.TuttiPersistenceServiceLocator; -import fr.ifremer.tutti.persistence.service.synchro.ReferentialSynchronizeResult; -import fr.ifremer.tutti.persistence.service.synchro.ReferentialSynchronizeService; import fr.ifremer.tutti.service.AbstractTuttiService; import fr.ifremer.tutti.service.PersistenceService; import fr.ifremer.tutti.service.TuttiServiceContext; @@ -44,22 +44,22 @@ protected PersistenceService persistenceService; - protected ReferentialSynchronizeService synchroService; + protected ReferentialSynchroService synchroService; @Override public void setServiceContext(TuttiServiceContext context) { super.setServiceContext(context); - synchroService = TuttiPersistenceServiceLocator.getReferentialSynchronizeService(); + synchroService = TuttiPersistenceServiceLocator.getReferentialSynchroService(); persistenceService = getService(PersistenceService.class); } - public void prepare(File dbDirectory, ReferentialSynchronizeResult result) { + public void prepare(File dbDirectory, ReferentialSynchroResult result) { Properties remoteConnectionProperties = getRemoteProperties(dbDirectory); synchroService.prepare(remoteConnectionProperties, result); } public void synchronize(File dbDirectory, - ReferentialSynchronizeResult result) { + ReferentialSynchroResult result) { Properties remoteConnectionProperties = getRemoteProperties(dbDirectory); synchroService.synchronize(remoteConnectionProperties, result); } Modified: trunk/tutti-ui-swing/src/license/THIRD-PARTY.properties =================================================================== --- trunk/tutti-ui-swing/src/license/THIRD-PARTY.properties 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-ui-swing/src/license/THIRD-PARTY.properties 2014-01-15 08:43:26 UTC (rev 1486) @@ -30,7 +30,7 @@ # Please fill the missing licenses for dependencies : # # -#Mon Dec 09 13:48:21 CET 2013 +#Wed Jan 15 09:38:43 CET 2014 antlr--antlr--2.7.6=BSD License batik--batik-awt-util--1.6=The Apache Software License, Version 2.0 batik--batik-bridge--1.6=The Apache Software License, Version 2.0 Modified: trunk/tutti-ui-swing/src/main/filtered-resources/log4j.properties =================================================================== --- trunk/tutti-ui-swing/src/main/filtered-resources/log4j.properties 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-ui-swing/src/main/filtered-resources/log4j.properties 2014-01-15 08:43:26 UTC (rev 1486) @@ -34,6 +34,7 @@ #See https://forum.hibernate.org/viewtopic.php?p=2404391 log4j.logger.org.hibernate.engine.StatefulPersistenceContext.ProxyWarnLog=ERROR +log4j.logger.fr.ifremer.adagio.core.service.technical.synchro=DEBUG log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.file=${tutti.log.file} Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiApplicationUpdaterCallBack.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiApplicationUpdaterCallBack.java 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiApplicationUpdaterCallBack.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -230,7 +230,7 @@ File cacheDirectory = config.getCacheDirectory(); ApplicationIOUtil.forceDeleteOnExit( cacheDirectory, - _("tutti.applicationUpdater.updateDone.deleteDirectory.caches.error", i18nDirectory) + _("tutti.applicationUpdater.updateDone.deleteDirectory.caches.error", cacheDirectory) ); } } Modified: trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiDbUpdaterCallBack.java =================================================================== --- trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiDbUpdaterCallBack.java 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/TuttiDbUpdaterCallBack.java 2014-01-15 08:43:26 UTC (rev 1486) @@ -26,12 +26,13 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Maps; +import fr.ifremer.adagio.core.service.technical.synchro.ReferentialSynchroResult; import fr.ifremer.shared.application.ApplicationTechnicalException; import fr.ifremer.shared.application.swing.action.ApplicationActionException; import fr.ifremer.shared.application.swing.action.ApplicationActionUI; import fr.ifremer.tutti.TuttiConfiguration; import fr.ifremer.tutti.persistence.ProgressionModel; -import fr.ifremer.tutti.persistence.service.synchro.ReferentialSynchronizeResult; +import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel; import fr.ifremer.tutti.service.PersistenceService; import fr.ifremer.tutti.service.referential.TuttiReferentialSynchronizeService; import fr.ifremer.tutti.ui.swing.action.AbstractTuttiAction; @@ -227,7 +228,7 @@ log.info(String.format("A database update was downloaded (oldVersion: %s, newVersion: %s), will launch a referential synchronize operation ", info.oldVersion, info.newVersion)); } TuttiReferentialSynchronizeService service = context.getTuttiReferentialSynchronizeService(); - ReferentialSynchronizeResult result = new ReferentialSynchronizeResult(); + ReferentialSynchroResult result = new ReferentialSynchroResult(); File dbDirectory = getDbDirectory(info); ApplicationActionUI actionUI = context.getActionUI(); @@ -251,6 +252,15 @@ PersistenceService persistence = context.getPersistenceService(); persistence.clearAllCaches(); + // clean data context + if (log.isInfoEnabled()) { + log.info("Clean data context."); + } + SampleCategoryModel sampleCategoryModel = + context.getDataContext().getSampleCategoryModel(); + context.getDataContext().clearContext(); + context.getDataContext().loadSampleCategoryModel(sampleCategoryModel); + // replace the version.appup file content File target = context.getConfig().getDbDirectory(); File versionFile = ApplicationUpdater.getVersionFile(target); @@ -260,7 +270,8 @@ try { ApplicationUpdater.storeVersionFile(target, info.newVersion); } catch (IOException e) { - throw new ApplicationTechnicalException(_("tutti.applicationUpdater.synchroDB.writeVersion.error", versionFile)); + throw new ApplicationTechnicalException( + _("tutti.applicationUpdater.synchroDB.writeVersion.error", versionFile)); } } } Modified: trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties =================================================================== --- trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties 2014-01-13 15:19:06 UTC (rev 1485) +++ trunk/tutti-ui-swing/src/main/resources/i18n/tutti-ui-swing_fr_FR.properties 2014-01-15 08:43:26 UTC (rev 1486) @@ -301,7 +301,7 @@ tutti.dbManager.action.upgradeDb=Mettre à jour les référentiels tutti.dbManager.action.upgradeDb.check=Recherche des mises à jour de la base tutti.dbManager.action.upgradeDb.done=La mise à jour des référentiel en version <strong>%s</strong> est terminée. -tutti.dbManager.action.upgradeDb.mnemonic=V +tutti.dbManager.action.upgradeDb.mnemonic=M tutti.dbManager.action.upgradeDb.no.backup.db.choosen=La base ne sera pas migrée (vous avez annulé la sauvegarde avant migration). tutti.dbManager.action.upgradeDb.opening=Ouverture de la base de données tutti.dbManager.action.upgradeDb.reloading=Rechargement de la base de données @@ -313,7 +313,7 @@ tutti.dbManager.action.upgradeDb.schema.version.not.found=L'application n'a pas pu déterminer la version de la base de données à importer. L'import ne peut pas être réalisé, veuillez contacter les administrateurs de l'application. tutti.dbManager.action.upgradeDb.tip=Mettre à jour les référentiels tutti.dbManager.action.upgradeDb.upToDate=<strong>Aucune mise à jour de base détectée</strong> -tutti.dbManager.caracteristic.lastReferentialVersion=Version du référentiel disponible en mis à jour +tutti.dbManager.caracteristic.lastReferentialVersion=Version du référentiel disponible en mise à jour tutti.dbManager.caracteristic.referentialVersion=Version du référentiel utilisé tutti.dbManager.caracteristic.schemaVersion=Version du schema tutti.dbManager.caracteristic.url=Url de connexion @@ -1472,6 +1472,8 @@ tutti.updateReport.message.success=La mise à jour des rapports nécessite le redémarrage de l'application tutti.updateReport.noUpdate=<strong>Aucune mise à jour de rapports détectée.</strong> tutti.updateReport.title.success=Redémarrage de l'application nécessaire... +tutti.upgradeDb.message.success=La mise à jour des référentiels nécessite le redémarrage de l'application +tutti.upgradeDb.title.success=Redémarrage de l'application nécessaire... tutti.validateCruise.action.export.all.chooseFile.label=Choisir le fichier d'export tutti.validateCruise.action.export.all.chooseFile.title=Exporter les messages de validation de la campagne tutti.validateCruise.action.export.all.success=Les messages de validation des captures ont correctement été exporté dans le fichier %s