/******************************************************************************* * 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: ******************************************************************************/ package org.eclipse.emf.emfstore.server.startup; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.emfstore.common.model.ModelFactory; import org.eclipse.emf.emfstore.common.model.ModelVersion; import org.eclipse.emf.emfstore.common.model.util.MalformedModelVersionException; import org.eclipse.emf.emfstore.common.model.util.ModelUtil; import org.eclipse.emf.emfstore.migration.EMFStoreMigrationException; import org.eclipse.emf.emfstore.migration.EMFStoreMigratorUtil; import org.eclipse.emf.emfstore.server.ServerConfiguration; import org.eclipse.emf.emfstore.server.exceptions.FatalEmfStoreException; /** * Applies migrator to files on server. * * @author koegel * @author wesendon */ public class MigrationManager { /** * Starts migration. * * @throws FatalEmfStoreException in case of failure */ public void migrateModel() throws FatalEmfStoreException { int modelVersionNumber; try { modelVersionNumber = ModelUtil.getModelVersionNumber(); } catch (MalformedModelVersionException e1) { throw new FatalEmfStoreException(e1); } // check for legacy server space File versionFile = new File(ServerConfiguration.getModelReleaseNumberFileName()); if (!versionFile.exists()) { stampCurrentVersionNumber(modelVersionNumber); } // check if we need to migrate ModelVersion modelVersion; URI versionFileUri = URI.createFileURI(ServerConfiguration.getModelReleaseNumberFileName()); ResourceSet resourceSet = new ResourceSetImpl(); try { Resource resource = resourceSet.getResource(versionFileUri, true); EList<EObject> directContents = resource.getContents(); modelVersion = (ModelVersion) directContents.get(0); // BEGIN SUPRESS CATCH EXCEPTION } catch (RuntimeException e) { // END SUPRESS CATCH EXCEPTION // resource can not be loaded, assume version number before metamodel split modelVersion = ModelFactory.eINSTANCE.createModelVersion(); modelVersion.setReleaseNumber(4); } if (modelVersion.getReleaseNumber() == modelVersionNumber) { return; } if (!EMFStoreMigratorUtil.isMigratorAvailable()) { throw new FatalEmfStoreException("Model must be migrated to new version, but no migrators are available."); } // ask for confirmation boolean doProcceed = askForConfirmationForMigration(); if (!doProcceed) { String message = "Server shutting down, model update is mandatory."; System.out.println(message); throw new FatalEmfStoreException(message); } // migrate all versions of all projects // we need to migrate File serverSpaceDirectory = new File(ServerConfiguration.getServerHome()); // for all projects for (File projectDirectory : serverSpaceDirectory.listFiles()) { if (projectDirectory.getName().startsWith(ServerConfiguration.FILE_PREFIX_PROJECTFOLDER) && projectDirectory.isDirectory()) { System.out.println("Migrating project at " + projectDirectory + "..."); convertInitialProjectState(modelVersion, projectDirectory); File[] listFiles = projectDirectory.listFiles(new FileFilter() { public boolean accept(File pathname) { if (pathname.isFile() && (pathname.getName().endsWith(".ucp") || pathname.getName().endsWith(".ups"))) { return true; } return false; } }); convertAllVersions(modelVersion, projectDirectory, listFiles); // convertAllBackupStates(modelVersion, projectDirectory, listFiles); } } stampCurrentVersionNumber(modelVersionNumber); } private void convertInitialProjectState(ModelVersion modelVersion, File projectDirectory) throws FatalEmfStoreException { URI version0StateURI = URI.createFileURI(projectDirectory.getAbsolutePath() + File.separatorChar + ServerConfiguration.FILE_PREFIX_PROJECTSTATE + "0" + ServerConfiguration.FILE_EXTENSION_PROJECTSTATE); try { System.out.println("Migrating version 0..."); migrate(version0StateURI, new ArrayList<URI>(), modelVersion.getReleaseNumber()); } catch (EMFStoreMigrationException e) { throw new FatalEmfStoreException("Migration of project at " + projectDirectory + " failed!", e); } } @SuppressWarnings("unused") @Deprecated private void convertAllBackupStates(ModelVersion modelVersion, File projectDirectory, File[] listFiles) throws FatalEmfStoreException { System.out.println("Migrating backup states..."); for (File backUpState : listFiles) { if (backUpState.getName().startsWith(ServerConfiguration.FILE_PREFIX_BACKUPPROJECTSTATE)) { URI projectURI = URI.createFileURI(backUpState.getAbsolutePath()); try { migrate(projectURI, new ArrayList<URI>(), modelVersion.getReleaseNumber()); } catch (EMFStoreMigrationException e) { throw new FatalEmfStoreException("Migration of project at " + projectDirectory + " failed!", e); } } } } private void convertAllVersions(ModelVersion modelVersion, File projectDirectory, File[] listFiles) throws FatalEmfStoreException { List<URI> changePackageURIs = new ArrayList<URI>(); Arrays.sort(listFiles, new Comparator<File>() { public int compare(File o1, File o2) { return compare(o1.getName(), o2.getName()); } private int compare(String name1, String name2) { return getNumber(name1).compareTo(getNumber(name2)); } private Integer getNumber(String filename) { String name = filename.substring(0, filename.lastIndexOf(".")); int i = name.length() - 1; while (i >= 0 && '0' <= name.charAt(i) && name.charAt(i) <= '9') { i--; } i++; String number = name.substring(i); return number.equals("") ? 0 : Integer.parseInt(number); } }); for (File changePackageFile : listFiles) { String changePackageName = changePackageFile.getName(); if (changePackageName.startsWith(ServerConfiguration.FILE_PREFIX_CHANGEPACKAGE)) { int versionSpec = parseVersionSpecFromFileName(changePackageName); URI changePackageURI = URI.createFileURI(changePackageFile.getAbsolutePath()); changePackageURIs.add(changePackageURI); String projectStateFilename = projectDirectory.getAbsolutePath() + File.separatorChar + ServerConfiguration.FILE_PREFIX_PROJECTSTATE + versionSpec + ServerConfiguration.FILE_EXTENSION_PROJECTSTATE; File projectStateFile = new File(projectStateFilename); if (projectStateFile.exists()) { URI projectURI = URI.createFileURI(projectStateFilename); try { System.out.println("Migrating version " + versionSpec + " with its " + (changePackageURIs.size() - 1) + " previous versions..."); migrate(projectURI, changePackageURIs, modelVersion.getReleaseNumber()); } catch (EMFStoreMigrationException e) { throw new FatalEmfStoreException("Migration of project at " + projectDirectory + " failed!", e); } changePackageURIs.clear(); } } } } private int parseVersionSpecFromFileName(String versionName) { int startOfFileExtension = versionName.lastIndexOf("."); int prefixLength = ServerConfiguration.FILE_PREFIX_CHANGEPACKAGE.length(); String versionSpecString = versionName.substring(prefixLength, startOfFileExtension); int versionSpec = Integer.parseInt(versionSpecString); return versionSpec; } /** * Migrate the model instance if neccessary. * * @param projectURI the uri of the project state * @param changesURI the uri of the local changes of the project state * @param sourceModelReleaseNumber * @throws ModelMigrationException */ private void migrate(URI projectURI, List<URI> changesURIs, int sourceModelReleaseNumber) throws EMFStoreMigrationException { List<URI> modelURIs = new ArrayList<URI>(); modelURIs.add(projectURI); for (URI changeURI : changesURIs) { modelURIs.add(changeURI); } EMFStoreMigratorUtil.getEMFStoreMigrator().migrate(modelURIs, sourceModelReleaseNumber, new ConsoleProgressMonitor()); } private void stampCurrentVersionNumber(int modelReleaseNumber) { URI versionFileUri = URI.createFileURI(ServerConfiguration.getModelReleaseNumberFileName()); Resource versionResource = new ResourceSetImpl().createResource(versionFileUri); ModelVersion modelVersion = ModelFactory.eINSTANCE.createModelVersion(); modelVersion.setReleaseNumber(modelReleaseNumber); versionResource.getContents().add(modelVersion); try { versionResource.save(null); } catch (IOException e) { // MK Auto-generated catch block e.printStackTrace(); } } /** * Ask for Confirmation for model migration. * * @return true if user wants to proceed * @throws FatalEmfStoreException */ private boolean askForConfirmationForMigration() throws FatalEmfStoreException { System.out .println("Your model is not up to date. Do you want to update now and did you backup your emfstore folder? (y/n)"); byte[] buffer = new byte[1]; String input = ""; int read = 0; try { read = System.in.read(buffer, 0, 1); } catch (IOException e) { throw new FatalEmfStoreException("Cannot read from input", e); } input = new String(buffer, 0, read); return input.equalsIgnoreCase("y"); } }