All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.topia.service.migration.TopiaMigrationService Maven / Gradle / Ivy

The newest version!
package org.nuiton.topia.service.migration;

/*-
 * #%L
 * ObServe Toolkit :: ToPIA Migration service
 * %%
 * Copyright (C) 2017 - 2018 IRD, Ultreia.io
 * %%
 * 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
 * .
 * #L%
 */

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.nuiton.topia.persistence.TopiaApplicationContext;
import org.nuiton.topia.persistence.TopiaMigrationServiceException;
import org.nuiton.topia.persistence.internal.support.HibernateTopiaSqlSupport;
import org.nuiton.topia.persistence.support.TopiaSqlSupport;
import org.nuiton.topia.persistence.script.SqlScriptConsumer;
import org.nuiton.topia.service.migration.resources.MigrationVersionResource;
import org.nuiton.util.TimeLog;
import org.nuiton.version.Version;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * Topia migration service default implementation.
 * 

* This new version of the migration service requires no configuration by default. *

* The only thing you ca, configure is the migration user callback (see @link {@link TopiaMigrationServiceAskUserToMigrate}. *

* Created by tchemit on 05/05/2018. * * @author Tony Chemit - [email protected] */ @SuppressWarnings("WeakerAccess") public class TopiaMigrationService implements org.nuiton.topia.persistence.TopiaMigrationService { private static final TimeLog TIME_LOG = new TimeLog(TopiaMigrationService.class, 100, 1000); private static final Log log = LogFactory.getLog(TopiaMigrationService.class); /** * Configuration of service. */ protected TopiaMigrationServiceConfiguration configuration; /** * Contains all states of the service. */ protected TopiaMigrationServiceContext context; @Override public String getSchemaVersion() throws TopiaMigrationServiceException { return getContext().getDbVersion().getVersion(); } @Override public void initOnCreateSchema() throws TopiaMigrationServiceException { // Schema has just been created, save the application version getContext().createSchemaIfNotExist(); getContext().saveModelVersion(); } @Override public void runSchemaMigration() throws TopiaMigrationServiceException { TopiaMigrationServiceContext context = getContext(); Version modelVersion = context.getModelVersion(); Version dbVersion = context.getDbVersion(); boolean dbNotVersioned = context.isDbNotVersioned(); boolean versionTableExist = context.isVersionTableExist(); log.info(String.format("Starting Topia Migration Service - Model version : %s, Database version : %s", modelVersion, dbVersion)); log.debug(String.format("Is db not versioned ? = %s", dbNotVersioned)); log.debug(String.format("TMSVersion exists = %s", versionTableExist)); if (!versionTableExist) { context.createSchemaIfNotExist(); } if (versionTableExist && dbVersion.equals(modelVersion)) { log.info("Database is up to date, no migration needed."); return; } if (versionTableExist && dbNotVersioned) { log.info("Database is empty, no migration needed."); context.saveModelVersion(); return; } List allVersions = context.getResources().getAvailableVersions(); log.info(String.format("Available versions: %1$s", allVersions)); List versionsToApply = context.getResources().getVersionsAfter(dbVersion); if (versionsToApply.isEmpty()) { log.info("No version to apply, no migration needed."); context.saveModelVersion(); return; } log.info(String.format("Versions to apply: %1$s", versionsToApply)); Optional askUserToMigrate = context.getAskUserToMigrate(); // ask to perform the migration boolean performMigration = askUserToMigrate.map(c -> c.canIMigrate(dbVersion, versionsToApply)).orElse(true); log.debug("Handler choose : " + performMigration); if (!performMigration) { // user cancel migration return; } long statementCount = 0; for (Version version : versionsToApply) { long t0 = TimeLog.getTime(); long versionCount = migrateVersion(context, version); statementCount += versionCount; TIME_LOG.log(t0, "migrationVersion", version.toString() + " - " + versionCount + " sql statements"); } log.info(String.format("Ends migration - db version: %s - consume %d sql statement(s)", context.getDbVersion(), statementCount)); } @Override public void initTopiaService(TopiaApplicationContext topiaApplicationContext, Map serviceConfiguration) { this.configuration = TopiaMigrationServiceConfiguration.of(Objects.requireNonNull(topiaApplicationContext)); } @Override public void close() { context = null; } protected long migrateVersion(TopiaMigrationServiceContext context, Version version) { MigrationVersionResource resource = context.getResource(version); try (SessionFactory sessionFactory = context.newSessionFactory()) { try (Session session = sessionFactory.openSession()) { session.getTransaction().begin(); TopiaSqlSupport sqlSupport = new HibernateTopiaSqlSupport(session); try (TopiaMigrationServiceExecutor executor = context.newExecutor(version, sqlSupport)) { String logPrefix = executor.getLogPrefix(); log.info(logPrefix + "Start schema migration."); resource.generateSqlScript(executor); long inStatementCount = executor.flush(); log.info(logPrefix + String.format("Discover %d sql statement(s) to apply.", inStatementCount)); long outStatementCount; try (SqlScriptConsumer sqlWork = SqlScriptConsumer.of(executor.getScriptForVersion())) { sqlSupport.doSqlWork(sqlWork); outStatementCount = sqlWork.getStatementCount(); log.info(logPrefix + String.format("Consume %d sql statement(s).", outStatementCount)); } context.saveVersion(version); session.getTransaction().commit(); return outStatementCount; } catch (Exception e) { // Exception, rollback transaction log.error("Exception during schema migration on version: " + version + ", rollback transaction", e); if (TransactionStatus.ACTIVE == session.getTransaction().getStatus()) { session.getTransaction().rollback(); } throw new TopiaMigrationServiceException("Exception during schema migration on version: " + version, e); } } } } public void createSchemaIfNotExist() { getContext().createSchemaIfNotExist(); } public TopiaMigrationServiceContext getContext() { return context == null ? context = TopiaMigrationServiceContext.of(configuration) : context; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy