package com.sap.runlet.interpreter.expressions; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import behavioral.actions.Statement; import com.sap.runlet.abstractinterpreter.Interpreter; import com.sap.runlet.abstractinterpreter.objects.ClassTypedObject; import com.sap.runlet.abstractinterpreter.objects.MultiValuedObject; import com.sap.runlet.abstractinterpreter.objects.RunletObject; import com.sap.runlet.interpreter.RunletInterpreter; import com.sap.runlet.interpreter.RunletStackFrame; import com.sap.runlet.interpreter.objects.ValueObject; import data.classes.Association; import data.classes.AssociationEnd; import data.classes.ClassTypeDefinition; import data.classes.NativeImpl; import data.classes.SapClass; import data.classes.SignatureImplementation; import data.classes.TypeDefinition; import dataaccess.expressions.Expression; import dataaccess.expressions.NavigationStep; import dataaccess.expressions.Replace; public class ReplaceInterpreter implements Interpreter<Replace, SapClass, TypeDefinition, ClassTypeDefinition, Association, AssociationEnd, Statement, Expression, SignatureImplementation, RunletStackFrame, NativeImpl, RunletInterpreter> { private Replace replace; public ReplaceInterpreter(Replace replace) { this.replace = replace; } @Override public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluate(RunletInterpreter interpreter) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> ro = interpreter.evaluate(replace.getObject()); if (ro instanceof ValueObject) { // not a multi-object ValueObject vo = (ValueObject) interpreter.evaluate(replace.getObject()); int step = 0; return replace(interpreter, vo, step); } else { // TODO parallelize Collection<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> resultCol = RunletObject.createCollection(replace.getType().isOrdered(), replace.getType().isUnique()); for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> voUncast : ro.flatten()) { ValueObject vo = (ValueObject) voUncast; int step = 0; resultCol.add(replace(interpreter, vo, step)); } return new MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>(replace.getType(), resultCol, replace.getType().isOrdered(), replace.getType().isUnique()); } } private ValueObject replace(RunletInterpreter interpreter, ValueObject vo, int step) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Collection<AssociationEnd> equalityRelevantEnds = vo.getType().getClazz() .getEqualityRelevantAssociationEnds(); Map<AssociationEnd, Collection<ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>> propertyValues = new HashMap<AssociationEnd, Collection<ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>>(); // now fill this map with the objects at all equality-relevant association end except // for the one named in the first step of the replace expression NavigationStep nextStep = replace.getSteps().get(step); AssociationEnd stepEnd = nextStep.getTo(); for (AssociationEnd ae:equalityRelevantEnds) { AssociationEnd otherEnd = ae.otherEnd(); if (!otherEnd.equals(stepEnd)) { // copy value from original object to map for copy Collection<ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> values = RunletObject.createCollection(otherEnd.getType() .isOrdered(), otherEnd.getType().isUnique()); for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> value : interpreter.navigate(vo, otherEnd).flatten()) { ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> propertyValue = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) value; values.add(propertyValue); } propertyValues.put(otherEnd, values); } } Collection<ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> valuesForStep = RunletObject.createCollection(stepEnd .getType().isOrdered(), stepEnd.getType().isUnique()); if (step < replace.getSteps().size() - 1) { // now recurse for the values for the end identified by stepEnd for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> stepResult : interpreter.navigate(vo, stepEnd).flatten()) { valuesForStep.add(replace(interpreter, (ValueObject) stepResult, step + 1)); } } else { // last step: replace with "with" expression ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> replacement = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) interpreter.convert( interpreter.evaluate(replace.getWith()), stepEnd.getType()); valuesForStep.add(replacement); } propertyValues.put(stepEnd, valuesForStep); ValueObject result = interpreter.createValueObject(vo.getType(), propertyValues); interpreter.loadEqualityRelevantLinksOfValue(result); return result; } }