blob: a344ec89c58b092331c26ae9d116d17c503915b9 [file] [log] [blame]
/*
* Copyright (c) 2008 Borland Software Corporation
*
* 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:
* Artem Tikhomirov (Borland) - initial API and implementation
*/
package org.eclipse.gmf.internal.graphdef.util;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.BasicResourceHandler;
import org.eclipse.gmf.gmfgraph.ChildAccess;
import org.eclipse.gmf.gmfgraph.Compartment;
import org.eclipse.gmf.gmfgraph.CustomFigure;
import org.eclipse.gmf.gmfgraph.DiagramElement;
import org.eclipse.gmf.gmfgraph.DiagramLabel;
import org.eclipse.gmf.gmfgraph.Figure;
import org.eclipse.gmf.gmfgraph.FigureAccessor;
import org.eclipse.gmf.gmfgraph.FigureDescriptor;
import org.eclipse.gmf.gmfgraph.FigureGallery;
import org.eclipse.gmf.gmfgraph.GMFGraphFactory;
import org.eclipse.gmf.gmfgraph.GMFGraphPackage;
import org.eclipse.gmf.gmfgraph.RealFigure;
import org.eclipse.gmf.internal.common.ToolingResourceFactory;
import org.eclipse.gmf.internal.common.migrate.FilteringCopier;
import org.eclipse.gmf.internal.common.migrate.Messages;
import org.eclipse.gmf.internal.common.migrate.MigrationResource;
/**
* This is a complete rework of old XML-based MigrationDelegate,
* to handle migration of gmfgraph resources of year 2005 to the
* version of year 2007, using dynamic meta-model for old one.
* @author artem
*/
public class MigrateFactory2005 extends ToolingResourceFactory {
private static final Object MIGRATION_IN_PROGRESS = "gmf.migration";
private static final Object MIGRATION_PARTICIPANTS = "gmf.migration.resources";
private static final String OLD_NS_URI = "http://www.eclipse.org/gmf/2005/GraphicalDefinition";
@Override
public Resource createResource(URI uri) {
ToolResource r = (ToolResource) super.createResource(uri);
r.getDefaultLoadOptions().put(XMLResource.OPTION_RESOURCE_HANDLER, new BasicResourceHandler() {
@Override
public void postLoad(XMLResource resource, InputStream inputStream, Map<?, ?> options) {
// when modifying, can't use passed options as they represent merged value of rs options and default resource options
if (Boolean.TRUE.equals(options.get(MIGRATION_IN_PROGRESS))) {
@SuppressWarnings("unchecked")
List<XMLResource> participants = (List<XMLResource>) resource.getResourceSet().getLoadOptions().get(MIGRATION_PARTICIPANTS);
participants.add(resource);
return;
}
try {
resource.getResourceSet().getLoadOptions().put(MIGRATION_IN_PROGRESS, Boolean.TRUE);
final LinkedList<XMLResource> participants = new LinkedList<XMLResource>();
participants.add(resource);
resource.getResourceSet().getLoadOptions().put(MIGRATION_PARTICIPANTS, participants);
for (EObject o : resource.getContents()) {
if (isOfInterest(o)) {
// trigger load of all resorces while migration-in-progress flag is set
// and no actual migration happens
EcoreUtil.resolveAll(o);
}
}
// collect all objects for migration
Map<EObject, EObject> wholeMigration = new HashMap<EObject, EObject>();
for (XMLResource r : participants) {
for (EObject o : r.getContents()) {
if (isOfInterest(o)) {
wholeMigration.put(o, null);
}
}
}
migrate2005to2006(wholeMigration);
// update migrated elements in their respective resources
for (XMLResource r : participants) {
LinkedList<EObject> migrated = new LinkedList<EObject>();
for (EObject o : r.getContents()) {
EObject m = wholeMigration.get(o);
if (m != null) {
migrated.add(m);
r.getWarnings().add(0, MigrationResource.createMessageDiagnostic(r, Messages.oldModelVersionLoadedMigrationRequired));
} else {
migrated.add(o);
}
}
r.getContents().clear();
r.getContents().addAll(migrated);
}
} finally {
resource.getResourceSet().getLoadOptions().remove(MIGRATION_IN_PROGRESS);
resource.getResourceSet().getLoadOptions().remove(MIGRATION_PARTICIPANTS);
}
}
private boolean isOfInterest(EObject o) {
return o != null && OLD_NS_URI.equals(o.eClass().getEPackage().getNsURI());
}
});
return r;
}
private void migrate2005to2006(Map<EObject, EObject> original2migrated) {
final EPackage oldModel = EPackage.Registry.INSTANCE.getEPackage(OLD_NS_URI);
final EClass oldFigureClass = (EClass) oldModel.getEClassifier("Figure");
final EClass oldFigureAccessorClass = (EClass) oldModel.getEClassifier("FigureAccessor");
final EStructuralFeature deFigure = ((EClass) oldModel.getEClassifier("DiagramElement")).getEStructuralFeature("figure");
final EStructuralFeature fhReferencingElements = ((EClass) oldModel.getEClassifier("FigureHandle")).getEStructuralFeature("referencingElements");
final EStructuralFeature identityName = ((EClass) oldModel.getEClassifier("Identity")).getEStructuralFeature("name");
final EStructuralFeature figureChildren = oldFigureClass.getEStructuralFeature("children");
final EStructuralFeature faTypedFigure = oldFigureAccessorClass.getEStructuralFeature("typedFigure");
FilteringCopier cc = new FilteringCopier(false, false, GMFGraphPackage.eINSTANCE);
cc.ignore(((EClass) oldModel.getEClassifier("CustomClass")).getEStructuralFeature("bundleName"));
cc.ignore(deFigure);
cc.ignore(fhReferencingElements);
cc.ignoreIn(identityName, oldFigureClass);
cc.ignore(faTypedFigure);
cc.substitute(figureChildren, GMFGraphPackage.eINSTANCE.getRealFigure_Children());
cc.copyAll(original2migrated.keySet());
cc.copyReferences();
for (EObject fa : cc.getIgnoredOwners(faTypedFigure)) {
EObject oldReferencedFigure = (EObject) fa.eGet(faTypedFigure);
if (oldReferencedFigure == null) {
// typedFigure reference was optional, became mandatory,
// need to create a bare figure to hold value
// @see MigrationDelegate#getOrCreateTypedFigure
CustomFigure custom = GMFGraphFactory.eINSTANCE.createCustomFigure();
custom.setQualifiedClassName("org.eclipse.draw2d.IFigure"); //$NON-NLS-1$
((FigureAccessor) cc.get(fa)).setTypedFigure(custom);
continue;
}
if (oldReferencedFigure.eIsProxy()) {
oldReferencedFigure = EcoreUtil.resolve(oldReferencedFigure, fa);
}
EObject newFigure = cc.get(oldReferencedFigure);
if (newFigure == null) {
continue;
}
assert !newFigure.eIsProxy(); // how come freshly copied newFigure may be a proxy?
EObject copy = EcoreUtil.copy(newFigure);
if (copy instanceof RealFigure) { // sanity, typedFigure can't be anything but CustomFigure
((FigureAccessor) cc.get(fa)).setTypedFigure((RealFigure) copy);
}
}
final EClass oldFigureGalleryClass = (EClass) oldModel.getEClassifier("FigureGallery");
final Map<EObject, FigureDescriptor> oldFigure2newDescriptor = new HashMap<EObject, FigureDescriptor>();
final Map<EObject, ChildAccess> oldFigureAccessor2newChildAccess = new HashMap<EObject, ChildAccess>();
for (EObject fh : cc.getIgnoredOwners(fhReferencingElements)) {
List<?> de = (List<?>) fh.eGet(fhReferencingElements);
if (de.isEmpty()) {
// in original migration code, similar effect (not-referenced
// figures are not migrated to FigureDescriptor) was achieved
// as there happen to be no 'referencedElement' tag in a gmfgraph
// file, and hence, migrateFigureStructureToDescriptor() wasn't invoked
continue;
}
if (!oldFigureClass.isInstance(fh) && !oldFigureAccessorClass.isInstance(fh)) {
// no more known subclasses of FigureHandle
assert false;
continue;
}
EObject topLevel = fh;
while (topLevel != null && !oldFigureGalleryClass.isInstance(topLevel.eContainer())) {
topLevel = topLevel.eContainer();
}
if (topLevel == null) {
assert false; // can't happen
continue;
}
initFigureDescriptor(cc, topLevel, fh, oldFigure2newDescriptor, oldFigureAccessor2newChildAccess);
}
for (EObject de : cc.getIgnoredOwners(deFigure)) {
final Object fh = de.eGet(deFigure);
if (false == fh instanceof EObject) {
continue;
}
EObject oldFigure = (EObject) fh;
if (oldFigure.eIsProxy()) {
oldFigure = EcoreUtil.resolve(oldFigure, de);
if (oldFigure.eIsProxy()) { // failed to resolve proxy
continue;
}
}
// oldFigure is either subclass of Figure or FigureAccessor
if (!oldFigureClass.isInstance(oldFigure) && !oldFigureAccessorClass.isInstance(oldFigure)) {
assert false;
continue;
}
EObject topLevel = oldFigure;
while (topLevel != null && !oldFigureGalleryClass.isInstance(topLevel.eContainer())) {
topLevel = topLevel.eContainer();
}
if (topLevel == null) {
assert false;
continue;
}
if (!oldFigure2newDescriptor.containsKey(topLevel)) {
// though all *correct* figures should already be migrated,
// there might be a figure without referencedElements set,
// hence, may need to migrate it anyway
initFigureDescriptor(cc, topLevel, oldFigure, oldFigure2newDescriptor, oldFigureAccessor2newChildAccess);
}
FigureDescriptor fd = oldFigure2newDescriptor.get(topLevel);
final DiagramElement newDE = (DiagramElement) cc.get(de);
newDE.setFigure(fd);
if (topLevel != oldFigure) {
// child access, MigrationDelegate#setNestedFigureAccessFor
ChildAccess access = oldFigureAccessor2newChildAccess.get(oldFigure);
if (access == null) {
// assert false; // XXX create new one?
continue;
}
if (newDE instanceof DiagramLabel) {
((DiagramLabel) newDE).setAccessor(access);
} else if (newDE instanceof Compartment) {
((Compartment) newDE).setAccessor(access);
}
}
}
for (EObject i : cc.getIgnoredOwners(identityName)) {
if (cc.get(i) instanceof RealFigure && i.eIsSet(identityName)) {
// in old model, name feature came from Identity class,
// while in the new model, name feature is RealFigure's attribute.
// Copier#getTarget(EStructuralFeature) logic is not suited to
// find new feature owners yet, using feature.getEContainingClass()
// for simplicity now, hence can't get appropriate new EStrFea.
((RealFigure) cc.get(i)).setName((String) i.eGet(identityName));
}
}
// map original elements to their respective copies
for (EObject o : new LinkedList<EObject>(original2migrated.keySet())) {
original2migrated.put(o, cc.get(o));
}
}
private void initFigureDescriptor(FilteringCopier cc, EObject topLevel, EObject fh, Map<EObject, FigureDescriptor> oldFigure2newDescriptor, Map<EObject, ChildAccess> oldFigureAccessor2newChildAccess) {
FigureDescriptor fd = oldFigure2newDescriptor.get(topLevel);
if (fd == null) {
fd = GMFGraphFactory.eINSTANCE.createFigureDescriptor();
fd.setActualFigure((RealFigure) cc.get(topLevel));
fd.setName((String) topLevel.eGet(topLevel.eClass().getEStructuralFeature("name")));
oldFigure2newDescriptor.put(topLevel, fd);
EObject figureGallery = topLevel.eContainer();
((FigureGallery) cc.get(figureGallery)).getDescriptors().add(fd);
}
if (topLevel != fh && !oldFigureAccessor2newChildAccess.containsKey(fh)) {
ChildAccess a = GMFGraphFactory.eINSTANCE.createChildAccess();
final EClass oldFigureAccessorClass = (EClass) topLevel.eClass().getEPackage().getEClassifier("FigureAccessor");
if (oldFigureAccessorClass.isInstance(fh)) {
FigureAccessor fa = (FigureAccessor) cc.get(fh);
if (fa != null) {
a.setFigure(fa.getTypedFigure());
}
} else {
a.setFigure((Figure) cc.get(fh));
}
oldFigureAccessor2newChildAccess.put(fh, a);
fd.getAccessors().add(a);
}
}
}