/* * Copyright 2014-2016 CyberVision, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaaproject.kaa.server.datamigration; import static java.util.stream.Collectors.joining; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.kaaproject.kaa.server.datamigration.model.Schema; import org.kaaproject.kaa.server.datamigration.utils.BaseSchemaIdCounter; import org.kaaproject.kaa.server.datamigration.utils.datadefinition.Constraint; import org.kaaproject.kaa.server.datamigration.utils.datadefinition.DataDefinition; import org.kaaproject.kaa.server.datamigration.utils.datadefinition.ReferenceOptions; import java.sql.Connection; import java.sql.SQLException; import java.util.List; public abstract class AbstractCtlMigration { protected Connection connection; protected QueryRunner runner; protected DataDefinition dd; protected Long idShift; /** * Create entity that responsible for data migration from old tables to new ctl based ones. * * @param connection the connection to relational database */ public AbstractCtlMigration(Connection connection) { this.connection = connection; runner = new QueryRunner(); dd = new DataDefinition(connection); } /** * Do necessary operation to database before execution of {@link AbstractCtlMigration#transform()} * method. * * @throws SQLException the sql exception */ public void beforeTransform() throws SQLException { // delete relation between <table_prefix>_schems to schems dd.dropUnnamedFk(getPrefixTableName() + "_schems", "schems"); } /** * Do main part of data migration from old tables to new ctl based ones. * * @throws SQLException the sql exception */ protected List<Schema> transform() throws SQLException { // fetch schemas of appropriate feature like configuration List<Schema> schemas = runner.query(connection, "select " + "f.id as id, created_time as createdTime, created_username as createdUsername, " + "description, name, schems, version, application_id as appId " + "from " + getPrefixTableName() + "_schems f join schems s on f.id = s.id", new BeanListHandler<>(Schema.class)); // delete the fetched ids from schema table String toDelete = schemas.stream().map(s -> s.getId().toString()).collect(joining(", ")); String notEmptyIdSet = "^[\\s]*([0-9]+(\\,\\s)?)+"; if (toDelete.matches(notEmptyIdSet)) { runner.update(connection, "delete from schems where id in (" + toDelete + ")"); } // shift ids in order to avoid PK constraint violation during adding record to base_schema Long shift = runner.query(connection, "select max(id) as max_id from " + getPrefixTableName() + "_schems", rs -> rs.next() ? rs.getLong("max_id") : null); idShift = BaseSchemaIdCounter.getInstance().getAndShift(shift); runner.update(connection, "update " + getPrefixTableName() + "_schems set id = id + " + idShift + " order by id desc"); schemas.forEach(s -> s.setId(s.getId() + idShift)); return schemas; } /** * Do necessary operation to database after execution of {@link AbstractCtlMigration#transform()} * method. * * @throws SQLException the sql exception */ public void afterTransform() throws SQLException { dd.alterTable(getPrefixTableName() + "_schems") .add(Constraint.constraint("FK_" + getPrefixTableName() + "_base_schems_id") .foreignKey("id") .references("base_schems", "id") .onDelete(ReferenceOptions.CASCADE) .onUpdate(ReferenceOptions.CASCADE) ) .execute(); } protected abstract String getPrefixTableName(); }