/**
* Copyright 2010-2015 Axel Fontaine
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.contrastsecurity.cassandra.migration.resolver;
import com.contrastsecurity.cassandra.migration.CassandraMigrationException;
import com.contrastsecurity.cassandra.migration.config.ScriptsLocation;
import com.contrastsecurity.cassandra.migration.config.ScriptsLocations;
import com.contrastsecurity.cassandra.migration.info.ResolvedMigration;
import com.contrastsecurity.cassandra.migration.resolver.cql.CqlMigrationResolver;
import com.contrastsecurity.cassandra.migration.resolver.java.JavaMigrationResolver;
import java.util.*;
/**
* Facility for retrieving and sorting the available migrations from the classpath through the various migration
* resolvers.
*/
public class CompositeMigrationResolver implements MigrationResolver {
/**
* The migration resolvers to use internally.
*/
private Collection<MigrationResolver> migrationResolvers = new ArrayList<MigrationResolver>();
/**
* The available migrations, sorted by version, newest first. An empty list is returned when no migrations can be
* found.
*/
private List<ResolvedMigration> availableMigrations;
/**
* Creates a new CompositeMigrationResolver.
*
* @param classLoader The ClassLoader for loading migrations on the classpath.
* @param locations The locations where migrations are located.
* @param encoding The encoding of Cql migrations.
* @param customMigrationResolvers Custom Migration Resolvers.
*/
public CompositeMigrationResolver(ClassLoader classLoader, ScriptsLocations locations,
String encoding,
MigrationResolver... customMigrationResolvers) {
for (ScriptsLocation location : locations.getLocations()) {
migrationResolvers.add(new CqlMigrationResolver(classLoader, location, encoding));
migrationResolvers.add(new JavaMigrationResolver(classLoader, location));
}
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.
*/
public List<ResolvedMigration> resolveMigrations() {
if (availableMigrations == null) {
availableMigrations = doFindAvailableMigrations();
}
return availableMigrations;
}
/**
* 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.
*/
private List<ResolvedMigration> doFindAvailableMigrations() throws CassandraMigrationException {
List<ResolvedMigration> migrations = new ArrayList<ResolvedMigration>(collectMigrations(migrationResolvers));
Collections.sort(migrations, new ResolvedMigrationComparator());
checkForIncompatibilities(migrations);
return migrations;
}
/**
* Collects all the migrations for all migration resolvers.
*
* @param migrationResolvers The migration resolvers to check.
* @return All migrations.
*/
/* private -> for testing */
static Collection<ResolvedMigration> collectMigrations(Collection<MigrationResolver> migrationResolvers) {
Set<ResolvedMigration> migrations = new HashSet<ResolvedMigration>();
for (MigrationResolver migrationResolver : migrationResolvers) {
migrations.addAll(migrationResolver.resolveMigrations());
}
return migrations;
}
/**
* Checks for incompatible migrations.
*
* @param migrations The migrations to check.
* @throws CassandraMigrationException when two different migration with the same version number are found.
*/
/* private -> for testing */
static void checkForIncompatibilities(List<ResolvedMigration> migrations) {
// check for more than one migration with same version
for (int i = 0; i < migrations.size() - 1; i++) {
ResolvedMigration current = migrations.get(i);
ResolvedMigration next = migrations.get(i + 1);
if (current.getVersion().compareTo(next.getVersion()) == 0) {
throw new CassandraMigrationException(String.format("Found more than one migration with version %s\nOffenders:\n-> %s (%s)\n-> %s (%s)",
current.getVersion(),
current.getPhysicalLocation(),
current.getType(),
next.getPhysicalLocation(),
next.getType()));
}
}
}
}