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

com.hhandoko.cassandra.migration.internal.resolver.CompositeMigrationResolver.kt Maven / Gradle / Ivy

/**
 * File     : CompositeMigrationResolver.kt
 * License  :
 *   Original   - Copyright (c) 2010 - 2016 Boxfuse GmbH
 *   Derivative - Copyright (c) 2016 - 2018 cassandra-migration Contributors
 *
 *   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 com.hhandoko.cassandra.migration.internal.resolver

import com.hhandoko.cassandra.migration.api.CassandraMigrationException
import com.hhandoko.cassandra.migration.api.resolver.MigrationResolver
import com.hhandoko.cassandra.migration.api.resolver.ResolvedMigration
import com.hhandoko.cassandra.migration.internal.resolver.cql.CqlMigrationResolver
import com.hhandoko.cassandra.migration.internal.resolver.java.JavaMigrationResolver
import com.hhandoko.cassandra.migration.internal.util.Locations
import java.util.*

/**
 * Facility for retrieving and sorting the available migrations from the classpath through the various migration
 * resolvers.
 *
 * @param classLoader The ClassLoader for loading migrations on the classpath.
 * @param locations The locations where migrations are located.
 * @param encoding The CQL migrations encoding.
 * @param timeout The CQL migrations read timeout duration in seconds.
 * @param customMigrationResolvers Custom Migration Resolvers.
 */
class CompositeMigrationResolver(
    classLoader: ClassLoader,
    locations: Locations,
    encoding: String,
    timeout: Int,
    vararg customMigrationResolvers: MigrationResolver
) : MigrationResolver {

    /**
     * The migration resolvers to use internally.
     */
    private val migrationResolvers = ArrayList()

    /**
     * The available migrations, sorted by version, newest first. An empty list is returned when no migrations can be
     * found.
     */
    private var availableMigrations: List? = null

    /**
     * CompositeMigrationResolver initialization.
     */
    init {
        locations.getLocations().forEach {
            migrationResolvers.add(CqlMigrationResolver(classLoader, it, encoding, timeout))
            migrationResolvers.add(JavaMigrationResolver(classLoader, it))
        }

        migrationResolvers.addAll(Arrays.asList(*customMigrationResolvers))
    }

    /**
     * Finds all available migrations using all migration resolvers (CQL, Java, ...).
     *
     * @return The available migrations, sorted by version, oldest first. An empty list is returned when no migrations
     *         can be found.
     * @throws CassandraMigrationException when the available migrations have overlapping versions.
     */
    override fun resolveMigrations(): List {
        if (availableMigrations == null) {
            availableMigrations = doFindAvailableMigrations()
        }

        return availableMigrations as List
    }

    /**
     * Finds all available migrations using all migration resolvers (CQL, Java, ...).
     *
     * @return The available migrations, sorted by version, oldest first. An empty list is returned when no migrations
     *         can be found.
     * @throws CassandraMigrationException when the available migrations have overlapping versions.
     */
    @Throws(CassandraMigrationException::class)
    private fun doFindAvailableMigrations(): List {
        val migrations = ArrayList(collectMigrations(migrationResolvers))
        migrations.sortWith(ResolvedMigrationComparator())

        checkForIncompatibilities(migrations)

        return migrations
    }

    /**
     * CompositeMigrationResolver companion object.
     */
    companion object {

        /**
         * Collects all the migrations for all migration resolvers.
         *
         * @param migrationResolvers The migration resolvers to check.
         * @return All migrations.
         */
        fun collectMigrations(migrationResolvers: Collection): Collection {
            return migrationResolvers.flatMap { it.resolveMigrations() }.distinct()
        }

        /**
         * Checks for incompatible migrations.
         *
         * @param migrations The migrations to check.
         * @throws CassandraMigrationException when two different migration with the same version number are found.
         */
        fun checkForIncompatibilities(migrations: List) {

            /**
             * Returns incompatible migration error message.
             *
             * @param current The current migration run.
             * @param next The next migration to run.
             * @return Incompatible migration error message.
             */
            fun incompatibleErrorMsg(current: ResolvedMigration, next: ResolvedMigration): String {
                return "Found more than one migration with version ${current.version}\nOffenders:\n-> ${current.physicalLocation} (${current.type})\n-> ${next.physicalLocation} (${next.type})"
            }

            // Check for more than one migration with same version
            for (i in 0..migrations.size - 1 - 1) {
                val current = migrations[i]
                val next = migrations[i + 1]
                if (current.version!!.compareTo(next.version) == 0) {
                    throw CassandraMigrationException(incompatibleErrorMsg(current, next))
                }
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy