/* * Copyright (c) 2006 Eclipse.org * * 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: * Dmitry Stadnik - initial API and implementation */ package org.eclipse.gmf.internal.bridge.resolver; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; /** * @author dstadnik */ public class StructureResolver { private Vocabulary nodeVocabulary; private Vocabulary linkVocabulary; private Vocabulary linkSourceVocabulary; private Vocabulary linkTargetVocabulary; public StructureResolver() { nodeVocabulary = new Vocabulary(); nodeVocabulary.add(new String[] { "node", "item" }); //$NON-NLS-1$ //$NON-NLS-2$ linkVocabulary = new Vocabulary(); linkVocabulary.add(new String[] { "link", "connection", "relation", "dependency", "flow" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ linkSourceVocabulary = new Vocabulary(); linkSourceVocabulary.add(new String[] { "source", "src", "from" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ linkTargetVocabulary = new Vocabulary(); linkTargetVocabulary.add(new String[] { "destination", "dst", "dest", "to" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } protected boolean guessNode(EClass type) { return nodeVocabulary.containsWords(type.getName()); } protected boolean guessLink(EClass type) { return linkVocabulary.containsWords(type.getName()); } protected EReference guessLinkSource(EReference[] refs) { for (int i = 0; i < refs.length; i++) { if (linkSourceVocabulary.containsWords(refs[i].getName())) { return refs[i]; } } return null; } protected EReference guessLinkTarget(EReference[] refs) { for (int i = 0; i < refs.length; i++) { if (linkTargetVocabulary.containsWords(refs[i].getName())) { return refs[i]; } } return null; } public TypePattern resolve(EClass type, EPackage scope) { if (type.isAbstract() || type.isInterface()) { return null; } EReference[] containments = getContainments(type, scope); if (containments.length == 0) { // skip diagram node and other unattached types return null; } EAttribute[] labels = getLabels(type); EReference[] refs = getEAllPotentialRefs(type, true); // heuristics : type without refs is a node // heuristics : type that has containment feature(s) is likely a node // heuristics : guess node by vocabulary if (refs.length == 0 || !type.getEAllContainments().isEmpty() || guessNode(type)) { refs = getEAllPotentialRefs(type, false); return new NodePattern(type, labels, refs); } EReference source; EReference target; if (refs.length == 1) { // heuristics : one ref is target; source is container source = null; target = refs[0]; } else { // heuristics : guess source and target refs by vocabulary source = guessLinkSource(refs); target = guessLinkTarget(refs); if (source == null) { source = target == refs[0] ? refs[1] : refs[0]; } if (target == null) { target = source == refs[1] ? refs[0] : refs[1]; } } return new TypeLinkPattern(type, labels, source, target); } protected EAttribute[] getLabels(EClass type) { List<EAttribute> attrs = new ArrayList<EAttribute>(); for (Iterator<EAttribute> it = type.getEAllAttributes().iterator(); it.hasNext();) { attrs.add(it.next()); } return attrs.toArray(new EAttribute[attrs.size()]); } /** * Finds all potential references. Such references are not containers, containments, * derived and have type from the same package as the host type; thus they may * connect types as links on diagram surface. */ protected EReference[] getEAllPotentialRefs(EClass type, boolean forLink) { List<EReference> refs = new ArrayList<EReference>(); for (Iterator<EReference> it = type.getEAllReferences().iterator(); it.hasNext();) { EReference ref = it.next(); EClass refType = ref.getEReferenceType(); if (forLink && (refType.isSuperTypeOf(type) || ref.isMany())) { continue; } boolean samePackage = refType.getEPackage().equals(type.getEPackage()); if (!ref.isDerived() && !ref.isContainer() && !ref.isContainment() && samePackage) { refs.add(ref); } } return refs.toArray(new EReference[refs.size()]); } /** * Returns list of references that contain this type. */ protected EReference[] getContainments(EClass type, EPackage scope) { List<EReference> refs = new ArrayList<EReference>(); for (Iterator<EObject> it = scope.eAllContents(); it.hasNext();) { EObject element = it.next(); if (element instanceof EReference) { EReference ref = (EReference) element; if (ref.isContainment() && ref.getEReferenceType().isSuperTypeOf(type)) { refs.add(ref); } } } return refs.toArray(new EReference[refs.size()]); } }