diff options
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.java | 391 |
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; + } +} |