/* * 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); } } }