blob: 84247a65abb2741fe8c5d77671e18b81ab4c870e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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.eclipse.org/legal/epl-v10.html
*
* Contributors:
* wesendon
* koegel
* jfaltermeier
******************************************************************************/
package org.eclipse.emf.emfstore.internal.server.startup;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.emfstore.common.ESSystemOutProgressMonitor;
import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.internal.migration.EMFStoreMigrationException;
import org.eclipse.emf.emfstore.internal.migration.EMFStoreMigrator;
import org.eclipse.emf.emfstore.internal.migration.EMFStoreMigratorUtil;
import org.eclipse.emf.emfstore.internal.server.exceptions.FatalESException;
import org.eclipse.emf.emfstore.internal.server.model.ProjectHistory;
import org.eclipse.emf.emfstore.internal.server.model.ServerSpace;
import org.eclipse.emf.emfstore.internal.server.model.versioning.FileBasedChangePackage;
import org.eclipse.emf.emfstore.internal.server.model.versioning.Version;
import org.eclipse.emf.emfstore.internal.server.model.versioning.VersioningFactory;
import org.eclipse.emf.emfstore.internal.server.model.versioning.impl.FileBasedChangePackageImpl;
import org.eclipse.emf.emfstore.internal.server.model.versioning.impl.persistent.Direction;
import org.eclipse.emf.emfstore.internal.server.model.versioning.impl.persistent.SerializedOperationEmitter;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.OperationsPackage;
import org.eclipse.emf.emfstore.server.ESServerURIUtil;
import com.google.common.base.Optional;
/**
* Applies migrator to files on server.
*
* @author koegel
* @author wesendon
* @author jfaltermeier
*/
@SuppressWarnings("restriction")
public final class MigrationManager {
private MigrationManager() {
}
/**
* Performs a migration of the server space.
*
* @param resourceSet a resource set which contains all necessary converters/handler and may be safely used by the
* migrator.
* @param inMemoryChangePackage <code>true</code> if server is configured to use in memory change packages,
* <code>false</code> otherwise
* @throws FatalESException in case of a fatal state
*/
public static void migrate(ResourceSet resourceSet, boolean inMemoryChangePackage) throws FatalESException {
/* check if migrator is available */
if (!EMFStoreMigratorUtil.isMigratorAvailable()) {
return;
}
/* get migrator */
EMFStoreMigrator migrator = null;
try {
migrator = EMFStoreMigratorUtil.getEMFStoreMigrator();
} catch (final EMFStoreMigrationException ex1) {
throw new FatalESException(
"No EMFStore Migrator could be created even though a migrator should be available."); //$NON-NLS-1$
}
/* load server space in order to access versions */
final URI serverSpaceURI = ESServerURIUtil.createServerSpaceURI();
final Resource resource = resourceSet.createResource(serverSpaceURI);
try {
resource.load(null);
} catch (final IOException ex) {
ModelUtil.logException(ex);
return;
}
final ServerSpace serverSpace = (ServerSpace) resource.getContents().get(0);
/* get uris which might have to be migrated */
final Set<URI> urisToMigrate = new LinkedHashSet<URI>();
final Map<URI, List<URI>> fileBasedCPToTempFiles = new LinkedHashMap<URI, List<URI>>();
fillURIsToMigrate(resourceSet.getURIConverter(), serverSpace, urisToMigrate, fileBasedCPToTempFiles,
inMemoryChangePackage);
/* check if all URIs may be handled by the migrator */
final Set<URI> urisWhichCantBeHandled = migrator.canHandle(urisToMigrate);
if (!urisWhichCantBeHandled.isEmpty()) {
urisToMigrate.removeAll(urisWhichCantBeHandled);
for (final URI uri : urisWhichCantBeHandled) {
ModelUtil.logInfo(MessageFormat.format(
"No migrator found for URI {0}. If a migration is needed for this URI you may encounter problems.", //$NON-NLS-1$
uri));
}
}
/* get URIs that actually need migration */
final Set<URI> urisWhichNeedMigration = migrator.needsMigration(urisToMigrate);
if (urisWhichNeedMigration.isEmpty()) {
return;
}
/* perform the actual migration */
try {
migrator.migrate(urisWhichNeedMigration, new ESSystemOutProgressMonitor());
} catch (final EMFStoreMigrationException ex) {
ModelUtil.logException(ex);
}
/*
* fix file based changepackages (every operation was migrated on its own in a temp file. these need to be
* reassembled)
*/
fixFileBasedCPs(fileBasedCPToTempFiles);
}
private static void fixFileBasedCPs(final Map<URI, List<URI>> fileBasedCPToTempFiles) {
for (final URI fileBasedCPURI : fileBasedCPToTempFiles.keySet()) {
/* create a new file based changepackage and add all migrated operations to it */
final FileBasedChangePackage changePackage = VersioningFactory.eINSTANCE.createFileBasedChangePackage();
changePackage.initialize(fileBasedCPURI.toFileString());
for (final URI tempOperationFileURI : fileBasedCPToTempFiles.get(fileBasedCPURI)) {
try {
final AbstractOperation operation = ModelUtil.loadEObjectFromResource(
OperationsPackage.eINSTANCE.getAbstractOperation(),
tempOperationFileURI, false);
changePackage.add(operation);
} catch (final IOException ex) {
ModelUtil.logException(ex);
}
}
/* copy temp file to regular file */
try {
FileUtils.copyFile(new File(changePackage.getTempFilePath()),
new File(changePackage.getFilePath()));
} catch (final IOException ex) {
ModelUtil.logException(ex);
}
}
}
private static void fillURIsToMigrate(
URIConverter uriConverter,
final ServerSpace serverSpace,
Set<URI> urisToMigrate,
Map<URI, List<URI>> fileBasedCPToTempFiles,
boolean inMemoryChangePackage) {
/* loop over all versions and check if changepackage/projectstate resources are available */
for (final ProjectHistory project : serverSpace.getProjects()) {
for (final Version version : project.getVersions()) {
final URI versionURI = EcoreUtil.getURI(version);
final URI projectStateURI = ESServerURIUtil.createProjectStateURI(versionURI);
if (uriConverter.exists(projectStateURI, null)) {
urisToMigrate.add(uriConverter.normalize(projectStateURI));
}
final URI changePackageURI = ESServerURIUtil.createChangePackageURI(versionURI);
if (!inMemoryChangePackage) {
fillURIsToMigrateForFileBasedCP(uriConverter, changePackageURI, urisToMigrate,
fileBasedCPToTempFiles);
} else {
if (uriConverter.exists(changePackageURI, null)) {
urisToMigrate.add(uriConverter.normalize(changePackageURI));
}
}
}
}
}
private static void fillURIsToMigrateForFileBasedCP(
URIConverter uriConverter,
URI changePackageURI,
Set<URI> urisToMigrate,
Map<URI, List<URI>> fileBasedCPToTempFiles) {
final URI normalizedFileBasedChangePackageURI = uriConverter.normalize(changePackageURI);
final URI operationsFile = URI.createURI(
normalizedFileBasedChangePackageURI.toString() + FileBasedChangePackageImpl.FILE_OP_INDEX);
try {
final File operationsJavaFile = new File(operationsFile.toFileString());
if (!operationsJavaFile.exists()) {
/* no file -> nothing to add */
return;
}
fileBasedCPToTempFiles.put(operationsFile, new ArrayList<URI>());
final SerializedOperationEmitter operationEmitter = new SerializedOperationEmitter(
Direction.Forward, operationsJavaFile);
Optional<String> operation = operationEmitter.tryEmit();
while (operation.isPresent()) {
final File tempFile = File.createTempFile("esMigration", ".xmi"); //$NON-NLS-1$//$NON-NLS-2$
tempFile.deleteOnExit();
FileUtils.writeStringToFile(tempFile,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + operation.get(), //$NON-NLS-1$
"UTF-8"); //$NON-NLS-1$
final URI tempFileURI = URI.createFileURI(tempFile.getAbsolutePath());
urisToMigrate.add(tempFileURI);
fileBasedCPToTempFiles.get(operationsFile).add(tempFileURI);
operation = operationEmitter.tryEmit();
}
operationEmitter.close();
} catch (final IOException ex) {
ModelUtil.logException(ex);
}
}
}