/* ********************************************************************** **
** Copyright notice **
** **
** (c) 2005-2009 RSSOwl Development Team **
** http://www.rssowl.org/ **
** **
** All rights reserved **
** **
** This program and the accompanying materials are made available under **
** the terms of the Eclipse Public License v1.0 which accompanies this **
** distribution, and is available at: **
** http://www.rssowl.org/legal/epl-v10.html **
** **
** A copy is found in the file epl-v10.html and important notices to the **
** license from the team is found in the textfile LICENSE.txt distributed **
** in this package. **
** **
** This copyright notice MUST APPEAR in all copies of the file! **
** **
** Contributors: **
** RSSOwl Development Team - initial API and implementation **
** **
** ********************************************************************** */
package org.rssowl.core.internal.persist.migration;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.rssowl.core.internal.persist.service.ConfigurationFactory;
import org.rssowl.core.internal.persist.service.Migration;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
/**
* This object is responsible for holding the currently supported migrations and
* making them available on request.
*/
public final class Migrations {
public static class ChainedMigration implements Migration {
private final List<Migration> fMigrations;
private final int fDestinationFormat;
private final int fOriginFormat;
public ChainedMigration(int originFormat, int destinationFormat, List<Migration> migrations) {
fOriginFormat = originFormat;
fDestinationFormat = destinationFormat;
fMigrations = migrations;
}
/*
* @see
* org.rssowl.core.internal.persist.service.Migration#getDestinationFormat()
*/
public int getDestinationFormat() {
return fDestinationFormat;
}
/*
* @see org.rssowl.core.internal.persist.service.Migration#getOriginFormat()
*/
public int getOriginFormat() {
return fOriginFormat;
}
public List<Migration> getMigrations() {
return Collections.unmodifiableList(fMigrations);
}
/*
* @see
* org.rssowl.core.internal.persist.service.Migration#migrate(org.rssowl
* .core.internal.persist.service.ConfigurationFactory, java.lang.String,
* org.eclipse.core.runtime.IProgressMonitor)
*/
public MigrationResult migrate(ConfigurationFactory configFactory, String dbFileName, IProgressMonitor progressMonitor) {
boolean reindex = false;
boolean optimize = false;
boolean defragment = false;
for (Migration migration : fMigrations) {
MigrationResult migrationResult = migration.migrate(configFactory, dbFileName, progressMonitor);
reindex |= migrationResult.isReindex();
optimize |= migrationResult.isOptimizeIndex();
defragment |= migrationResult.isDefragmentDatabase();
}
return new MigrationResult(reindex, optimize, defragment);
}
}
private final List<Migration> fMigrations;
/**
* Creates an instance of this object.
*/
public Migrations() {
fMigrations = Arrays.<Migration> asList(new Migration2To3(), new Migration3To4(), new Migration4To5(), new Migration2To5());
}
public Migrations(Migration... migrations) {
fMigrations = Arrays.asList(migrations);
}
/**
* @return the {@link List} of migrations.
*/
public List<Migration> getMigrations() {
return Collections.unmodifiableList(fMigrations);
}
/**
* Returns a Migration that satisfies {@code originFormat} and
* {@code destinationFormat} or {@code null} if none can be found.
*
* @param originFormat The current format of the database.
* @param destinationFormat The desired format of the database.
* @return a Migration or {@code} null.
*/
public final Migration getMigration(int originFormat, int destinationFormat) {
Assert.isLegal(originFormat < destinationFormat, "Only forward migrations supported currently, originFormat: " + originFormat + ", destinationFormat: " + destinationFormat); //$NON-NLS-1$ //$NON-NLS-2$
Migration migration = doGetMigration(originFormat, destinationFormat);
if (migration != null)
return migration;
List<Migration> chainedMigrations = findChainedMigrations(originFormat, destinationFormat);
if (chainedMigrations.isEmpty())
return null;
return new ChainedMigration(originFormat, destinationFormat, chainedMigrations);
}
private Migration doGetMigration(int originFormat, int destinationFormat) {
for (Migration migration : fMigrations) {
if (migration.getOriginFormat() == originFormat && migration.getDestinationFormat() == destinationFormat) {
return migration;
}
}
return null;
}
private List<Migration> findChainedMigrations(int originFormat, int destinationFormat) {
LinkedList<LinkedList<Migration>> migrationsQueues = createMigrationsQueues(originFormat, destinationFormat);
List<Migration> smallestQueue = Collections.emptyList();
for (LinkedList<Migration> migrationQueue : migrationsQueues) {
if (smallestQueue.isEmpty() || migrationQueue.size() < smallestQueue.size())
smallestQueue = migrationQueue;
}
return smallestQueue;
}
private LinkedList<LinkedList<Migration>> createMigrationsQueues(int originFormat, int destinationFormat) {
LinkedList<LinkedList<Migration>> migrationQueues = new LinkedList<LinkedList<Migration>>();
for (Migration migration : fMigrations) {
if (migration.getOriginFormat() == originFormat) {
LinkedList<Migration> migrationQueue = new LinkedList<Migration>();
migrationQueue.add(migration);
migrationQueues.add(migrationQueue);
}
}
return findMigrationQueues(migrationQueues, destinationFormat);
}
private LinkedList<LinkedList<Migration>> findMigrationQueues(LinkedList<LinkedList<Migration>> migrationQueues, int destinationFormat) {
boolean changed = false;
LinkedList<LinkedList<Migration>> migrationQueuesCopy = new LinkedList<LinkedList<Migration>>(migrationQueues);
for (ListIterator<LinkedList<Migration>> it = migrationQueuesCopy.listIterator(); it.hasNext();) {
LinkedList<Migration> migrationQueue = it.next();
Migration migration = migrationQueue.getLast();
if (migration.getDestinationFormat() == destinationFormat)
continue;
it.remove();
for (Migration innerMigration : fMigrations) {
if (migration.equals(innerMigration))
continue;
if (migration.getDestinationFormat() == innerMigration.getOriginFormat()) {
changed = true;
LinkedList<Migration> newMigrationQueue = new LinkedList<Migration>(migrationQueue);
newMigrationQueue.add(innerMigration);
it.add(newMigrationQueue);
}
}
}
if (changed)
return findMigrationQueues(migrationQueuesCopy, destinationFormat);
return migrationQueuesCopy;
}
}