blob: 7f5bacea3f91f88022ff965de43d0644311cf64f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2021 Borland Software Corporation and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Borland Software Corporation - initial API and implementation
* Alex Paperno - bugs 424584
* Yuri Blankenstein - bug 428325
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.evaluator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.AbstractEList;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.m2m.internal.qvt.oml.ast.env.InternalEvaluationEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.env.TupleFactory;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalUtil;
import org.eclipse.m2m.internal.qvt.oml.expressions.DirectionKind;
import org.eclipse.m2m.internal.qvt.oml.expressions.MappingOperation;
import org.eclipse.m2m.internal.qvt.oml.expressions.MappingParameter;
import org.eclipse.m2m.internal.qvt.oml.expressions.ModelType;
import org.eclipse.m2m.internal.qvt.oml.expressions.Module;
import org.eclipse.m2m.internal.qvt.oml.expressions.ModuleImport;
import org.eclipse.m2m.internal.qvt.oml.expressions.VarParameter;
import org.eclipse.m2m.internal.qvt.oml.trace.EDirectionKind;
import org.eclipse.m2m.internal.qvt.oml.trace.EMappingContext;
import org.eclipse.m2m.internal.qvt.oml.trace.EMappingOperation;
import org.eclipse.m2m.internal.qvt.oml.trace.EMappingParameters;
import org.eclipse.m2m.internal.qvt.oml.trace.EMappingResults;
import org.eclipse.m2m.internal.qvt.oml.trace.ETuplePartValue;
import org.eclipse.m2m.internal.qvt.oml.trace.EValue;
import org.eclipse.m2m.internal.qvt.oml.trace.Trace;
import org.eclipse.m2m.internal.qvt.oml.trace.TraceFactory;
import org.eclipse.m2m.internal.qvt.oml.trace.TraceRecord;
import org.eclipse.m2m.internal.qvt.oml.trace.VarParameterValue;
import org.eclipse.m2m.qvt.oml.util.Dictionary;
import org.eclipse.m2m.qvt.oml.util.MutableList;
import org.eclipse.m2m.qvt.oml.util.Utils;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.types.BagType;
import org.eclipse.ocl.types.CollectionType;
import org.eclipse.ocl.types.OrderedSetType;
import org.eclipse.ocl.types.PrimitiveType;
import org.eclipse.ocl.types.SequenceType;
import org.eclipse.ocl.types.SetType;
import org.eclipse.ocl.types.TupleType;
import org.eclipse.ocl.util.Bag;
import org.eclipse.ocl.util.CollectionUtil;
import org.eclipse.ocl.util.Tuple;
import org.eclipse.ocl.util.TypeUtil;
import org.eclipse.ocl.utilities.PredefinedType;
public class TraceUtil {
private TraceUtil() {
}
static TraceRecord getTraceRecord(QvtOperationalEvaluationEnv evalEnv, MappingOperation mappingOperation) {
InternalEvaluationEnv internEnv = evalEnv.getAdapter(InternalEvaluationEnv.class);
Trace trace = internEnv.getTraces();
Object selfObj = evalEnv.getValueOf(Environment.SELF_VARIABLE_NAME);
Object key = createKey(selfObj, evalEnv, mappingOperation);
if (key != null) {
TraceRecord record = trace.getRecordBySource(mappingOperation, key);
if (record != null && Boolean.TRUE.equals(checkResultMatch(record, evalEnv))) {
return record;
}
// nothing found, mapping executed for the first time on the given
// source
return null;
}
// Fall back on 'original' TraceUtil
return getTraceRecordDefault(evalEnv, mappingOperation);
}
private static TraceRecord getTraceRecordDefault(QvtOperationalEvaluationEnv evalEnv, MappingOperation mappingOperation) {
InternalEvaluationEnv internEnv = evalEnv.getAdapter(InternalEvaluationEnv.class);
Trace trace = internEnv.getTraces();
Object selfObj = evalEnv.getValueOf(Environment.SELF_VARIABLE_NAME);
// the direct fetch by the contextual source object
if(selfObj != null && isParameterLessContextual(mappingOperation)) {
TraceRecord record = trace.getRecordBySource(mappingOperation, selfObj);
if(record != null && Boolean.TRUE.equals(checkResultMatch(record, evalEnv))) {
return record;
}
// nothing found, mapping executed for the first time on the given source
return null;
}
EMap<MappingOperation, EList<TraceRecord>> allTraceRecordMap = trace.getTraceRecordMap();
EList<TraceRecord> traceRecords = allTraceRecordMap.get(mappingOperation);
if (traceRecords == null) {
return null;
}
// Section [8.2.1.15]
// After call resolution, all the parameters of the mapping are passed as a tuple.
// The parameters include, in this order: the context parameter (if any), the owned
// parameters (from Operation::ownedParameter), and the parameters declared as result.
traceCheckCycle:
for (TraceRecord nextRecord : traceRecords) {
// check context parameter
if (QvtOperationalParserUtil.isContextual(mappingOperation)) {
VarParameterValue nextContext = nextRecord.getContext().getContext();
if (nextContext == null) {
continue;
}
if (!isOclEqual(selfObj, nextContext.getValue().getOclObject(), mappingOperation.getContext().getKind(), evalEnv)) {
continue;
}
}
// check owned parameters
int candidateParamSize = mappingOperation.getEParameters().size();
if (nextRecord.getParameters().getParameters().size() != candidateParamSize) {
continue;
}
for (int i = 0; i < candidateParamSize; i++) {
EParameter param = mappingOperation.getEParameters().get(i);
Object paramValue = evalEnv.getValueOf(param.getName());
VarParameterValue traceParamVal = (VarParameterValue) nextRecord.getParameters().getParameters().get(i);
DirectionKind paramKind = DirectionKind.IN;
if (param instanceof VarParameter) {
paramKind = ((VarParameter) param).getKind();
}
if (paramKind != DirectionKind.OUT
&& !isOclEqual(paramValue, traceParamVal.getValue().getOclObject(), paramKind, evalEnv)) {
continue traceCheckCycle;
}
}
// check result parameters
Boolean checkResult = checkResultMatch(nextRecord, evalEnv);
if(checkResult == null) {
continue;
} else if(Boolean.FALSE.equals(checkResult)) {
continue traceCheckCycle;
}
return nextRecord;
}
return null;
}
static TraceRecord addTraceRecord(QvtOperationalEvaluationEnv evalEnv, MappingOperation mappingOperation) {
TraceRecord traceRecord = TraceFactory.eINSTANCE.createTraceRecord();
InternalEvaluationEnv internEnv = evalEnv.getAdapter(InternalEvaluationEnv.class);
Trace trace = internEnv.getTraces();
EList<TraceRecord> allRecList = createOrGetListElementFromMap(trace.getTraceRecordMap(), mappingOperation);
addUnique(traceRecord, allRecList);
EMappingOperation eMappingOperation = TraceFactory.eINSTANCE.createEMappingOperation();
traceRecord.setMappingOperation(eMappingOperation);
eMappingOperation.setName(mappingOperation.getName());
Module module = QvtOperationalParserUtil.getOwningModule(mappingOperation);
eMappingOperation.setPackage(module.getNsPrefix());
eMappingOperation.setModule(module.getName());
eMappingOperation.setRuntimeMappingOperation(mappingOperation);
EMappingContext eMappingContext = TraceFactory.eINSTANCE.createEMappingContext();
traceRecord.setContext(eMappingContext);
if(QvtOperationalParserUtil.isContextual(mappingOperation)) {
VarParameter operContext = mappingOperation.getContext();
VarParameterValue contextVPV = createVarParameterValue(mappingOperation,
operContext.getKind(), operContext.getEType(), Environment.SELF_VARIABLE_NAME, evalEnv);
eMappingContext.setContext(contextVPV);
EList<TraceRecord> contextMappings = createOrGetListElementFromMap(trace.getSourceToTraceRecordMap(), contextVPV.getValue().getOclObject());
addUnique(traceRecord, contextMappings);
}
else {
// make the first in parameter as the mapping source object
for (EParameter nextEParam : mappingOperation.getEParameters()) {
if(nextEParam instanceof VarParameter) {
VarParameter firstInVarParam = (VarParameter) nextEParam;
if((firstInVarParam.getEType() instanceof PredefinedType<?> == false)
&& (firstInVarParam.getKind() == DirectionKind.IN || firstInVarParam.getKind() == DirectionKind.INOUT)) {
Object val = createVarParameterValue(mappingOperation, firstInVarParam.getKind() ,
firstInVarParam.getEType(), firstInVarParam.getName(), evalEnv).getValue().getOclObject();
EList<TraceRecord> sourceMappings = createOrGetListElementFromMap(trace.getSourceToTraceRecordMap(), val);
addUnique(traceRecord, sourceMappings);
break;
}
}
}
}
EMappingParameters eMappingParameters = TraceFactory.eINSTANCE.createEMappingParameters();
traceRecord.setParameters(eMappingParameters);
for (EParameter param : mappingOperation.getEParameters()) {
VarParameter varParameter = (VarParameter) param;
VarParameterValue paramVPV = createVarParameterValue(mappingOperation, varParameter.getKind(),
varParameter.getEType(), varParameter.getName(), evalEnv);
eMappingParameters.getParameters().add(paramVPV);
}
EMappingResults eMappingResults = TraceFactory.eINSTANCE.createEMappingResults();
traceRecord.setResult(eMappingResults);
EList<VarParameter> results = mappingOperation.getResult();
if (!results.isEmpty()) {
String resultVarName = results.size() == 1 ? results.get(0).getName() : Environment.RESULT_VARIABLE_NAME;
EClassifier resultElementType = results.size() == 1 ? results.get(0).getEType() : mappingOperation.getEType();
VarParameterValue resultVPV = createVarParameterValue(mappingOperation, DirectionKind.OUT, resultElementType, resultVarName, evalEnv);
eMappingResults.getResult().add(resultVPV);
EList<TraceRecord> resultMappings = createOrGetListElementFromMap(trace.getTargetToTraceRecordMap(), resultVPV.getValue().getOclObject());
addUnique(traceRecord, resultMappings);
}
// Note: add it here so we ensure the record is fully initialized
addUnique(traceRecord, trace.getTraceRecords());
addTraceRecordByMapping(mappingOperation, traceRecord, trace);
return traceRecord;
}
/**
* Improves performance a lot for mapping operations with parameters by
* means of (re)using the cache.
*/
private static void addTraceRecordByMapping(MappingOperation mappingOperation, TraceRecord traceRecord, Trace trace) {
Object selfObj = null;
if (traceRecord.getContext() != null && traceRecord.getContext().getContext() != null) {
EValue value = traceRecord.getContext().getContext().getValue();
selfObj = value.getOclObject();
}
Object key = createKey(selfObj, traceRecord);
if (key != null) {
trace.addRecordBySource(key, mappingOperation, traceRecord);
}
}
/**
* Creates a key for mapping operations, based on the context (if available)
* and all parameters (if any).
*/
private static Object createKey(Object selfObj, QvtOperationalEvaluationEnv evalEnv, MappingOperation mappingOperation) {
EList<EParameter> eParameters = mappingOperation.getEParameters();
if (eParameters.isEmpty()) {
// Backwards compatible for isParameterLessContextual
return selfObj;
}
ArrayList<Object> key = new ArrayList<Object>(eParameters.size() + 1);
key.add(selfObj);
for (EParameter param : eParameters) {
VarParameter varParam = (VarParameter) param;
if (varParam.getKind() == DirectionKind.OUT) {
continue;
}
key.add(evalEnv.getValueOf(param.getName()));
}
return key;
}
/**
* Creates a key for mapping operations, based on the context (if available)
* and all parameters (if any).
*/
private static Object createKey(Object selfObj, TraceRecord traceRecord) {
EList<VarParameterValue> eParameters = traceRecord.getParameters().getParameters();
if (eParameters.isEmpty()) {
// Backwards compatible for isParameterLessContextual
return selfObj;
}
ArrayList<Object> key = new ArrayList<Object>(eParameters.size() + 1);
key.add(selfObj);
for (VarParameterValue param : eParameters) {
if (param.getKind() == EDirectionKind.OUT) {
continue;
}
key.add(param.getValue().getOclObject());
}
return key;
}
static Object fetchResultFromTrace(QvtOperationalEvaluationEnv evalEnv, TraceRecord record) {
MappingOperation operation = record.getMappingOperation().getRuntimeMappingOperation();
if (operation.getResult().isEmpty()) {
return null;
}
ListIterator<Object> itArgument = evalEnv.getOperationArgs().listIterator();
Iterator<VarParameterValue> itValues = record.getParameters().getParameters().iterator();
while (itArgument.hasNext()) {
VarParameterValue param = itValues.next();
itArgument.next();
if (param.getKind() == EDirectionKind.OUT) {
itArgument.set(param.getValue().getOclObject());
}
}
EList<VarParameterValue> traceResult = record.getResult().getResult();
assert traceResult.size() == 1;
return traceResult.get(0).getValue().getOclObject();
}
private static VarParameterValue createVarParameterValue(MappingOperation mappingOperation, DirectionKind kind, EClassifier type, String name, QvtOperationalEvaluationEnv evalEnv) {
VarParameterValue varParameterValue = TraceFactory.eINSTANCE.createVarParameterValue();
varParameterValue.setKind(getDirectionKind(kind));
varParameterValue.setName(name);
varParameterValue.setType(type.getName());
Object oclObject = evalEnv.getValueOf(name);
varParameterValue.setValue(createEValue(oclObject, kind));
return varParameterValue;
}
/**
* @deprecated Use {@link #createEValue(Object, DirectionKind)}.
*/
@Deprecated
public static EValue createEValue(Object oclObject) {
return createEValue(oclObject, DirectionKind.IN);
}
@SuppressWarnings("unchecked")
public static EValue createEValue(Object oclObject, DirectionKind kind) {
EValue value = TraceFactory.eINSTANCE.createEValue();
value.setOclObject(cloneOclObject(oclObject, kind));
if (oclObject != null) {
if (oclObject instanceof Dictionary) {
Dictionary<Object, Object> dict = (Dictionary<Object, Object>) oclObject;
value.setCollectionType(Dictionary.SINGLETON_NAME);
for (Object dictKey : dict.keys()) {
ETuplePartValue tuplePartValue = TraceFactory.eINSTANCE.createETuplePartValue();
tuplePartValue.setName("key"); //$NON-NLS-1$
tuplePartValue.setValue(createEValue(dictKey, kind));
value.getCollection().add(tuplePartValue);
Object dictValue = dict.get(dictKey);
tuplePartValue = TraceFactory.eINSTANCE.createETuplePartValue();
tuplePartValue.setName("value"); //$NON-NLS-1$
tuplePartValue.setValue(createEValue(dictValue, kind));
value.getCollection().add(tuplePartValue);
}
} else if (oclObject instanceof Tuple) {
Tuple<EOperation, EStructuralFeature> tuple = (Tuple<EOperation, EStructuralFeature>) oclObject;
value.setCollectionType(TupleType.SINGLETON_NAME);
TupleType<EOperation, EStructuralFeature> tupleType = tuple.getTupleType();
for (EStructuralFeature part : tupleType.oclProperties()) {
Object partValue = tuple.getValue(part);
ETuplePartValue tuplePartValue = TraceFactory.eINSTANCE.createETuplePartValue();
tuplePartValue.setName(part.getName());
EValue partEValue = createEValue(partValue, kind);
tuplePartValue.setValue(partEValue);
value.getCollection().add(tuplePartValue);
}
} else if (oclObject instanceof Collection) {
Collection<Object> oclCollection = (Collection<Object>) oclObject;
// TODO: Write a test for checking collections
value.setCollectionType(getCollectionTypeName(oclCollection));
for (Object collectionElement : oclCollection) {
value.getCollection().add(createEValue(collectionElement, kind));
}
} else if (oclObject instanceof ModelInstance) {
value.setCollectionType(ModelType.SINGLETON_NAME);
for (Object collectionElement : ((ModelInstance) oclObject).getExtent().getInitialObjects()) {
value.getCollection().add(createEValue(collectionElement, kind));
}
} else if (oclObject instanceof EObject) {
value.setModelElement((EObject) oclObject);
} else {
if (oclObject != null) {
value.setPrimitiveValue(oclObject.toString());
value.setCollectionType(getPrimitiveTypeName(oclObject));
}
}
}
return value;
}
private static String getCollectionTypeName(Collection<?> c) {
String result = CollectionType.SINGLETON_NAME;
if (c instanceof MutableList<?>) {
result = MutableList.SINGLETON_NAME;
} else if (c instanceof Dictionary<?, ?>) {
result = Dictionary.SINGLETON_NAME;
} else if (c instanceof Bag<?>) {
result = BagType.SINGLETON_NAME;
} else if (c instanceof LinkedHashSet<?>) {
result = OrderedSetType.SINGLETON_NAME;
} else if (c instanceof Set<?>) {
result = SetType.SINGLETON_NAME;
} else if (c instanceof ArrayList<?>) {
result = SequenceType.SINGLETON_NAME;
}
return result;
}
private static String getPrimitiveTypeName(Object o) {
if (o instanceof Boolean) {
return PrimitiveType.BOOLEAN_NAME;
}
if (o instanceof Integer) {
return PrimitiveType.INTEGER_NAME;
}
if (o instanceof Double) {
return PrimitiveType.REAL_NAME;
}
if (o instanceof String) {
return PrimitiveType.STRING_NAME;
}
return null;
}
private static Object cloneOclObject(Object obj, DirectionKind kind) {
return cloneOclObjectRec(obj, new IdentityHashMap<Object, Object>(), kind);
}
@SuppressWarnings("unchecked")
private static Object cloneOclObjectRec(Object obj, Map<Object, Object> processed, DirectionKind kind) {
if (kind == DirectionKind.IN && obj instanceof MutableList<?>) {
if (processed.containsKey(obj)) {
return processed.get(obj);
}
MutableList<Object> original = (MutableList<Object>) obj;
MutableList<Object> result = Utils.createList();
processed.put(obj, result);
for (Object o : original) {
result.add(cloneOclObjectRec(o, processed, kind));
}
return result;
}
if (kind == DirectionKind.IN && obj instanceof Dictionary<?, ?>) {
if (processed.containsKey(obj)) {
return processed.get(obj);
}
Dictionary<Object, Object> original = (Dictionary<Object, Object>) obj;
Dictionary<Object, Object> result = Utils.createDictionary();
processed.put(obj, result);
for (Object k : original.keys()) {
result.put(cloneOclObjectRec(k, processed, kind), cloneOclObjectRec(original.get(k), processed, kind));
}
return result;
}
return obj;
}
private static EDirectionKind getDirectionKind(DirectionKind kind) {
if (kind == DirectionKind.IN) {
return EDirectionKind.IN;
} else if (kind == DirectionKind.INOUT) {
return EDirectionKind.INOUT;
} else if (kind == DirectionKind.OUT) {
return EDirectionKind.OUT;
}
throw new RuntimeException("Wrong DirectionKind: " + kind.name()); //$NON-NLS-1$
}
private static <K, T> EList<T> createOrGetListElementFromMap(EMap<K, EList<T>> map, K key) {
EList<T> list = map.get(key);
if (list == null) {
list = new BasicEList<T>();
map.put(key, list);
list = map.get(key);
}
return list;
}
private static boolean isOclEqual(Object candidateObject, Object traceObject, DirectionKind directionKind, QvtOperationalEvaluationEnv evalEnv) {
if (directionKind == DirectionKind.OUT) {
if (candidateObject == null) {
// yet not bound 'out' parameter, suit for any
return true;
}
}
if (candidateObject == traceObject) {
return true;
}
if (QvtOperationalUtil.isUndefined(candidateObject, evalEnv)) {
return QvtOperationalUtil.isUndefined(traceObject, evalEnv);
}
if ((candidateObject == null) || (traceObject == null)) {
return false;
}
return candidateObject.equals(traceObject); // Overridden equals() is implied
}
private static Boolean checkResultMatch(TraceRecord nextRecord, QvtOperationalEvaluationEnv evalEnv) {
// check result parameters
Object resultValue = evalEnv.getValueOf(Environment.RESULT_VARIABLE_NAME);
if (resultValue != null) {
List<Object> resultValues = new ArrayList<Object>(1);
resultValues.add(resultValue);
if (nextRecord.getResult().getResult().size() != resultValues.size()) {
return null;
}
for (int i = 0, n = resultValues.size(); i < n; i++) {
Object paramValue = resultValues.get(i);
VarParameterValue traceParamVal = (VarParameterValue) nextRecord.getResult().getResult().get(i);
if (!isOclEqual(paramValue, traceParamVal.getValue().getOclObject(), DirectionKind.OUT, evalEnv)) {
return Boolean.FALSE;
}
}
}
return Boolean.TRUE;
}
private static boolean isParameterLessContextual(MappingOperation mappingOperation) {
return QvtOperationalParserUtil.isContextual(mappingOperation) && mappingOperation.getEParameters().isEmpty();
}
private static void addUnique(TraceRecord record, EList<TraceRecord> recordList) {
if(recordList instanceof AbstractEList<?>) {
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=287589
AbstractEList<TraceRecord> basicRecList = (AbstractEList<TraceRecord>) recordList;
basicRecList.addUnique(record);
} else {
// TODO - spit a trace warning
recordList.add(record);
}
}
static TraceRecord getIncrementalTraceRecord(QvtOperationalEvaluationEnv evalEnv, QvtOperationalEnv env, MappingOperation mappingOperation) {
List<EObject> traceContent = evalEnv.getContext().getTrace().getTraceContent();
if (traceContent.isEmpty()) {
return null;
}
Object selfObj = evalEnv.getValueOf(Environment.SELF_VARIABLE_NAME);
Object key = createKey(selfObj, evalEnv, mappingOperation);
if (key != null) {
for (EObject o : traceContent) {
if (false == o instanceof Trace) {
continue;
}
TraceRecord record = ((Trace) o).getRecordBySource(mappingOperation, key);
if (record != null && Boolean.TRUE.equals(checkIncrementalResultMatch(env, record))) {
return record;
}
}
}
// nothing found
return null;
}
private static boolean checkIncrementalResultMatch(QvtOperationalEnv env, TraceRecord record) {
MappingOperation operation = record.getMappingOperation().getRuntimeMappingOperation();
Iterator<VarParameterValue> itrRecordParams = record.getParameters().getParameters().iterator();
for (EParameter param : operation.getEParameters()) {
if (!itrRecordParams.hasNext()) {
return false;
}
VarParameterValue recordParam = itrRecordParams.next();
if (!recordParam.getType().equals(param.getEType().getName())) {
return false;
}
}
if (operation.getResult().isEmpty()) {
return true;
}
if (record.getResult().getResult().size() != 1) {
return false;
}
VarParameterValue resultParam = record.getResult().getResult().get(0);
if (operation.getResult().size() == 1) {
if (!resultParam.getType().equals(operation.getResult().get(0).getEType().getName())) {
return false;
}
}
else {
EValue value = resultParam.getValue();
if (!TupleType.SINGLETON_NAME.equals(value.getCollectionType())) {
return false;
}
EClass resultType = (EClass) createOclTypeFromValue(env, value);
for (VarParameter param : operation.getResult()) {
EStructuralFeature feature = resultType.getEStructuralFeature(param.getName());
if (feature == null) {
return false;
}
if (!param.getEType().getName().equals(feature.getEType().getName())) {
return false;
}
}
}
return true;
}
static void fetchIncrementalResultFromTrace(QvtOperationalEvaluationEnv evalEnv, TraceRecord record) {
MappingOperation operation = record.getMappingOperation().getRuntimeMappingOperation();
Iterator<EParameter> itParams = operation.getEParameters().iterator();
for (VarParameterValue value : record.getParameters().getParameters()) {
MappingParameter mappingParam = (MappingParameter) itParams.next();
if (value.getKind() == EDirectionKind.OUT) {
Object oclObject = value.getValue().getOclObject();
if (oclObject != null) {
evalEnv.replace(value.getName(), oclObject);
}
if (oclObject instanceof EObject) {
evalEnv.putInstanceToExtent((EObject) oclObject, mappingParam.getExtent());
}
}
}
if (operation.getResult().isEmpty()) {
return;
}
EList<VarParameterValue> traceResult = record.getResult().getResult();
assert traceResult.size() == 1;
if (operation.getResult().size() == 1) {
Object oclObject = traceResult.get(0).getValue().getOclObject();
if (oclObject != null) {
evalEnv.replace(Environment.RESULT_VARIABLE_NAME, oclObject);
}
if (oclObject instanceof EObject) {
MappingParameter resultParam = (MappingParameter) operation.getResult().get(0);
evalEnv.putInstanceToExtent((EObject) oclObject, resultParam.getExtent());
}
}
else if (operation.getResult().size() > 1) {
@SuppressWarnings("unchecked")
Tuple<EOperation, EStructuralFeature> tuple = (Tuple<EOperation, EStructuralFeature>) traceResult.get(0).getValue().getOclObject();
Iterator<VarParameter> itrResults = operation.getResult().iterator();
TupleType<EOperation, EStructuralFeature> tupleType = tuple.getTupleType();
for (EStructuralFeature feature : tupleType.oclProperties()) {
Object oclObject = tuple.getValue(feature);
if (oclObject != null) {
evalEnv.replace(feature.getName(), oclObject);
}
if (oclObject instanceof EObject) {
MappingParameter resultParam = (MappingParameter) itrResults.next();
evalEnv.putInstanceToExtent((EObject) oclObject, resultParam.getExtent());
}
}
}
}
public static List<EObject> resolveTraces(QvtOperationalEnv env, Module qvtModule, List<EObject> traces) {
if (traces.isEmpty()) {
return traces;
}
List<EObject> result = new ArrayList<EObject>(traces.size());
Map<String, MappingOperation> mappings = null;
for (EObject o : traces) {
if (false == o instanceof Trace) {
result.add(o);
continue;
}
Trace trace = (Trace) o;
if (!trace.hasRecordsBySource() || getTraceRootModule(trace) != qvtModule) {
if (mappings == null) {
mappings = new TreeMap<String, MappingOperation>();
fetchAllMappings(qvtModule, mappings);
}
setTraceRootModule(trace, qvtModule);
processTrace(env, trace, mappings);
}
result.add(trace);
}
return result;
}
private static void processTrace(QvtOperationalEnv env, Trace trace, Map<String, MappingOperation> mappings) {
trace.clearRecordsBySource();
for (TraceRecord traceRecord : trace.getTraceRecords()) {
EMappingOperation eMappingOperation = traceRecord.getMappingOperation();
MappingOperation mappingOperation = mappings.get(getMappingKey(eMappingOperation));
eMappingOperation.setRuntimeMappingOperation(mappingOperation);
if (mappingOperation != null) {
if (traceRecord.getContext() != null && traceRecord.getContext().getContext() != null) {
VarParameterValue value = traceRecord.getContext().getContext();
value.getValue().setOclObject(createOclObjectFromValue(env, value.getValue(), value.getKind()));
}
EList<VarParameterValue> eParameters = traceRecord.getParameters().getParameters();
for (VarParameterValue param : eParameters) {
param.getValue().setOclObject(createOclObjectFromValue(env, param.getValue(), param.getKind()));
}
EList<VarParameterValue> eResults = traceRecord.getResult().getResult();
for (VarParameterValue result : eResults) {
result.getValue().setOclObject(createOclObjectFromValue(env, result.getValue(), result.getKind()));
}
addTraceRecordByMapping(mappingOperation, traceRecord, trace);
}
}
//EcoreUtil.resolveAll(trace);
}
private static Object createOclObjectFromValue(QvtOperationalEnv env, EValue value, EDirectionKind directionKind) {
if (value.getModelElement() != null) {
EObject modelElement = value.getModelElement();
if (modelElement.eIsProxy()) {
return null;
}
if (directionKind == EDirectionKind.OUT) {
// model element which is fetched from the trace should operate like a new object
((InternalEObject) modelElement).eSetResource(null, null);
}
return modelElement;
}
final String type = value.getCollectionType();
if (value.getPrimitiveValue() != null) {
final String primitiveValue = value.getPrimitiveValue();
if (PrimitiveType.STRING_NAME.equals(type)) {
return primitiveValue;
}
else if (PrimitiveType.BOOLEAN_NAME.equals(type)) {
return Boolean.valueOf(primitiveValue);
}
else if (PrimitiveType.INTEGER_NAME.equals(type)) {
return Integer.valueOf(primitiveValue);
}
else if (PrimitiveType.REAL_NAME.equals(type)) {
return Double.valueOf(primitiveValue);
}
else if (PrimitiveType.UNLIMITED_NATURAL_NAME.equals(type)) {
return Integer.valueOf(primitiveValue);
}
assert false : ("Unknown primitive type: " + type); //$NON-NLS-1$
}
if (Dictionary.SINGLETON_NAME.equals(type)) {
Dictionary<Object, Object> dict = Utils.createDictionary();
for (Iterator<EValue> itr = value.getCollection().iterator(); itr.hasNext(); ) {
ETuplePartValue key = (ETuplePartValue) itr.next();
assert "key".equals(key.getName());
ETuplePartValue val = (ETuplePartValue) itr.next();
assert "value".equals(val.getName());
dict.put(createOclObjectFromValue(env, key.getValue(), directionKind), createOclObjectFromValue(env, val.getValue(), directionKind));
}
return dict;
}
if (TupleType.SINGLETON_NAME.equals(type)) {
List<Variable<EClassifier, EParameter>> parts = new ArrayList<Variable<EClassifier,EParameter>>(value.getCollection().size());
for (EValue elem : value.getCollection()) {
ETuplePartValue part = (ETuplePartValue) elem;
Variable<EClassifier, EParameter> var = env.getOCLFactory().createVariable();
var.setName(part.getName());
var.setType(createOclTypeFromValue(env, part.getValue()));
parts.add(var);
}
EClassifier tupleType = env.getTypeResolver().resolve((EClassifier)env.getOCLFactory().createTupleType(parts));
EObject tuple = TupleFactory.createTuple((EClass) tupleType);
for (EValue elem : value.getCollection()) {
ETuplePartValue part = (ETuplePartValue) elem;
EStructuralFeature feature = tuple.eClass().getEStructuralFeature(part.getName());
tuple.eSet(feature, createOclObjectFromValue(env, part.getValue(), directionKind));
}
return tuple;
}
Collection<Object> oclCollection = null;
if (MutableList.SINGLETON_NAME.equals(type)) {
oclCollection = Utils.createList();
}
else if (BagType.SINGLETON_NAME.equals(type)) {
oclCollection = CollectionUtil.createNewBag();
}
else if (OrderedSetType.SINGLETON_NAME.equals(type)) {
oclCollection = CollectionUtil.createNewOrderedSet();
}
else if (SetType.SINGLETON_NAME.equals(type)) {
oclCollection = CollectionUtil.createNewSet();
}
else if (SequenceType.SINGLETON_NAME.equals(type)) {
oclCollection = CollectionUtil.createNewSequence();
}
if (oclCollection != null) {
for (EValue elem : value.getCollection()) {
oclCollection.add(createOclObjectFromValue(env, elem, directionKind));
}
return oclCollection;
}
assert false : ("Unsupported type: " + type); //$NON-NLS-1$
return null;
}
private static EClassifier createOclTypeFromValue(QvtOperationalEnv env, EValue value) {
if (value.getModelElement() != null) {
return value.getModelElement().eClass();
}
final String type = value.getCollectionType();
if (value.getPrimitiveValue() != null) {
if (PrimitiveType.STRING_NAME.equals(type)) {
return env.getOCLStandardLibrary().getString();
}
else if (PrimitiveType.BOOLEAN_NAME.equals(type)) {
return env.getOCLStandardLibrary().getBoolean();
}
else if (PrimitiveType.INTEGER_NAME.equals(type)) {
return env.getOCLStandardLibrary().getInteger();
}
else if (PrimitiveType.REAL_NAME.equals(type)) {
return env.getOCLStandardLibrary().getReal();
}
else if (PrimitiveType.UNLIMITED_NATURAL_NAME.equals(type)) {
return env.getOCLStandardLibrary().getUnlimitedNatural();
}
assert false : ("Unknown primitive type: " + type); //$NON-NLS-1$
}
if (Dictionary.SINGLETON_NAME.equals(type)) {
if (value.getCollection().isEmpty()) {
return env.getQVTStandardLibrary().getDictionary();
}
else {
for (Iterator<EValue> itr = value.getCollection().iterator(); itr.hasNext(); ) {
ETuplePartValue key = (ETuplePartValue) itr.next();
assert "key".equals(key.getName());
ETuplePartValue val = (ETuplePartValue) itr.next();
assert "value".equals(val.getName());
return env.getTypeResolver().resolveDictionaryType(createOclTypeFromValue(env, key.getValue()), createOclTypeFromValue(env, val.getValue()));
}
}
}
if (TupleType.SINGLETON_NAME.equals(type)) {
List<Variable<EClassifier, EParameter>> parts = new ArrayList<Variable<EClassifier,EParameter>>(value.getCollection().size());
for (EValue elem : value.getCollection()) {
ETuplePartValue part = (ETuplePartValue) elem;
Variable<EClassifier, EParameter> var = env.getOCLFactory().createVariable();
var.setName(part.getName());
var.setType(createOclTypeFromValue(env, part.getValue()));
parts.add(var);
}
return env.getTypeResolver().resolve((EClassifier)env.getOCLFactory().createTupleType(parts));
}
if (MutableList.SINGLETON_NAME.equals(type)) {
if (value.getCollection().isEmpty()) {
return env.getQVTStandardLibrary().getList();
}
else {
return env.getTypeResolver().resolveListType(createOclTypeFromValue(env, value.getCollection().iterator().next()));
}
}
else if (BagType.SINGLETON_NAME.equals(type)) {
if (value.getCollection().isEmpty()) {
return env.getOCLStandardLibrary().getBag();
}
else {
return TypeUtil.resolveBagType(env, createOclTypeFromValue(env, value.getCollection().iterator().next()));
}
}
else if (OrderedSetType.SINGLETON_NAME.equals(type)) {
if (value.getCollection().isEmpty()) {
return env.getOCLStandardLibrary().getOrderedSet();
}
else {
return TypeUtil.resolveOrderedSetType(env, createOclTypeFromValue(env, value.getCollection().iterator().next()));
}
}
else if (SetType.SINGLETON_NAME.equals(type)) {
if (value.getCollection().isEmpty()) {
return env.getOCLStandardLibrary().getSet();
}
else {
return TypeUtil.resolveSetType(env, createOclTypeFromValue(env, value.getCollection().iterator().next()));
}
}
else if (SequenceType.SINGLETON_NAME.equals(type)) {
if (value.getCollection().isEmpty()) {
return env.getOCLStandardLibrary().getSequence();
}
else {
return TypeUtil.resolveSequenceType(env, createOclTypeFromValue(env, value.getCollection().iterator().next()));
}
}
assert false : ("Unsupported type: " + type); //$NON-NLS-1$
return null;
}
private static void fetchAllMappings(Module qvtModule, Map<String, MappingOperation> mappings) {
for (EOperation op : qvtModule.getEOperations()) {
if (op instanceof MappingOperation) {
MappingOperation mappingOperation = (MappingOperation) op;
mappings.put(getMappingKey(mappingOperation), mappingOperation);
}
}
for (ModuleImport mi : qvtModule.getModuleImport()) {
fetchAllMappings(mi.getImportedModule(), mappings);
}
}
private static String getMappingKey(MappingOperation mappingOperation) {
String result = mappingOperation.getName();
result += '#';
Module module = QvtOperationalParserUtil.getOwningModule(mappingOperation);
result += module.getNsPrefix();
result += '#';
result += module.getName();
return result;
}
private static String getMappingKey(EMappingOperation eMappingOperation) {
String result = eMappingOperation.getName();
result += '#';
result += eMappingOperation.getPackage();
result += '#';
result += eMappingOperation.getModule();
return result;
}
public static void setTraceRootModule(QvtOperationalEvaluationEnv evalEnv, Module module) {
InternalEvaluationEnv internEnv = evalEnv.getAdapter(InternalEvaluationEnv.class);
Trace trace = internEnv.getTraces();
setTraceRootModule(trace, module);
}
private static void setTraceRootModule(Trace trace, Module module) {
Adapter adapter = EcoreUtil.getAdapter(trace.eAdapters(), TraceModuleAdapter.class);
if(adapter != null) {
trace.eAdapters().remove(adapter);
}
trace.eAdapters().add(new TraceModuleAdapter(module));
}
private static Module getTraceRootModule(Trace trace) {
Adapter adapter = EcoreUtil.getAdapter(trace.eAdapters(), TraceModuleAdapter.class);
if(adapter instanceof TraceModuleAdapter) {
return ((TraceModuleAdapter) adapter).getModule();
}
return null;
}
private static class TraceModuleAdapter extends AdapterImpl {
private final Module fModule;
TraceModuleAdapter(Module module) {
assert module != null;
fModule = module;
}
@Override
public boolean isAdapterForType(Object type) {
return type == TraceModuleAdapter.class;
}
Module getModule() {
return fModule;
}
}
}