blob: e593fede42f098c8ab1c40fc46567533fc2111da [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2019 Willink Transformations 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:
* R.Dvorak and others - QVTo debugger framework
* E.D.Willink - revised API for OCL debugger framework
*******************************************************************************/
package org.eclipse.ocl.examples.debug.vm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.debug.vm.data.VMTypeData;
import org.eclipse.ocl.examples.debug.vm.data.VMValueData;
import org.eclipse.ocl.examples.debug.vm.data.VMVariableData;
import org.eclipse.ocl.examples.debug.vm.evaluator.VMEvaluationEnvironment;
import org.eclipse.ocl.examples.debug.vm.request.VMVariableRequest;
import org.eclipse.ocl.examples.debug.vm.response.VMResponse;
import org.eclipse.ocl.examples.debug.vm.response.VMVariableResponse;
import org.eclipse.ocl.examples.debug.vm.utils.VMRuntimeException;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VoidType;
import org.eclipse.ocl.pivot.evaluation.EvaluationEnvironment;
import org.eclipse.ocl.pivot.internal.ecore.es2as.Ecore2AS;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.LabelUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.PivotConstants;
import org.eclipse.ocl.pivot.utilities.StringUtil;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
import org.eclipse.ocl.pivot.values.CollectionValue;
import org.eclipse.ocl.pivot.values.InvalidValueException;
import org.eclipse.ocl.pivot.values.Value;
public class VariableFinder
{
public static final @NonNull String CONTAINER_VARIABLE_NAME = "$container";
/** @deprecated use non-static method */
@Deprecated
public static @Nullable String computeDetail(@NonNull URI variableURI, @NonNull VMEvaluationEnvironment fEvalEnv) {
return newInstance(fEvalEnv, true).computeDetail(variableURI);
}
public static @NonNull URI createURI(@NonNull String @NonNull [] varPath) {
return createURI(varPath, varPath.length - 1);
}
public static @NonNull URI createURI(@NonNull String @NonNull [] varPath, int endIndex) {
String[] segments = new String[endIndex + 1];
for (int i = 0; i < segments.length; i++) {
segments[i] = URI.encodeSegment(varPath[i], true);
}
@SuppressWarnings("null") @NonNull URI hierarchicalURI = URI.createHierarchicalURI(segments, null, null);
return hierarchicalURI;
}
public static @NonNull List<EStructuralFeature> getAllFeatures(@NonNull EClass eClass) {
List<EStructuralFeature> features = new ArrayList<EStructuralFeature>();
features.addAll(eClass.getEAllStructuralFeatures());
/* if (eClass instanceof Root) {
for (Iterator<EStructuralFeature> it = features.iterator(); it.hasNext();) {
EStructuralFeature feature = it.next();
if(feature instanceof ContextualProperty) {
it.remove();
}
}
}
collectIntermediateProperties(features, eClass); */
Collections.sort(features, new Comparator<EStructuralFeature>() {
@Override
public int compare(EStructuralFeature var1, EStructuralFeature var2) {
String n1 = var1.getName();
String n2 = var2.getName();
if (n1 == null) n1 = "";
if (n2 == null) n2 = "";
return n1.compareTo(n2);
}
});
return features;
}
private static @NonNull String getOCLType(@NonNull ETypedElement feature) {
boolean isNullFree = Ecore2AS.isNullFree(feature);
return getOCLType(feature.getEType(), feature.isUnique(), feature.isOrdered(), isNullFree, feature.getLowerBound(), feature.getUpperBound());
}
private static @NonNull String getOCLType(@Nullable EClassifier eType, boolean isUnique, boolean isOrdered, boolean isNullFree, int lowerBound, int upperBound) {
StringBuilder s = new StringBuilder();
if (eType == null) {
s.append("null");
}
else if (upperBound != 1) {
if (isUnique) {
s.append(isOrdered ? "OrderedSet" : "Set");
}
else {
s.append(isOrdered ? "Sequence" : "Bag");
}
s.append("(");
s.append(eType.getName());
StringUtil.appendMultiplicity(s, lowerBound, upperBound, isNullFree);
s.append(")");
}
else {
s.append(eType.getName());
}
return s.toString();
}
public static String getRootVarName(URI variableURI) {
if (variableURI.segmentCount() == 0) {
throw new IllegalArgumentException();
}
return URI.decode(variableURI.segment(0));
}
public static @NonNull List<VMVariableData> getVariables(@NonNull VMEvaluationEnvironment evalEnv) {
return newInstance(evalEnv, false).getVariables();
}
private static boolean isPredefinedVar(String name, @NonNull VMEvaluationEnvironment evalEnv) {
if((PivotConstants.SELF_NAME.equals(name) || PivotConstants.RESULT_NAME.equals(name)) && evalEnv.getOperation() != null) {
return true;
}
return "this".equals(name);
}
public static @NonNull String @NonNull [] getVariablePath(@NonNull URI variableURI) {
@NonNull String @NonNull [] ids = new @NonNull String[variableURI.segmentCount()];
for (int i = 0; i < ids.length; i++) {
ids[i] = String.valueOf(URI.decode(variableURI.segment(i)));
}
return ids;
}
public static @NonNull VariableFinder newInstance(@NonNull VMEvaluationEnvironment vmEvaluationEnvironment, boolean isStoreValues) {
return vmEvaluationEnvironment.createVariableFinder(isStoreValues);
}
public static @NonNull URI parseURI(String variableURI) throws IllegalArgumentException {
return URI.createURI(variableURI);
}
/** @deprecated use non-static method */
@Deprecated
public static VMResponse process(@NonNull VMVariableRequest request, @NonNull List<UnitLocation> stack, @NonNull VMEvaluationEnvironment vmEvaluationEnvironment) {
return newInstance(vmEvaluationEnvironment, true).process(request, stack);
}
private static EClass selectEClass(EClass eClass, int index) {
if(index > 0) {
EList<EClass> superClasses = eClass.getEAllSuperTypes();
if(index < superClasses.size()) {
return superClasses.get(index);
}
}
return eClass;
}
/** @deprecated use non-static method */
@Deprecated
public static void setValueAndType(@NonNull VMVariableData variable, @Nullable Object value, @Nullable Type optDeclaredType, @NonNull EvaluationEnvironment evalEnv) {
String declaredTypeName = (optDeclaredType != null) ? optDeclaredType.toString() : null;
setValueAndType(variable, value, declaredTypeName, evalEnv);
}
/** @deprecated use non-static method */
@Deprecated
public static void setValueAndType(@NonNull VMVariableData variable, @Nullable Object value, @Nullable EClassifier optDeclaredType, @NonNull EvaluationEnvironment evalEnv) {
String declaredTypeName = (optDeclaredType != null) ? optDeclaredType.getName() : null;
setValueAndType(variable, value, declaredTypeName, evalEnv);
}
/** @deprecated use non-static method */
@Deprecated
public static void setValueAndType(@NonNull VMVariableData variable, @Nullable Object value, @Nullable String declaredTypeName, @NonNull EvaluationEnvironment evalEnv) {
VMValueData vmValue;
VMTypeData vmType;
if (value == null) {
vmType = new VMTypeData(VMTypeData.DATATYPE, "OclVoid", declaredTypeName); //$NON-NLS-1$
vmValue = null;
} else if (value instanceof InvalidValueException) {
vmValue = new VMValueData(VMValueData.INVALID, "invalid - " + ((InvalidValueException)value).getMessage());
vmType = new VMTypeData(VMTypeData.DATATYPE, "OclInvalid", declaredTypeName); //$NON-NLS-1$
} else if (value instanceof Resource) {
Resource resource = (Resource) value;
// EClass eClass = eObject.eClass();
@NonNull String strVal = String.valueOf(resource.getURI());
vmValue = new VMValueData(VMValueData.RESOURCE, strVal, true);
@NonNull String className = resource.getClass().getSimpleName();
vmType = new VMTypeData(VMTypeData.EOBJECT, className, declaredTypeName);
} else if (value instanceof EObject) {
EObject eObject = (EObject) value;
EClass eClass = eObject.eClass();
String qualifiedName = eClass != null ? eClass.getEPackage().getName() + "::" + eClass.getName() : eObject.getClass().getSimpleName();
String strVal = qualifiedName + " @" + Integer.toHexString(System.identityHashCode(value));
boolean hasVariables = (eClass == null) || !eClass.getEAllStructuralFeatures().isEmpty() || value instanceof Resource;
vmValue = new VMValueData(VMValueData.OBJECT_REF, strVal, hasVariables);
@SuppressWarnings("null")@NonNull String className = eClass != null ? eClass.getName() : eObject.getClass().getSimpleName();
vmType = new VMTypeData(VMTypeData.EOBJECT, className, declaredTypeName);
} else if (value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) value;
Class<?> javaType = value.getClass();
StringBuilder strVal = new StringBuilder();
if (declaredTypeName != null) {
strVal.append(declaredTypeName);
} else {
strVal.append(javaType.getSimpleName());
}
strVal.append('[').append(collection.size()).append(']');
String string = strVal.toString();
vmValue = new VMValueData(VMValueData.COLLECTION_REF, string, !collection.isEmpty());
// TODO - use mapping by runtime class to OCL type
@NonNull String className = javaType.getSimpleName();
vmType = new VMTypeData(VMTypeData.COLLECTION, className, declaredTypeName);
} else if (value instanceof CollectionValue) {
CollectionValue collection = (CollectionValue) value;
Class<?> javaType = value.getClass();
StringBuilder strVal = new StringBuilder();
if (declaredTypeName != null) {
strVal.append(declaredTypeName);
} else {
strVal.append(javaType.getSimpleName());
}
strVal.append('[').append(collection.size()).append(']');
String string = strVal.toString();
vmValue = new VMValueData(VMValueData.COLLECTION_REF, string, !collection.isEmpty());
// TODO - use mapping by runtime class to OCL type
@NonNull String className = javaType.getSimpleName();
vmType = new VMTypeData(VMTypeData.COLLECTION, className, declaredTypeName);
} else {
// everything else we see as a data type
@NonNull String valueOf = String.valueOf(value);
if (value.getClass().equals(String.class)) {
valueOf = "'" + valueOf + "'";
}
vmValue = new VMValueData(VMValueData.PRIMITIVE, valueOf);
@NonNull String className = value.getClass().getSimpleName();
vmType = new VMTypeData(VMTypeData.DATATYPE, className, declaredTypeName);
}
variable.type = vmType;
variable.value = vmValue;
}
protected final @NonNull VMEvaluationEnvironment fEvalEnv;
protected final boolean fIsStoreValues;
private @Nullable VMVariableData fTargetVar; // FIXME Redundant
private @Nullable String fRootDeclaredType; // FIXME Redundant
public VariableFinder(@NonNull VMEvaluationEnvironment fEvalEnv, boolean isStoreValues) {
this.fEvalEnv = fEvalEnv;
fIsStoreValues = isStoreValues;
}
public void collectChildVars(Object root, @NonNull String @NonNull [] parentPath, @Nullable String containerType, @NonNull List<@NonNull VMVariableData> result) {
@NonNull String childPath @NonNull [] = new @NonNull String[parentPath.length + 1];
System.arraycopy(parentPath, 0, childPath, 0, parentPath.length);
if (root instanceof Resource) {
Resource model = (Resource) root;
root = model.getContents();
containerType = "Set(EObject)";
}
if (root instanceof EObject) {
EObject eObject = (EObject) root;
@SuppressWarnings("null")@NonNull EClass eClass = eObject.eClass();
StringBuilder uriBuf = new StringBuilder();
List<EStructuralFeature> eAllFeatures = getAllFeatures(eClass);
List<EClass> superClasses = eClass.getEAllSuperTypes();
for (EStructuralFeature feature : eAllFeatures) {
EClass owner;
// if(feature.eClass() == ExpressionsPackage.eINSTANCE.getContextualProperty()) {
// ContextualProperty ctxProperty = (ContextualProperty) feature;
// owner = ctxProperty.getContext();
// uriBuf.append('+');//.append(intermPropIndex++);
// } else {
owner = feature.getEContainingClass();
// }
int index = superClasses.indexOf(owner);
uriBuf.append(index < 0 ? 0 : index);
uriBuf.append('.').append(feature.getName());
childPath[childPath.length - 1] = String.valueOf(uriBuf);
VMVariableData elementVar = createFeatureVar(feature, getValue(feature, eObject), createURI(childPath).toString());
result.add(elementVar);
uriBuf.setLength(0);
}
childPath[childPath.length - 1] = CONTAINER_VARIABLE_NAME;
Object value = eObject.eContainer();
if (value == null) {
value = eObject.eResource();
}
VMVariableData elementVar = createContainerVariable(eObject.eContainer(), createURI(childPath));
result.add(elementVar);
} else if(root instanceof Collection<?>) {
Collection<?> elements = (Collection<?>) root;
String elementType = "?";//"(containerType instanceof CollectionType) ? ((CollectionType) containerType) .getElementType() : fFeatureAccessor.getStandardLibrary().getOclAny()";
// Dictionary<Object, Object> asDictionary = null;
// if(root instanceof Dictionary<?, ?>) {
// @SuppressWarnings("unchecked")
// Dictionary<Object, Object> dict = (Dictionary<Object, Object>) root;
// asDictionary = dict;
// elements = asDictionary.keys();
// }
int i = 0;
for (Object element : elements) {
childPath[childPath.length - 1] = String.valueOf(i);
VMVariableData elementVar;
// if(asDictionary == null) {
elementVar = createCollectionElementVar(i, element, elementType, createURI(childPath).toString());
// } else {
// Object key = element;
// Object value = asDictionary.get(element);
// elementVar = createDictionaryElementVar(key, value, elementType, createURI(childPath).toString());
// }
result.add(elementVar);
i++;
}
} else if(root instanceof CollectionValue) {
CollectionValue elements = (CollectionValue) root;
String elementType = "(containerType instanceof CollectionType) ? ((CollectionType) containerType) .getElementType() : fFeatureAccessor.getStandardLibrary().getOclAny()";
// Dictionary<Object, Object> asDictionary = null;
// if(root instanceof Dictionary<?, ?>) {
// @SuppressWarnings("unchecked")
// Dictionary<Object, Object> dict = (Dictionary<Object, Object>) root;
// asDictionary = dict;
// elements = asDictionary.keys();
// }
int i = 0;
for (Object element : elements) {
childPath[childPath.length - 1] = String.valueOf(i);
VMVariableData elementVar;
// if(asDictionary == null) {
elementVar = createCollectionElementVar(i, element, elementType, createURI(childPath).toString());
// } else {
// Object key = element;
// Object value = asDictionary.get(element);
// elementVar = createDictionaryElementVar(key, value, elementType, createURI(childPath).toString());
// }
result.add(elementVar);
i++;
}
}
}
public @Nullable String computeDetail(@NonNull URI variableURI) {
@NonNull String @NonNull [] variablePath = getVariablePath(variableURI);
Object valueObject = findStackObject(variablePath);
try {
return LabelUtil.getLabel(valueObject);
} catch(RuntimeException e) {
// do nothing, empty detail will be returned
}
return null;
}
private @NonNull VMVariableData createCollectionElementVar(int elementIndex, Object element, @Nullable String elementType, String uri) {
String varName = "[" + elementIndex + "]"; //$NON-NLS-1$ //$NON-NLS-2$
int kind = VMVariableData.COLLECTION_ELEMENT;
return createVariable(varName, kind, elementType, element, uri);
}
protected @NonNull VMVariableData createContainerVariable(Object value, @NonNull URI uri) {
String oclType = getOCLType(ClassUtil.nonNullModel(EcorePackage.Literals.EOBJECT___ECONTAINER));
return createVariable(CONTAINER_VARIABLE_NAME, VMVariableData.REFERENCE, oclType, value, uri.toString());
}
/* private VMVariable createDictionaryElementVar(Object key, Object value, @Nullable String elementType, String uri) {
String varName = String.valueOf(key);
int kind = VMVariable.COLLECTION_ELEMENT;
return createVariable(varName, kind, elementType, value, uri);
} */
private @NonNull VMVariableData createFeatureVar(@NonNull EStructuralFeature feature, Object value, String uri) {
String varName = ClassUtil.nonNullModel(feature.getName());
String declaredType = getOCLType(feature);
int kind = VMVariableData.ATTRIBUTE;
if (feature instanceof EReference) {
kind = VMVariableData.REFERENCE;
}
// if (feature instanceof ContextualProperty) {
// kind = VMVariable.INTERM_PROPERTY;
// }
return createVariable(varName, kind, declaredType, value, uri);
}
private @NonNull VMVariableData createVariable(@NonNull String varName, int kind, @Nullable String declaredType, Object varObj, String uri) {
VMVariableData result = new VMVariableData(varName, uri);
result.kind = kind;
setValueAndType(result, varObj, declaredType);
if (fIsStoreValues) {
result.valueObject = varObj;
}
return result;
}
public void find(@NonNull String @NonNull [] objectPath, boolean fetchChildVariables, @NonNull List<@NonNull VMVariableData> result) {
if (result.contains(null)) {
throw new IllegalArgumentException("null result variables"); //$NON-NLS-1$
}
try {
Object referencedObj = findStackObject(objectPath);
VMVariableData variable = fTargetVar;
if (variable != null) {
result.add(variable);
if (fetchChildVariables) {
collectChildVars(referencedObj, objectPath, fRootDeclaredType, result);
}
}
} finally {
fTargetVar = null;
}
}
protected Object findChildObject(Object parentObj, @Nullable String optParentDeclaredType, @NonNull String @NonNull [] varTreePath, int pathIndex) {
URI uri = createURI(varTreePath, pathIndex);
// FIXME - deduce the type from actual type, ensure null is not propagated
VMVariableData childVar = null;
Object nextObject = null;
String nextDeclaredType = null;
if (parentObj instanceof Resource) {
parentObj = ((Resource)parentObj).getContents();
nextDeclaredType = "EObject"; //"QvtOperationalStdLibrary.INSTANCE.getElementType()";
}
if (parentObj instanceof EObject) {
String indexedPath = varTreePath[pathIndex];
if (CONTAINER_VARIABLE_NAME.equals(indexedPath)) {
Object value = ((EObject)parentObj).eContainer();
if (value == null) {
value = ((EObject)parentObj).eResource();
}
childVar = createContainerVariable(value, uri);
nextObject = value;
nextDeclaredType = getOCLType(ClassUtil.nonNullModel(EcorePackage.Literals.EOBJECT___ECONTAINER));
}
else {
EObject eObject = (EObject) parentObj;
EStructuralFeature eFeature = findFeature(ClassUtil.nonNullState(indexedPath), eObject.eClass());
if (eFeature != null) {
Object value = getValue(eFeature, eObject);
childVar = createFeatureVar(eFeature, value, uri.toString());
nextObject = value;
nextDeclaredType = getOCLType(eFeature);
}
}
} else if (parentObj instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) parentObj;
int elementIndex = -1;
try {
elementIndex = Integer.parseInt(varTreePath[pathIndex]);
} catch(NumberFormatException e) {
// FIXME
throw new IllegalArgumentException();
}
if (elementIndex < 0 || elementIndex >= collection.size()) {
// not valid element position in this collection
throw new IllegalArgumentException();
}
// if (optParentDeclaredType instanceof CollectionType) {
// CollectionType type = (CollectionType) optParentDeclaredType;
// nextDeclaredType = "type.getElementType()";
// } else if(nextDeclaredType == null) {
// FIXME
nextDeclaredType = "OclAny";
// }
Object element = getElement(collection, elementIndex);
childVar = createCollectionElementVar(elementIndex, element, nextDeclaredType, uri.toString());
nextObject = element;
} else if (parentObj instanceof CollectionValue) {
CollectionValue collection = (CollectionValue) parentObj;
int elementIndex = -1;
try {
elementIndex = Integer.parseInt(varTreePath[pathIndex]);
} catch(NumberFormatException e) {
// FIXME
throw new IllegalArgumentException();
}
if (elementIndex < 0 || elementIndex >= collection.intSize()) {
// not valid element position in this collection
throw new IllegalArgumentException();
}
// if (optParentDeclaredType instanceof CollectionType) {
// CollectionType type = (CollectionType) optParentDeclaredType;
// nextDeclaredType = "type.getElementType()";
// } else if(nextDeclaredType == null) {
// FIXME
nextDeclaredType = "OclAny";
// }
Object element = getElement(collection.getElements(), elementIndex);
childVar = createCollectionElementVar(elementIndex, element, nextDeclaredType, uri.toString());
nextObject = element;
}
int nextIndex = pathIndex + 1;
if (nextIndex < varTreePath.length) {
if (nextObject != null) {
// continue navigation in the hierarchy
return findChildObject(nextObject, nextDeclaredType, varTreePath, nextIndex);
} else {
// we can't navigate further via the path due to <null> termination object
return null;
}
}
this.fTargetVar = childVar;
return nextObject;
}
private @Nullable Object findStackObject(@NonNull String @NonNull [] varTreePath) {
Object rootObj = null;
boolean gotIt = false;
String envVarName = ClassUtil.nonNullState(varTreePath[0]);
if (envVarName.startsWith("$")) {
Object pcObject = fEvalEnv.getValueOf(fEvalEnv.getPCVariable());
for (VMEvaluationEnvironment evalEnv = fEvalEnv; evalEnv != null; evalEnv = evalEnv.getVMParentEvaluationEnvironment()) {
for (TypedElement localVariable : evalEnv.getVariables()) {
if (localVariable instanceof OCLExpression) {
OCLExpression oclExpression = (OCLExpression) localVariable;
if (oclExpression.eContainer() == pcObject) {
String varName = getTermVariableName(oclExpression);
if (envVarName.equals(varName)) {
rootObj = fEvalEnv.getValueOf(localVariable);
gotIt = true;
break;
}
}
}
}
if (gotIt) {
break;
}
}
}
if (!gotIt) {
Set<TypedElement> variables = new HashSet<TypedElement>();
for (VMEvaluationEnvironment evalEnv = fEvalEnv; evalEnv != null; evalEnv = evalEnv.getVMParentEvaluationEnvironment()) {
Set<TypedElement> localVariables = evalEnv.getVariables();
variables.addAll(localVariables);
if (NameUtil.getNameable(localVariables, PivotConstants.SELF_NAME) != null) {
break;
}
}
rootObj = NameUtil.getNameable(variables, envVarName);
if (rootObj instanceof Variable) {
rootObj = fEvalEnv.getValueOf((TypedElement)rootObj);
gotIt = true;
}
}
fRootDeclaredType = getDeclaredType(rootObj);
if(rootObj != null && varTreePath.length == 1) {
// refers to environment variable only
@NonNull String @NonNull [] uri = new @NonNull String @NonNull [] { envVarName };
fTargetVar = createVariable(envVarName, VMVariableData.LOCAL, fRootDeclaredType, rootObj, createURI(uri).toString());
return rootObj;
}
if(rootObj == null) {
// can't navigate further via <null> object
return null;
}
// navigate from the root object using the remaining variable path
return findChildObject(rootObj, fRootDeclaredType, varTreePath, 1);
}
protected String getDeclaredType(Object valueObject) {
if (valueObject instanceof EObject) {
return ((EObject)valueObject).eClass().getName();
}
else if (valueObject instanceof Value) {
return ((Value)valueObject).getTypeId().toString();
}
else {
return "evalEnv.getTypeOf(envVarName)"; // FIXME
}
}
private @Nullable Object getElement(@NonNull Collection<?> collection, int index) {
if (collection instanceof EList<?>) {
EList<?> eList = (EList<?>) collection;
return eList.get(index);
}
int curr = 0;
for (Iterator<?> it = collection.iterator(); it.hasNext();) {
Object object = it.next();
if (curr++ == index) {
return object;
}
}
return null;
}
private @Nullable EStructuralFeature findFeature(@NonNull String featureRef, EClass actualTarget) {
String actualRef = featureRef.startsWith("+") ? featureRef.substring(1) : featureRef;
boolean isIntermediate = featureRef.length() != actualRef.length();
int classIndex;
String featureName;
try {
int delimiterPos = actualRef.indexOf('.');
if(delimiterPos <= 0 || delimiterPos >= actualRef.length() - 1) {
throw new IllegalArgumentException("navigation feature: " + actualRef);
}
classIndex = Integer.parseInt(actualRef.substring(0, delimiterPos));
featureName = actualRef.substring(delimiterPos + 1);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Illegal feature reference: " + featureRef);
}
EClass featureOwner = selectEClass(actualTarget, classIndex);
if(featureOwner == null) {
return null;
}
if(!isIntermediate) {
return featureOwner.getEStructuralFeature(featureName);
}
// EClass contextualPropMetaClass = ExpressionsPackage.eINSTANCE.getContextualProperty();
// for (EStructuralFeature feature : actualTarget.getEAllStructuralFeatures()) {
// if(feature.eClass() == contextualPropMetaClass && feature.equals(feature.getName())) {
// return feature;
// }
// }
return null;
}
protected static String getTermVariableName(@NonNull OCLExpression oclExpression) {
EStructuralFeature eContainingFeature = oclExpression.eContainingFeature();
if (eContainingFeature == null) {
return null;
}
String varName;
varName = "$" + eContainingFeature.getName();
if (eContainingFeature.isMany()) {
EObject eContainer = oclExpression.eContainer();
if (eContainer != null) {
Object eGet = eContainer.eGet(eContainingFeature);
if (eGet instanceof List<?>) {
int index = ((List<?>)eGet).indexOf(oclExpression);
varName = varName + "[" + index + "]";
}
}
}
return varName;
}
public Object getValue(EStructuralFeature feature, EObject target) {
return /*fEvalEnv*/navigateProperty(feature, null, target);
// throw new UnsupportedOperationException();
}
protected @Nullable VMVariableData getVariable(@NonNull TypedElement variable, @Nullable Object pcObject) {
String varName = variable.getName();
if (variable instanceof OCLExpression) {
OCLExpression oclExpression = (OCLExpression) variable;
if (oclExpression.eContainer() == pcObject) {
varName = getTermVariableName(oclExpression);
if (varName != null) {
VMVariableData var = new VMVariableData(varName, null);
var.kind = VMVariableData.LOCAL;
Object value = null;
try {
value = fEvalEnv.getValueOf(oclExpression);
var.valueObject = value;
}
catch (Throwable e) {
value = e;
}
Type declaredType = oclExpression.getType();
setValueAndType(var, value, declaredType);
return var;
}
}
}
else if (varName != null) {
VMVariableData var = new VMVariableData(varName, null);
if (isPredefinedVar(varName, fEvalEnv)) {
var.kind = VMVariableData.PREDEFINED_VAR;
}
Object value = null;
try {
value = fEvalEnv.getValueOf(variable);
var.valueObject = value;
}
catch (Throwable e) {
value = e;
}
Type declaredType = variable.getType();
setValueAndType(var, value, declaredType);
return var;
}
return null;
}
public @NonNull List<VMVariableData> getVariables() {
List<VMVariableData> result = new ArrayList<VMVariableData>();
Object pcObject = fEvalEnv.getValueOf(fEvalEnv.getPCVariable());
for (TypedElement variable : fEvalEnv.getVariables()) {
if (variable != null) {
VMVariableData var = getVariable(variable, pcObject);
if (var != null) {
result.add(var);
}
}
}
return result;
}
// @Override
public Object navigateProperty(EStructuralFeature property, List<?> qualifiers, Object target) throws IllegalArgumentException {
/* if(target instanceof ModuleInstance) {
ModuleInstance moduleTarget = (ModuleInstance) target;
EClassifier owningClassifier = QvtOperationalStdLibrary.INSTANCE.getEnvironment().getUMLReflection().getOwningClassifier(property);
if (owningClassifier instanceof Module) {
target = moduleTarget.getThisInstanceOf((Module) owningClassifier);
}
else {
target = moduleTarget.getThisInstanceOf(moduleTarget.getModule());
}
} */
EStructuralFeature resolvedProperty = property;
// if (property instanceof ContextualProperty) {
// IntermediatePropertyModelAdapter.ShadowEntry shadow = IntermediatePropertyModelAdapter.getPropertyHolder(
// property.getEContainingClass(), (ContextualProperty)property, target);
// target = shadow.getPropertyRuntimeOwner(target, this);
// resolvedProperty = shadow.getProperty();
// }
// FIXME - workaround for a issue of multiple typle type instances, possibly coming from
// imported modules. The super impl. looks for the property by feature instance, do it
// by name here to avoid lookup failure, IllegalArgExc...
/* if(target instanceof Tuple<?, ?>) {
if (target instanceof EObject) {
EObject etarget = (EObject) target;
resolvedProperty = etarget.eClass().getEStructuralFeature(property.getName());
if(resolvedProperty == null) {
return null;
}
}
else {
resolvedProperty = null;
for (EStructuralFeature feature : ((Tuple<EOperation, EStructuralFeature>) target).getTupleType().oclProperties()) {
if (property.getName().equals(feature.getName())) {
resolvedProperty = feature;
break;
}
}
if(resolvedProperty == null) {
return null;
}
}
}
else if(property.getEType() instanceof CollectionType<?, ?> && target instanceof EObject) {
// module property of direct OCL collection type => override the super impl which coerce the result value
// and takes only the first element and returns from navigate call
EObject eTarget = (EObject) target;
if (eTarget.eClass().getEAllStructuralFeatures().contains(resolvedProperty)) {
return eTarget.eGet(resolvedProperty, true);
}
} */
try {
return superNavigateProperty(resolvedProperty, qualifiers, target);
}
catch (IllegalArgumentException e) {
fEvalEnv.throwVMException(new VMRuntimeException("Unknown property '" + property.getName() + "'", e)); //$NON-NLS-1$ //$NON-NLS-2$
return ValueUtil.INVALID_VALUE; //getInvalidResult();
}
}
public @Nullable VMResponse process(@NonNull VMVariableRequest request, @NonNull List<UnitLocation> stack) {
UnitLocation location = VMVirtualMachine.lookupEnvironmentByID(request.frameID, stack);
if (location == null) {
return VMResponse.createERROR();
}
String variableURIStr = request.variableURI;
URI variableURI = parseURI(variableURIStr);
@NonNull String @NonNull [] variablePath = getVariablePath(variableURI);
List<@NonNull VMVariableData> variables = new ArrayList<@NonNull VMVariableData>();
find(variablePath, request.includeChildVars, variables);
if (variables.isEmpty()) {
return VMResponse.createERROR();
}
@NonNull VMVariableData @Nullable [] children = null;
int size = variables.size();
if (size > 1) {
children = variables.subList(1, size).toArray(new @NonNull VMVariableData @NonNull [size - 1]);
}
VMVariableData variable0 = variables.get(0);
return variable0 != null ? new VMVariableResponse(variable0, children) : null;
}
public void setValueAndType(@NonNull VMVariableData variable, @Nullable Object value, @Nullable Type optDeclaredType) {
String declaredTypeName = (optDeclaredType != null) ? optDeclaredType.toString() : null;
setValueAndType(variable, value, declaredTypeName);
}
public void setValueAndType(@NonNull VMVariableData variable, @Nullable Object value, @Nullable String declaredTypeName) {
VMValueData vmValue;
VMTypeData vmType;
if (value == null) {
vmType = new VMTypeData(VMTypeData.DATATYPE, "OclVoid", declaredTypeName); //$NON-NLS-1$
vmValue = null;
} else if (value instanceof InvalidValueException) {
vmValue = new VMValueData(VMValueData.INVALID, "invalid - " + ((InvalidValueException)value).getMessage());
vmType = new VMTypeData(VMTypeData.DATATYPE, "OclInvalid", declaredTypeName); //$NON-NLS-1$
} else if (value instanceof Resource) {
Resource resource = (Resource) value;
// EClass eClass = eObject.eClass();
@NonNull String strVal = String.valueOf(resource.getURI());
vmValue = new VMValueData(VMValueData.RESOURCE, strVal, true);
@NonNull String className = resource.getClass().getSimpleName();
vmType = new VMTypeData(VMTypeData.EOBJECT, className, declaredTypeName);
} else if (value instanceof EObject) {
EObject eObject = (EObject) value;
EClass eClass = eObject.eClass();
String qualifiedName = eClass != null ? eClass.getEPackage().getName() + "::" + eClass.getName() : eObject.getClass().getSimpleName();
String strVal = qualifiedName + " @" + Integer.toHexString(System.identityHashCode(value));
boolean hasVariables = (eClass == null) || !eClass.getEAllStructuralFeatures().isEmpty() || value instanceof Resource;
vmValue = new VMValueData(VMValueData.OBJECT_REF, strVal, hasVariables);
@SuppressWarnings("null")@NonNull String className = eClass != null ? eClass.getName() : eObject.getClass().getSimpleName();
vmType = new VMTypeData(VMTypeData.EOBJECT, className, declaredTypeName);
} else if (value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) value;
Class<?> javaType = value.getClass();
StringBuilder strVal = new StringBuilder();
if (declaredTypeName != null) {
strVal.append(declaredTypeName);
} else {
strVal.append(javaType.getSimpleName());
}
strVal.append('[').append(collection.size()).append(']');
String string = strVal.toString();
vmValue = new VMValueData(VMValueData.COLLECTION_REF, string, !collection.isEmpty());
// TODO - use mapping by runtime class to OCL type
@NonNull String className = javaType.getSimpleName();
vmType = new VMTypeData(VMTypeData.COLLECTION, className, declaredTypeName);
} else if (value instanceof CollectionValue) {
CollectionValue collection = (CollectionValue) value;
Class<?> javaType = value.getClass();
StringBuilder strVal = new StringBuilder();
if (declaredTypeName != null) {
strVal.append(declaredTypeName);
} else {
strVal.append(javaType.getSimpleName());
}
strVal.append('[').append(collection.size()).append(']');
String string = strVal.toString();
vmValue = new VMValueData(VMValueData.COLLECTION_REF, string, !collection.isEmpty());
// TODO - use mapping by runtime class to OCL type
@NonNull String className = javaType.getSimpleName();
vmType = new VMTypeData(VMTypeData.COLLECTION, className, declaredTypeName);
} else {
// everything else we see as a data type
@NonNull String valueOf = String.valueOf(value);
if (value.getClass().equals(String.class)) {
valueOf = "'" + valueOf + "'";
}
vmValue = new VMValueData(VMValueData.PRIMITIVE, valueOf);
@NonNull String className = value.getClass().getSimpleName();
vmType = new VMTypeData(VMTypeData.DATATYPE, className, declaredTypeName);
}
variable.type = vmType;
variable.value = vmValue;
}
// implements the inherited specification
public Object superNavigateProperty(EStructuralFeature property,
List<?> qualifiers, Object target)
throws IllegalArgumentException {
if (target instanceof EObject) {
EObject etarget = (EObject) target;
if (etarget.eClass().getEAllStructuralFeatures().contains(property)) {
if (property.getEType() instanceof VoidType) {
// then the only instance is null; using eGet would
// cause a ClassCastException because VoidTypeImpl
// is neither an EClass nor an EDataType.
return null;
}
return /*coerceValue(property,*/ etarget.eGet(property)/*, true)*/;
}
} /*else if (target instanceof Tuple<?, ?>) {
@SuppressWarnings("unchecked")
Tuple<EOperation, EStructuralFeature> tuple = (Tuple<EOperation, EStructuralFeature>) target;
if (tuple.getTupleType().oclProperties().contains(property)) {
return tuple.getValue(property);
}
} */
throw new IllegalArgumentException();
}
}