Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.emf.edapt.history.cdo/src/org/eclipse/emf/edapt/cdo/migration/execution/CDOMigrator.java')
-rw-r--r--plugins/org.eclipse.emf.edapt.history.cdo/src/org/eclipse/emf/edapt/cdo/migration/execution/CDOMigrator.java391
1 files changed, 391 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.edapt.history.cdo/src/org/eclipse/emf/edapt/cdo/migration/execution/CDOMigrator.java b/plugins/org.eclipse.emf.edapt.history.cdo/src/org/eclipse/emf/edapt/cdo/migration/execution/CDOMigrator.java
new file mode 100644
index 0000000..b02849d
--- /dev/null
+++ b/plugins/org.eclipse.emf.edapt.history.cdo/src/org/eclipse/emf/edapt/cdo/migration/execution/CDOMigrator.java
@@ -0,0 +1,391 @@
+package org.eclipse.emf.edapt.cdo.migration.execution;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edapt.common.IResourceSetFactory;
+import org.eclipse.emf.edapt.common.MetamodelExtent;
+import org.eclipse.emf.edapt.common.MetamodelUtils;
+import org.eclipse.emf.edapt.common.ResourceSetFactoryImpl;
+import org.eclipse.emf.edapt.common.ResourceUtils;
+import org.eclipse.emf.edapt.declaration.LibraryImplementation;
+import org.eclipse.emf.edapt.declaration.OperationImplementation;
+import org.eclipse.emf.edapt.declaration.OperationRegistry;
+import org.eclipse.emf.edapt.history.Delete;
+import org.eclipse.emf.edapt.history.History;
+import org.eclipse.emf.edapt.history.HistoryPackage;
+import org.eclipse.emf.edapt.history.Release;
+import org.eclipse.emf.edapt.history.reconstruction.EcoreForwardReconstructor;
+import org.eclipse.emf.edapt.history.util.HistoryUtils;
+import org.eclipse.emf.edapt.migration.BackupUtils;
+import org.eclipse.emf.edapt.migration.CustomMigration;
+import org.eclipse.emf.edapt.migration.MaterializingBackwardConverter;
+import org.eclipse.emf.edapt.migration.Metamodel;
+import org.eclipse.emf.edapt.migration.MigrationException;
+import org.eclipse.emf.edapt.migration.Model;
+import org.eclipse.emf.edapt.migration.PrintStreamProgressMonitor;
+import org.eclipse.emf.edapt.migration.ReleaseUtils;
+import org.eclipse.emf.edapt.migration.execution.ClassLoaderFacade;
+import org.eclipse.emf.edapt.migration.execution.IClassLoader;
+import org.eclipse.emf.edapt.migration.execution.MigratorCommandLine;
+import org.eclipse.emf.edapt.migration.execution.ValidationLevel;
+import org.eclipse.emf.edapt.migration.execution.WrappedMigrationException;
+
+/**
+ * Migrator to migrate a model from a previous to the current release.
+ *
+ * @author Christophe Bouhier
+ */
+public class CDOMigrator {
+
+ /** Metamodel history no which this migrator is based. */
+ private History history;
+
+ /** Mapping of namespace URIs to releases. */
+ private HashMap<String, Set<Release>> releaseMap;
+
+ /** Classloader to load {@link CustomMigration}s. */
+ private final IClassLoader classLoader;
+
+ /** Factory to create {@link ResourceSet}s for custom serialization. */
+ private IResourceSetFactory resourceSetFactory = new ResourceSetFactoryImpl();
+
+ /** Validation level. */
+ private ValidationLevel level = ValidationLevel.CUSTOM_MIGRATION;
+
+ private MetamodelExtent extent;
+
+ /** Constructor. */
+ public CDOMigrator(URI historyURI, IClassLoader classLoader)
+ throws MigrationException {
+ HistoryPackage.eINSTANCE.getHistory();
+ try {
+ history = ResourceUtils.loadElement(historyURI);
+ } catch (IOException e) {
+ throw new MigrationException("History could not be loaded", e);
+ }
+ this.classLoader = classLoader;
+ init();
+ }
+
+ /** Constructor. */
+ public CDOMigrator(History history, IClassLoader classLoader) {
+ this.history = history;
+ this.classLoader = classLoader;
+ init();
+ }
+
+ /** Initialize release map for the migrator. */
+ private void init() {
+ releaseMap = new HashMap<String, Set<Release>>();
+ Map<EPackage, String> packageMap = new HashMap<EPackage, String>();
+
+ for (Release release : history.getReleases()) {
+ if (!release.isLastRelease()) {
+ updatePackages(release, packageMap);
+ registerRelease(release, packageMap);
+ }
+ }
+ }
+
+ /** Register a package for a certain release. */
+ private void registerRelease(Release release,
+ Map<EPackage, String> packageMap) {
+ for (Entry<EPackage, String> entry : packageMap.entrySet()) {
+ String nsURI = entry.getValue();
+ Set<Release> releases = releaseMap.get(nsURI);
+ if (releases == null) {
+ releases = new HashSet<Release>();
+ releaseMap.put(nsURI, releases);
+ }
+ releases.add(release);
+ }
+ }
+
+ /** Update the namespace URIs based on the changes during a release. */
+ private void updatePackages(Release release,
+ Map<EPackage, String> packageMap) {
+ for (Iterator<EObject> i = release.eAllContents(); i.hasNext();) {
+ EObject element = i.next();
+ if (element instanceof org.eclipse.emf.edapt.history.Set) {
+ org.eclipse.emf.edapt.history.Set set = (org.eclipse.emf.edapt.history.Set) element;
+ if (set.getFeature() == EcorePackage.eINSTANCE
+ .getEPackage_NsURI()) {
+ EPackage ePackage = (EPackage) set.getElement();
+ String nsURI = (String) set.getValue();
+ packageMap.put(ePackage, nsURI);
+ }
+ } else if (element instanceof Delete) {
+ Delete delete = (Delete) element;
+ packageMap.remove(delete.getElement());
+ }
+ }
+ }
+
+ /**
+ * Migrate a model based on a set of {@link URI} and save to it's own URI
+ * location.
+ *
+ * @param modelURIs
+ * @param sourceRelease
+ * @param targetRelease
+ * @param monitor
+ * @throws MigrationException
+ */
+ public void migrateAndSave(List<URI> modelURIs, Release sourceRelease,
+ Release targetRelease, IProgressMonitor monitor)
+ throws MigrationException {
+ migrateAndSave(modelURIs, sourceRelease, targetRelease, monitor, null);
+ }
+
+ /**
+ * Migrate a model based on a set of {@link URI} and save it to a
+ * destination {@link URI}. The destination {@link URI} is the path URI in
+ * case multiple modelURIs are provided.
+ *
+ * @param modelURIs
+ * @param sourceRelease
+ * Release to which the model conforms
+ * @param targetRelease
+ * Release to which the model should be migrated (use null for
+ * the newest release)
+ * @param monitor
+ * Progress monitor
+ * @param destnationURI
+ */
+ public void migrateAndSave(List<URI> modelURIs, Release sourceRelease,
+ Release targetRelease, IProgressMonitor monitor, List<URI> list)
+ throws MigrationException {
+ Model model = migrate(modelURIs, sourceRelease, targetRelease, monitor);
+ if (model == null) {
+ throw new MigrationException("Model is up-to-date", null);
+ }
+ // Get the original extend, as we need a factory...
+ try {
+ CDOPersistency.saveModel(model, extent, list);
+ } catch (IOException e) {
+ throw new MigrationException("Model could not be saved", e);
+ }
+ }
+
+ /**
+ * Migrate a model based on a set of {@link URI}s and load it afterwards.
+ *
+ * @param modelURIs
+ * The set of {@link URI}
+ * @param sourceRelease
+ * Release to which the model conforms
+ * @param targetRelease
+ * Release to which the model should be migrated (use null for
+ * the newest release)
+ * @param monitor
+ * Progress monitor
+ * @return The model in a {@link ResourceSet}
+ */
+ public ResourceSet migrateAndLoad(List<URI> modelURIs,
+ Release sourceRelease, Release targetRelease,
+ IProgressMonitor monitor) throws MigrationException {
+ Model model = migrate(modelURIs, sourceRelease, targetRelease, monitor);
+ if (model == null) {
+ return null;
+ }
+ MaterializingBackwardConverter converter = new MaterializingBackwardConverter();
+ return converter.convert(model);
+ }
+
+ /** Get the latest release. */
+ private Release getLatestRelease() {
+ List<Release> releases = history.getReleases();
+ return releases.get(releases.size() - 2);
+ }
+
+ /**
+ * Migrate a model based on a set of {@link URI}s.
+ *
+ * @param modelURIs
+ * The set of {@link URI}
+ * @param sourceRelease
+ * Release to which the model conforms
+ * @param targetRelease
+ * Release to which the model should be migrated (use null for
+ * the newest release)
+ * @param monitor
+ * Progress monitor
+ * @return The model in the generic structure
+ */
+ private Model migrate(List<URI> modelURIs, Release sourceRelease,
+ Release targetRelease, IProgressMonitor monitor)
+ throws MigrationException {
+ try {
+ if (targetRelease == null) {
+ targetRelease = getLatestRelease();
+ }
+ if (sourceRelease == targetRelease) {
+ return null;
+ }
+
+ monitor.beginTask("Migrate",
+ numberOfSteps(sourceRelease, targetRelease));
+ EcoreForwardReconstructor reconstructor = new EcoreForwardReconstructor(
+ URI.createFileURI("test"));
+ CDOMigrationReconstructor migrationReconstructor = new CDOMigrationReconstructor(
+ modelURIs, sourceRelease, targetRelease, monitor,
+ classLoader, level, resourceSetFactory);
+ reconstructor.addReconstructor(migrationReconstructor);
+
+ reconstructor.reconstruct(targetRelease, false);
+
+ extent = reconstructor.getExtent();
+
+ Model model = migrationReconstructor.getModel();
+ return model;
+ } catch (WrappedMigrationException e) {
+ throw e.getCause();
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /** Returns the length of the migration in terms of the steps. */
+ private int numberOfSteps(Release sourceRelease, Release targetRelease) {
+ int size = 0;
+ boolean inRelease = false;
+ for (Release release : history.getReleases()) {
+ if (inRelease) {
+ size += release.getChanges().size();
+ }
+ if (release == sourceRelease) {
+ inRelease = true;
+ }
+ if (release == targetRelease) {
+ break;
+ }
+ }
+ return size;
+ }
+
+ /** Get the release of a model based on {@link URI}. */
+ public Set<Release> getRelease(URI modelURI) {
+ String nsURI = ReleaseUtils.getNamespaceURI(modelURI);
+ return releaseMap.containsKey(nsURI) ? releaseMap.get(nsURI)
+ : Collections.<Release> emptySet();
+ }
+
+ /** Get the release with a certain number. */
+ public Release getRelease(int number) {
+ if (number < 0 || number >= history.getReleases().size()) {
+ return null;
+ }
+ return history.getReleases().get(number);
+ }
+
+ /** Get all releases. */
+ public List<Release> getReleases() {
+ List<Release> releases = new ArrayList<Release>();
+ releases.addAll(history.getReleases());
+ releases.remove(history.getLastRelease());
+ return releases;
+ }
+
+ /** Get set of namespace URIs. */
+ public Set<String> getNsURIs() {
+ return releaseMap.keySet();
+ }
+
+ /** Returns the metamodel for a release. */
+ public Metamodel getMetamodel(Release release) {
+ EcoreForwardReconstructor reconstructor = new EcoreForwardReconstructor(
+ URI.createFileURI("test"));
+ reconstructor.reconstruct(release, false);
+ URI metamodelURI = URI.createFileURI(new File("metamodel."
+ + ResourceUtils.ECORE_FILE_EXTENSION).getAbsolutePath());
+ List<EPackage> rootPackages = ResourceUtils.getRootElements(
+ reconstructor.getResourceSet(), EPackage.class);
+ ResourceSet resourceSet = MetamodelUtils
+ .createIndependentMetamodelCopy(rootPackages, metamodelURI);
+ return CDOPersistency.loadMetamodel(resourceSet);
+ }
+
+ /** Set the validation level. */
+ public void setLevel(ValidationLevel level) {
+ this.level = level;
+ }
+
+ /** Main method to perform migrations. */
+ public static void main(String[] args) {
+
+ MigratorCommandLine commandLine = new MigratorCommandLine(args);
+ List<URI> modelURIs = commandLine.getModelURIs();
+ int sourceReleaseNumber = commandLine.getSourceReleaseNumber();
+ int targetReleaseNumber = commandLine.getTargetReleaseNumber();
+
+ try {
+ for (Class<? extends LibraryImplementation> library : commandLine
+ .getLibraries()) {
+ OperationRegistry.getInstance().registerLibrary(library);
+ }
+ for (Class<? extends OperationImplementation> operation : commandLine
+ .getOperations()) {
+ OperationRegistry.getInstance().registerOperation(operation);
+ }
+
+ CDOMigrator migrator = new CDOMigrator(commandLine.getHistoryURI(),
+ new ClassLoaderFacade(Thread.currentThread()
+ .getContextClassLoader()));
+ migrator.setLevel(commandLine.getLevel());
+
+ Set<Release> releases = migrator.getRelease(modelURIs.get(0));
+ Release sourceRelease = null;
+ if (sourceReleaseNumber != -1) {
+ sourceRelease = HistoryUtils.getRelease(releases,
+ sourceReleaseNumber);
+ } else {
+ sourceRelease = releases.iterator().next();
+ }
+
+ if (commandLine.isBackup()) {
+ Metamodel metamodel = migrator.getMetamodel(sourceRelease);
+ try {
+ BackupUtils.backup(modelURIs, metamodel);
+ } catch (IOException e) {
+ System.err.println(e.getMessage());
+ }
+ }
+
+ Release targetRelease = migrator.getRelease(targetReleaseNumber);
+
+ migrator.migrateAndSave(modelURIs, sourceRelease, targetRelease,
+ new PrintStreamProgressMonitor(System.out));
+ } catch (MigrationException e) {
+ System.err.println(e.getMessage());
+ System.err.println(e.getCause().getMessage());
+ }
+ }
+
+ /** Set the factory to create {@link ResourceSet}s for custom serialization. */
+ public void setResourceSetFactory(IResourceSetFactory resourceSetFactory) {
+ if (resourceSetFactory != null) {
+ this.resourceSetFactory = resourceSetFactory;
+ }
+ }
+
+ /** Get the factory to create {@link ResourceSet}s for custom serialization. */
+ public IResourceSetFactory getResourceSetFactory() {
+ return resourceSetFactory;
+ }
+}

Back to the top