blob: f14082828f234d5f6c3343ee45035c832b430343 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2016 Willink Transformations and others.
* 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:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.pivot.qvtcore.utilities;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.TreeIterable;
import org.eclipse.qvtd.pivot.qvtbase.Domain;
import org.eclipse.qvtd.pivot.qvtbase.Rule;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseEnvironmentFactory;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseEnvironmentFactory.CreateStrategy;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtcore.Area;
import org.eclipse.qvtd.pivot.qvtcore.Assignment;
import org.eclipse.qvtd.pivot.qvtcore.BottomPattern;
import org.eclipse.qvtd.pivot.qvtcore.CoreDomain;
import org.eclipse.qvtd.pivot.qvtcore.CoreModel;
import org.eclipse.qvtd.pivot.qvtcore.CorePattern;
import org.eclipse.qvtd.pivot.qvtcore.GuardPattern;
import org.eclipse.qvtd.pivot.qvtcore.Mapping;
import org.eclipse.qvtd.pivot.qvtcore.NavigationAssignment;
import org.eclipse.qvtd.pivot.qvtcore.OppositePropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcore.PropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcore.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcore.VariableAssignment;
import com.google.common.collect.Iterables;
public class QVTcoreUtil extends QVTbaseUtil
{
public static class Internal extends QVTbaseUtil.Internal
{
public static @NonNull List<@NonNull Assignment> getOwnedAssignmentsList(@NonNull BottomPattern mBottomPattern) {
return ClassUtil.nullFree(mBottomPattern.getAssignment());
}
}
protected static class PatternVariableComparator implements Comparator<@NonNull Variable>
{
private final @NonNull Map<@NonNull Variable, @Nullable List<@NonNull VariableDeclaration>> def2refs;
protected PatternVariableComparator(@NonNull Map<@NonNull Variable, @Nullable List<@NonNull VariableDeclaration>> def2refs) {
this.def2refs = def2refs;
}
@Override
public int compare(@NonNull Variable o1, @NonNull Variable o2) {
List<@NonNull VariableDeclaration> l1 = def2refs.get(o1);
List<@NonNull VariableDeclaration> l2 = def2refs.get(o2);
int s1 = l1 != null ? l1.size() : 0;
int s2 = l2 != null ? l2.size() : 0;
if (s1 != s2) {
return s1 - s2;
}
String n1 = o1.getName();
String n2 = o2.getName();
return ClassUtil.safeCompareTo(n1, n2);
}
}
public static @Nullable TypedModel basicGetTypedModel(@Nullable Area area) {
if (area instanceof CoreDomain) {
return ((CoreDomain)area).getTypedModel();
}
else {
return null;
}
}
public static @NonNull Set<Mapping> getAllRefinedMappings(@NonNull Mapping mapping) {
return getAllRefinedMappings(new HashSet<Mapping>(), mapping);
}
private static @NonNull Set<Mapping> getAllRefinedMappings(@NonNull Set<Mapping> allMappings, @NonNull Mapping mapping) {
if (allMappings.add(mapping)) {
for (@SuppressWarnings("null")@NonNull Mapping refinedMapping : mapping.getSpecification()) {
getAllRefinedMappings(allMappings, refinedMapping);
}
}
return allMappings;
}
public static @NonNull Area getArea(@NonNull Mapping mapping, @NonNull TypedModel typedModel) {
for (Domain domain : mapping.getDomain()) {
if (domain.getTypedModel() == typedModel) {
return (CoreDomain)domain;
}
}
return mapping;
}
public static @NonNull BottomPattern getBottomPattern(@NonNull Area area) {
return ClassUtil.nonNullState(area.getBottomPattern());
}
public static @Nullable Area getContainingArea(@Nullable EObject eObject) {
for ( ; eObject != null; eObject = eObject.eContainer()) {
if (eObject instanceof Area) {
return (Area) eObject;
}
}
return null;
}
public static @Nullable Mapping getContainingMapping(@Nullable EObject eObject) {
for ( ; eObject != null; eObject = eObject.eContainer()) {
if (eObject instanceof Mapping) {
return (Mapping) eObject;
}
}
return null;
}
public static @Nullable CorePattern getContainingPattern(@Nullable EObject eObject) {
for ( ; eObject != null; eObject = eObject.eContainer()) {
if (eObject instanceof CorePattern) {
return (CorePattern) eObject;
}
}
return null;
}
public static @Nullable CoreDomain getDomain(@NonNull Mapping rule, @NonNull TypedModel typedModel) {
return (CoreDomain)getDomain((Rule)rule, typedModel);
}
public static @NonNull GuardPattern getGuardPattern(@NonNull Area area) {
return ClassUtil.nonNullState(area.getGuardPattern());
}
public static @NonNull Iterable<@NonNull Assignment> getOwnedAssignments(@NonNull BottomPattern bottomPattern) {
return ClassUtil.nullFree(bottomPattern.getAssignment());
}
public static @NonNull Iterable<@NonNull CoreDomain> getOwnedDomains(@NonNull Mapping mapping) {
return Iterables.filter(ClassUtil.nullFree(mapping.getDomain()), CoreDomain.class);
}
public static @NonNull Iterable<@NonNull RealizedVariable> getOwnedRealizedVariables(@NonNull BottomPattern bottomPattern) {
return ClassUtil.nullFree(bottomPattern.getRealizedVariable());
}
public static @NonNull Iterable<@NonNull Variable> getOwnedVariables(@NonNull CorePattern corePattern) {
return ClassUtil.nullFree(corePattern.getVariable());
}
public static @NonNull OCLExpression getSlotExpression(@NonNull NavigationAssignment asNavigationAssignment) {
return ClassUtil.nonNullState(asNavigationAssignment.getSlotExpression());
}
public static @NonNull Property getTargetProperty(@NonNull NavigationAssignment asNavigationAssignment) {
if (asNavigationAssignment instanceof PropertyAssignment) {
return ClassUtil.nonNullState(((PropertyAssignment)asNavigationAssignment).getTargetProperty());
}
else if (asNavigationAssignment instanceof OppositePropertyAssignment) {
Property referredProperty = ClassUtil.nonNullState(((OppositePropertyAssignment)asNavigationAssignment).getTargetProperty());
if (referredProperty.eIsProxy() ) {
throw new IllegalStateException("Unresolved target property proxy '" + EcoreUtil.getURI(referredProperty) + "' at '" + EcoreUtil.getURI(asNavigationAssignment) + "'");
}
return ClassUtil.nonNullState(referredProperty.getOpposite());
}
throw new UnsupportedOperationException("Unsupported " + asNavigationAssignment.eClass().getName());
}
public static @NonNull Variable getTargetVariable(@NonNull VariableAssignment variableAssignment) {
return ClassUtil.nonNullState(variableAssignment.getTargetVariable());
}
public static @NonNull OCLExpression getValue(@NonNull Assignment asAssignment) {
return ClassUtil.nonNullState(asAssignment.getValue());
}
public static @NonNull Transformation loadTransformation(@NonNull QVTbaseEnvironmentFactory environmentFactory, @NonNull URI transformationURI, boolean keepDebug) throws IOException {
CreateStrategy savedStrategy = environmentFactory.setCreateStrategy(QVTcEnvironmentFactory.CREATE_STRATEGY);
try {
return loadTransformation(CoreModel.class, environmentFactory, transformationURI, keepDebug);
}
finally {
environmentFactory.setCreateStrategy(savedStrategy);
}
}
public static @NonNull Resource loadTransformations(@NonNull QVTbaseEnvironmentFactory environmentFactory, @NonNull URI transformationURI, boolean keepDebug) throws IOException {
CreateStrategy savedStrategy = environmentFactory.setCreateStrategy(QVTcEnvironmentFactory.CREATE_STRATEGY);
try {
return loadTransformations(CoreModel.class, environmentFactory, transformationURI, keepDebug);
}
finally {
environmentFactory.setCreateStrategy(savedStrategy);
}
}
/**
* Sort the pattern variables into a least referenced foirst then alphabetical order.
*/
public static void sortPatternVariables(@NonNull List<@NonNull Variable> variables) {
if (variables.size() > 1) {
final Map<@NonNull Variable, @Nullable List<@NonNull VariableDeclaration>> def2refs = new HashMap<@NonNull Variable, @Nullable List<@NonNull VariableDeclaration>>();
//
// Initialize the def2refs.keySet as a fast is-a-pattern-variable lookup.
//
for (@NonNull Variable variable : variables) {
def2refs.put(variable, null);
}
//
// Initialize the def2refs.values with the directly referenced pattern variables.
//
for (@NonNull Variable variable : variables) {
List<@NonNull VariableDeclaration> refs = null;
OCLExpression initExpression = variable.getOwnedInit();
if (initExpression != null) {
for (@NonNull EObject eObject : new TreeIterable(initExpression, true)) {
if (eObject instanceof VariableExp) {
VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable();
assert referredVariable != null;
if (def2refs.containsKey(referredVariable)) {
if (refs == null) {
refs = new ArrayList<@NonNull VariableDeclaration>();
def2refs.put(variable, refs);
}
if (!refs.contains(referredVariable)) {
refs.add(referredVariable);
}
}
}
}
}
}
//
// Recursively expand the def2refs.values to the closure of the directly referenced pattern variables.
//
boolean changed = true;
while (changed) {
changed = false;
for (@NonNull Variable variable : def2refs.keySet()) {
List<@NonNull VariableDeclaration> refs = def2refs.get(variable);
if (refs != null) {
for (int i = 0; i < refs.size(); i++) {
VariableDeclaration ref = refs.get(i);
List<@NonNull VariableDeclaration> refRefs = def2refs.get(ref);
if (refRefs != null) {
for (@NonNull VariableDeclaration refRef : refRefs) {
if (!refs.contains(refRef)) {
refs.add(refRef);
changed = true;
}
}
}
}
}
}
}
//
// Sort the variables fewest references first then alphabetically.
//
ClassUtil.sort(variables, new PatternVariableComparator(def2refs));
}
}
}