/** * Copyright (c) 2007 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: * bblajer - initial API and implementation */ package org.eclipse.gmf.internal.codegen.lite.utils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.WeakHashMap; import org.eclipse.emf.codegen.ecore.genmodel.GenClass; import org.eclipse.emf.codegen.ecore.genmodel.GenFeature; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.gmf.codegen.gmfgen.FeatureLinkModelFacet; import org.eclipse.gmf.codegen.gmfgen.GenChildContainer; import org.eclipse.gmf.codegen.gmfgen.GenChildNode; import org.eclipse.gmf.codegen.gmfgen.GenCommonBase; import org.eclipse.gmf.codegen.gmfgen.GenCompartment; import org.eclipse.gmf.codegen.gmfgen.GenContainerBase; import org.eclipse.gmf.codegen.gmfgen.GenDiagram; import org.eclipse.gmf.codegen.gmfgen.GenLink; import org.eclipse.gmf.codegen.gmfgen.GenNode; import org.eclipse.gmf.codegen.gmfgen.GenTopLevelNode; import org.eclipse.gmf.codegen.gmfgen.TypeLinkModelFacet; import org.eclipse.gmf.codegen.gmfgen.TypeModelFacet; import org.eclipse.gmf.codegen.gmfgen.util.GMFGenSwitch; import org.eclipse.m2m.qvt.oml.blackbox.java.Operation; import org.eclipse.m2m.qvt.oml.blackbox.java.Operation.Kind; import org.eclipse.ocl.util.CollectionUtil; /** * This class provides static utility methods for use with Xpand templates. * Although it is possible to implement these methods in Xtend, doing so would severely impact performance, * since they would have to be called several times without the possibility to cache their results. */ public class SemanticSyncUtils { @Operation(contextual = false, kind = Kind.HELPER) public static Collection<GenNode> getGenNodes(GenContainerBase genContainerBase, GenFeature genFeature) { Collection<GenNode> result = getGenChildFeature2genNodeMap(genContainerBase).get(genFeature); if (result == null) { return CollectionUtil.<GenNode> createNewBag(Collections.<GenNode> emptyList()); } return CollectionUtil.<GenNode> createNewBag(result); } private static Map<GenFeature, Collection<GenNode>> getGenChildFeature2genNodeMap(GenContainerBase genContainerBase) { Map<GenFeature, Collection<GenNode>> result = myFeature2NodesCache.get(genContainerBase); if (result == null) { result = buildGenChildFeature2genNodeMap(genContainerBase); myFeature2NodesCache.put(genContainerBase, result); } return result; } private static Map<GenFeature, Collection<GenNode>> buildGenChildFeature2genNodeMap(GenContainerBase genContainerBase) { Map<GenFeature, Collection<GenNode>> result = new LinkedHashMap<GenFeature, Collection<GenNode>>(); Collection<? extends GenNode> childNodes = new GMFGenSwitch<Collection<? extends GenNode>>() { @Override public Collection<? extends GenNode> caseGenDiagram(GenDiagram object) { return object.getTopLevelNodes(); } @Override public Collection<? extends GenNode> caseGenChildContainer(GenChildContainer object) { return object.getChildNodes(); } }.doSwitch(genContainerBase); for (GenNode nextNode : childNodes) { TypeModelFacet typeModelFacet = nextNode.getModelFacet(); if (typeModelFacet == null) { continue; } GenFeature childMetaFeature = typeModelFacet.getChildMetaFeature(); if (!result.containsKey(childMetaFeature)) { result.put(childMetaFeature, new ArrayList<GenNode>()); } result.get(childMetaFeature).add(nextNode); } return result; } @Operation(contextual = false, kind = Kind.HELPER) public static Collection<GenLink> getTypeGenLinksForFeature(GenCommonBase container, GenFeature feature, Collection<GenLink> containedLinks) { Collection<GenLink> result = getGenChildFeature2TypeGenLinkMap(container, containedLinks).get(feature); if (result == null) { return CollectionUtil.<GenLink> createNewBag(Collections.<GenLink> emptyList()); } return CollectionUtil.<GenLink> createNewBag(result); } @Operation(contextual = false, kind = Kind.HELPER) public static Collection<GenLink> getFeatureGenLinksForFeature(GenCommonBase container, GenFeature feature, Collection<GenLink> containedLinks) { Collection<GenLink> result = getGenChildFeature2FeatureGenLinkMap(container, containedLinks).get(feature); if (result == null) { return CollectionUtil.<GenLink> createNewBag(Collections.<GenLink> emptyList()); } return CollectionUtil.<GenLink> createNewBag(result); } private static Map<GenFeature, Collection<GenLink>> getGenChildFeature2TypeGenLinkMap(GenCommonBase container, Collection<GenLink> containedLinks) { if (!myFeature2TypeLinksCache.containsKey(container)) { buildGenChildFeature2LinkMaps(container, containedLinks); } return myFeature2TypeLinksCache.get(container); } private static Map<GenFeature, Collection<GenLink>> getGenChildFeature2FeatureGenLinkMap(GenCommonBase container, Collection<GenLink> containedLinks) { if (!myFeature2FeatureLinksCache.containsKey(container)) { buildGenChildFeature2LinkMaps(container, containedLinks); } return myFeature2FeatureLinksCache.get(container); } private static void buildGenChildFeature2LinkMaps(GenCommonBase container, Collection<GenLink> containedLinks) { final Map<GenFeature, Collection<GenLink>> genFeature2TypeGenLinkMap = new LinkedHashMap<GenFeature, Collection<GenLink>>(); final Map<GenFeature, Collection<GenLink>> genFeature2FeatureGenLinkMap = new LinkedHashMap<GenFeature, Collection<GenLink>>(); for(final GenLink genLink : containedLinks) { new GMFGenSwitch<Object>() { @Override public Object caseTypeLinkModelFacet(TypeLinkModelFacet modelFacet) { GenFeature metaFeature = modelFacet.getChildMetaFeature(); if (!genFeature2TypeGenLinkMap.containsKey(metaFeature)) { genFeature2TypeGenLinkMap.put(metaFeature, new ArrayList<GenLink>()); } genFeature2TypeGenLinkMap.get(metaFeature).add(genLink); return null; } @Override public Object caseFeatureLinkModelFacet(FeatureLinkModelFacet modelFacet) { GenFeature metaFeature = modelFacet.getMetaFeature(); if (!genFeature2FeatureGenLinkMap.containsKey(metaFeature)) { genFeature2FeatureGenLinkMap.put(metaFeature, new ArrayList<GenLink>()); } genFeature2FeatureGenLinkMap.get(metaFeature).add(genLink); return null; } }.doSwitch(genLink.getModelFacet()); } myFeature2TypeLinksCache.put(container, genFeature2TypeGenLinkMap); myFeature2FeatureLinksCache.put(container, genFeature2FeatureGenLinkMap); } @Operation(contextual = false, kind = Kind.HELPER) public static Collection<GenCommonBase> buildAncestorClosure(Collection<GenCommonBase> elements) { Collection<GenCommonBase> result = new LinkedHashSet<GenCommonBase>(elements); for(GenCommonBase next : elements) { addAncestors(result, next); } return CollectionUtil.<GenCommonBase> createNewBag(result); } private static void addAncestors(Collection<GenCommonBase> result, GenCommonBase next) { Collection<? extends GenCommonBase> ancestors = new GMFGenSwitch<Collection<? extends GenCommonBase>>() { @Override public Collection<? extends GenCommonBase> caseGenTopLevelNode(GenTopLevelNode object) { return Collections.singleton(object.getDiagram()); } @Override public Collection<? extends GenCommonBase> caseGenCompartment(GenCompartment object) { return Collections.singleton(object.getNode()); } @Override public Collection<? extends GenCommonBase> caseGenChildNode(GenChildNode object) { return object.getContainers(); } @Override public Collection<? extends GenCommonBase> caseGenLink(GenLink object) { return getPossibleContainers(object); } @Override public Collection<? extends GenCommonBase> defaultCase(EObject object) { return Collections.emptyList(); } }.doSwitch(next); for(GenCommonBase nextAncestor : ancestors) { if (!result.contains(nextAncestor)) { result.add(nextAncestor); addAncestors(result, nextAncestor); } } } private static Collection<? extends GenCommonBase> getPossibleContainers(GenLink link) { //XXX: NB: Implementation here must be synchronized with xpt::diagram::LinkFinder::getPossibleContainers(gmfgen::GenLink link) EClass containerClass = null; if (link.getModelFacet() instanceof TypeLinkModelFacet) { TypeLinkModelFacet facet = ((TypeLinkModelFacet) link.getModelFacet()); if (facet.getContainmentMetaFeature() != null && facet.getContainmentMetaFeature().getGenClass() != null) { containerClass = ((TypeLinkModelFacet) link.getModelFacet()).getContainmentMetaFeature().getGenClass().getEcoreClass(); } } else if (link.getModelFacet() instanceof FeatureLinkModelFacet) { FeatureLinkModelFacet facet = (FeatureLinkModelFacet) link.getModelFacet(); if (facet.getMetaFeature() != null && facet.getMetaFeature().getGenClass() != null) { containerClass = facet.getMetaFeature().getGenClass().getEcoreClass(); } } if (containerClass == null) { return Collections.emptyList(); } Collection<GenCommonBase> result = new ArrayList<GenCommonBase>(); result.add(link.getDiagram()); result.addAll(link.getDiagram().getAllNodes()); result.addAll(link.getDiagram().getLinks()); for (Iterator<GenCommonBase> it = result.iterator(); it.hasNext(); ) { GenCommonBase next = it.next(); GenClass effectiveMetaClass = getEffectiveMetaClass(next); if (effectiveMetaClass == null || !containerClass.isSuperTypeOf(effectiveMetaClass.getEcoreClass())) { it.remove(); } } return result; } private static GenClass getEffectiveMetaClass(GenCommonBase element) { //XXX: NB: Implementation here must be synchronized with xpt::diagram::LinkFinder::getEffectiveMetaClass(...) methods return new GMFGenSwitch<GenClass>() { @Override public GenClass caseGenDiagram(GenDiagram object) { return object.getDomainDiagramElement(); } @Override public GenClass caseGenNode(GenNode object) { return object.getDomainMetaClass(); } @Override public GenClass caseGenLink(GenLink object) { return doSwitch(object.getModelFacet()); } @Override public GenClass caseTypeLinkModelFacet(TypeLinkModelFacet object) { return object.getMetaClass(); } }.doSwitch(element); } private static WeakHashMap<GenContainerBase, Map<GenFeature, Collection<GenNode>>> myFeature2NodesCache = new WeakHashMap<GenContainerBase, Map<GenFeature,Collection<GenNode>>>(); private static WeakHashMap<GenCommonBase, Map<GenFeature, Collection<GenLink>>> myFeature2TypeLinksCache = new WeakHashMap<GenCommonBase, Map<GenFeature,Collection<GenLink>>>(); private static WeakHashMap<GenCommonBase, Map<GenFeature, Collection<GenLink>>> myFeature2FeatureLinksCache = new WeakHashMap<GenCommonBase, Map<GenFeature,Collection<GenLink>>>(); }