Skip to content

Commit

Permalink
[480] Add support for single inheritance (converter)
Browse files Browse the repository at this point in the history
Bug: #480
Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
  • Loading branch information
pcdavid committed May 7, 2021
1 parent d4a2186 commit 2b70491
Showing 1 changed file with 36 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*******************************************************************************/
package org.eclipse.sirius.web.emf.domain;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand All @@ -27,6 +29,7 @@
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.sirius.web.domain.Attribute;
import org.eclipse.sirius.web.domain.Domain;
import org.eclipse.sirius.web.domain.DomainFactory;
import org.eclipse.sirius.web.domain.Entity;
import org.eclipse.sirius.web.domain.Feature;
import org.eclipse.sirius.web.domain.Relation;
Expand All @@ -45,10 +48,35 @@ public Optional<EPackage> convert(Domain domain) {
ePackage.setNsURI(domain.getUri());

Map<Entity, EClass> convertedTypes = new HashMap<>();
for (Entity entity : domain.getTypes()) {
EClass eClass = this.convert(entity);
convertedTypes.put(entity, eClass);
ePackage.getEClassifiers().add(eClass);
// We need to make multiple passes to handle inheritance, as an Entity can only be converted
// once all its super types have been. We could use a topological sort to iterate in the correct
// order but it seems simpler to simply make multiple passes until all types are converted.
Deque<Entity> leftToConvert = new ArrayDeque<>(domain.getTypes());
Entity sentinel = DomainFactory.eINSTANCE.createEntity();
leftToConvert.addLast(sentinel);
// The worst case happens when we can only find and convert a single type on each pass.
// If we need more passes than that, it means at least one pass did not find any type that
// has all its parents already converted, and thus there is an inheritance loop.
int maxPasses = domain.getTypes().size();
int nbPasses = 0;
while (leftToConvert.size() > 1 && nbPasses <= maxPasses) {
Entity candidate = leftToConvert.pop();
if (candidate == sentinel) {
// We've hit the end of the queue, i.e. finished a single pass
nbPasses++;
leftToConvert.addLast(sentinel);
} else if (Optional.ofNullable(candidate.getSuperType()).stream().allMatch(convertedTypes::containsKey)) {
// candidate can be converted if all its super types have already been
EClass eClass = this.convert(candidate, convertedTypes);
convertedTypes.put(candidate, eClass);
ePackage.getEClassifiers().add(eClass);
} else {
// Try again in the next pass if we have converted all its super-types
leftToConvert.addLast(candidate);
}
}
if (leftToConvert.size() > 1) {
throw new IllegalStateException("Inheritance loop in domain definition"); //$NON-NLS-1$
}
for (Entity entity : domain.getTypes()) {
EClass eClass = convertedTypes.get(entity);
Expand All @@ -65,10 +93,13 @@ public Optional<EPackage> convert(Domain domain) {
}
}

private EClass convert(Entity entity) {
private EClass convert(Entity entity, Map<Entity, EClass> convertedTypes) {
EClass eClass = EcoreFactory.eINSTANCE.createEClass();
eClass.setName(entity.getName());
entity.getAttributes().forEach(attribute -> eClass.getEStructuralFeatures().add(this.convert(attribute)));
if (entity.getSuperType() != null && convertedTypes.containsKey(entity.getSuperType())) {
eClass.getESuperTypes().add(convertedTypes.get(entity.getSuperType()));
}
return eClass;
}

Expand Down

0 comments on commit 2b70491

Please sign in to comment.