blob: 2613ed6e4da6ff84231d1935919f66d8f2ea8002 [file] [log] [blame]
/**
* 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>>>();
}