package simulator; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.Position; import models.algebra.Term; import models.algebra.UnificationFailed; import models.algebra.Variable; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; public class Event { private DataTransferChannel channel; private Expression message; private boolean isInput = false; private ResourcePath inputResourcePath = null; private Resource inputResource = null; private List<Map.Entry<Selector, Constant>> channelSelectorAndValues = new ArrayList<>(); private Map<Expression, Expression> dependingParameters = new HashMap<>(); private Set<Resource> outputResources = new HashSet<>(); private Set<Event> succEvents = new HashSet<>(); private Map<Selector, Map<ResourcePath, Integer>> channelSelectorToInputResourcePathParam = new HashMap<>(); private Map<Selector, Map<ResourcePath, Integer>> channelSelectorToOutputResourcePathParam = new HashMap<>(); private Map<Variable, Expression> selectorVariables = new HashMap<>(); public Event(DataTransferChannel channel, Expression message, ArrayList<ResourcePath> outputResPaths, Resource outputResource, Map<Variable, Constant> bindings) { this.channel = channel; this.message = message; this.isInput = true; this.outputResources.add(outputResource); Map<Selector, Constant> variableSelectors = new HashMap<>(); for(var variable : bindings.keySet()) { variableSelectors.put(new Selector(variable), bindings.get(variable)); } connectChannelSelectorAndPathParameters(variableSelectors); // Extract channel parameters from the output resource. List<Selector> channelSelectors = channel.getAllSelectors(); for(var outputResPath : outputResPaths) { for (Selector sel: channelSelectors) { Integer paramIdx = channelSelectorToOutputResourcePathParam.getOrDefault(sel, new HashMap<>()).get(outputResPath); if(paramIdx == null) { continue; } Resource ancestor = outputResource; int idx = outputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; if (idx == paramIdx) break; } ancestor = ancestor.getParent(); } if (ancestor!= null) { channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); selectorVariables.put(new Variable(sel.getExpression().toString()), ancestor.getParameter()); } } } for (Selector sel : variableSelectors.keySet()) { channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, variableSelectors.get(sel))); } } public Event(DataTransferChannel channel, Expression message, ResourcePath outputResPath, Resource outputResource) { this.channel = channel; this.message = message; this.isInput = true; this.outputResources.add(outputResource); connectChannelSelectorAndPathParameters(); // Extract channel parameters from the output resource. List<Selector> channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { int paramIdx = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); Resource ancestor = outputResource; int idx = outputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; if (idx == paramIdx) break; } ancestor = ancestor.getParent(); } if (ancestor!= null) channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); } } public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource) { this.channel = channel; this.isInput = false; this.inputResourcePath = inputResPath; this.inputResource = inputResource; connectChannelSelectorAndPathParameters(); // Extract channel parameters from the input resource. List<Selector> channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { if (inputResPath != null) { Integer paramIdx = channelSelectorToInputResourcePathParam.get(sel).get(inputResPath); if (paramIdx != null) { Resource ancestor = inputResource; int idx = inputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; if (idx == paramIdx) break; } ancestor = ancestor.getParent(); } channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); } } } } public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource, List<Constant> channelSelectorValues, Map<Expression, Expression> dependingVarToVal) { this.channel = channel; this.isInput = false; this.inputResourcePath = inputResPath; this.inputResource = inputResource; connectChannelSelectorAndPathParameters(); // Extract channel parameters from the input resource. List<Selector> channelSelectors = channel.getAllSelectors(); for (int i = 0; i < channelSelectors.size(); i++) { Selector sel = channelSelectors.get(i); channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, channelSelectorValues.get(i))); } this.dependingParameters = dependingVarToVal; } private void connectChannelSelectorAndPathParameters() { connectChannelSelectorAndPathParameters(null); } private void connectChannelSelectorAndPathParameters(Map<Selector, Constant> bindings) { List<Selector> channelSelectors = channel.getAllSelectors(); if(bindings != null) { for(var sel : bindings.keySet()) { channelSelectors.add(sel); } } for (Selector sel: channelSelectors) { for (ResourcePath resPath: channel.getInputResources()) { int paramIdx = resPath.getPathParams().indexOf(sel.getExpression()); if (paramIdx >= 0) { Map<ResourcePath, Integer> pathToIdx = channelSelectorToInputResourcePathParam.get(sel); if (pathToIdx == null) { pathToIdx = new HashMap<>(); channelSelectorToInputResourcePathParam.put(sel, pathToIdx); } pathToIdx.put(resPath, paramIdx); } } for (ResourcePath resPath: channel.getOutputResources()) { int paramIdx = resPath.getPathParams().indexOf(sel.getExpression()); if (paramIdx >= 0) { Map<ResourcePath, Integer> pathToIdx = channelSelectorToOutputResourcePathParam.get(sel); if (pathToIdx == null) { pathToIdx = new HashMap<>(); channelSelectorToOutputResourcePathParam.put(sel, pathToIdx); } pathToIdx.put(resPath, paramIdx); } } } } public Map<Variable, Expression> getSelectorVariables() { return selectorVariables; } public DataTransferChannel getChannel() { return channel; } public Expression getMessage() { return message; } public void setMessage(Expression message) { this.message = message; } public boolean isInput() { return isInput; } public List<Map.Entry<Selector, Constant>> getChannelSelectorAndValues() { return channelSelectorAndValues; } public List<Constant> getChannelSelectorValues() { List<Constant> channelValues = new ArrayList<>(); for (Map.Entry<Selector, Constant> chEnt: channelSelectorAndValues) { channelValues.add(chEnt.getValue()); } return channelValues; } public void updateChannelSelectorValues(List<Constant> channelSelectorValues) { for (int i = 0; i < channelSelectorValues.size(); i++) { Map.Entry<Selector, Constant> chEnt = channelSelectorAndValues.get(i); chEnt.setValue(channelSelectorValues.get(i)); } } public Map<Expression, Expression> getDependingParameters() { return dependingParameters; } public Term updateDependingParameters(IResourceStateValueProvider resourceStateValueProvider) { IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { @Override public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { ResourceIdentifier resId = getInputResourceIdentifier(target.getResource()); return resourceStateValueProvider.getCurrentStateValueOf(resId); } @Override public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { ResourceIdentifier resId = getInputResourceIdentifier(target.getResource()); return resourceStateValueProvider.getNextStateValueOf(resId); } @Override public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { ResourceIdentifier resId = getInputResourceIdentifier(target); return resourceStateValueProvider.getCurrentStateValueOf(resId); } }; try { Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels = new HashMap<>(); Term unifiedMessage = null; // Calculate message constraints from leaf channel members on the channel member dependency graph. Map<ChannelMember, Set<ChannelMember>> dependency = channel.getMemberDependency(); if (dependency.size() == 0) { // No channel member dependency. Expression messageConstraint = null; for (ChannelMember channelMember: channel.getInputChannelMembers()) { // Calculate message constraint from an input state transition messageConstraint = channel.calcMessageConstraintForInputMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); if (unifiedMessage == null) { unifiedMessage = (Term) messageConstraint; } else { unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } for (ChannelMember channelMember: channel.getReferenceChannelMembers()) { // Calculate message constraint from a reference state transition messageConstraint = channel.calcMessageConstraintForReferenceMember(channelMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); if (unifiedMessage == null) { unifiedMessage = (Term) messageConstraint; } else { unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } return unifiedMessage; } Set<ChannelMember> toResolve = new HashSet<>(); Set<ChannelMember> resolved = new HashSet<>(); for (Set<ChannelMember> depended: dependency.values()) { toResolve.addAll(depended); } for (ChannelMember depending: dependency.keySet()) { toResolve.remove(depending); } for (ChannelMember leafMember: toResolve) { Expression messageConstraint = null; if (channel.getInputChannelMembers().contains(leafMember)) { // Calculate message constraint from an input state transition messageConstraint = channel.calcMessageConstraintForInputMember(leafMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } else if (channel.getReferenceChannelMembers().contains(leafMember)) { // Calculate message constraint from a reference state transition messageConstraint = channel.calcMessageConstraintForReferenceMember(leafMember, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } if (unifiedMessage == null) { unifiedMessage = (Term) messageConstraint; } else { unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } resolved.addAll(toResolve); toResolve.clear(); for (;;) { for (Map.Entry<ChannelMember, Set<ChannelMember>> dependEnt: dependency.entrySet()) { ChannelMember dependingMem = dependEnt.getKey(); Set<ChannelMember> dependedMems = dependEnt.getValue(); if (!resolved.contains(dependingMem) && resolved.containsAll(dependedMems)) { toResolve.add(dependingMem); } } if (toResolve.size() == 0) break; for (ChannelMember dependingMem: toResolve) { // Fill the path parameters of the resource path of a depending channel member. Set<Position> dependingVarPosInMessage = new HashSet<>(); ResourcePath filledResPath = channel.fillOutsideResourcePath(dependingMem.getResource(), unifiedMessage, dependingMem.getStateTransition().getMessageExpression(), dependingVarPosInMessage); ResourcePath unfilledResPath = dependingMem.getResource(); for (int i = 0; i < unfilledResPath.getPathParams().size(); i++) { Expression var = unfilledResPath.getPathParams().get(i); Expression val = filledResPath.getPathParams().get(i); boolean isSelector = false; for (Selector sel: channel.getAllSelectors()) { if (sel.getExpression().equals(var)) { isSelector = true; break; } } if (!isSelector) { // A depending channel parameter updateDependingParameter(var, val); } } // Calculate message constraint Expression messageConstraint = null; if (channel.getInputChannelMembers().contains(dependingMem)) { // Calculate message constraint from an input state transition messageConstraint = channel.calcMessageConstraintForInputMember(dependingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } else if (channel.getReferenceChannelMembers().contains(dependingMem)) { // Calculate message constraint from a reference state transition messageConstraint = channel.calcMessageConstraintForReferenceMember(dependingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } if (unifiedMessage == null) { unifiedMessage = (Term) messageConstraint; } else { unifiedMessage = (Term) unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } resolved.addAll(toResolve); toResolve.clear(); } return unifiedMessage; } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed e) { e.printStackTrace(); } return null; } public void updateDependingParameter(Expression variable, Expression value) { dependingParameters.put(variable, value); } public ResourcePath getInputResourcePath() { return inputResourcePath; } public Resource getInputResource() { return inputResource; } public Set<Resource> getOutputResources() { return outputResources; } public Set<Event> getSuccessors() { return succEvents; } public void addSuccessor(Event succEvt) { succEvents.add(succEvt); } public ResourceIdentifier getResourceIdentifier(ResourcePath resPath) { ResourceIdentifier resId = ResourceIdentifier.createFrom(resPath); for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); Map<ResourcePath, Integer> inputPathParamEnt = channelSelectorToInputResourcePathParam.get(sel); if (inputPathParamEnt != null) { Integer paramIdx = inputPathParamEnt.get(resPath); if (paramIdx != null) { resId.setPathParam(paramIdx, chParamEnt.getValue()); } } } for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); Map<ResourcePath, Integer> outputPathParamEnt = channelSelectorToOutputResourcePathParam.get(sel); if (outputPathParamEnt != null) { Integer paramIdx = outputPathParamEnt.get(resPath); if (paramIdx != null) { resId.setPathParam(paramIdx, chParamEnt.getValue()); } } } for (Expression var: dependingParameters.keySet()) { int paramIdx = resId.getPathParams().indexOf(var); if (paramIdx >= 0) { resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); } } return resId; } public ResourceIdentifier getInputResourceIdentifier(ResourcePath inputResPath) { ResourceIdentifier resId = ResourceIdentifier.createFrom(inputResPath); for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); if (channelSelectorToInputResourcePathParam.get(sel) != null) { Integer paramIdx = channelSelectorToInputResourcePathParam.get(sel).get(inputResPath); if (paramIdx != null) { resId.setPathParam(paramIdx, chParamEnt.getValue()); } } } for (Expression var: dependingParameters.keySet()) { int paramIdx = resId.getPathParams().indexOf(var); if (paramIdx >= 0) { resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); } } return resId; } public ResourceIdentifier getOutputResourceIdentifier(ResourcePath outputResPath) { ResourceIdentifier resId = ResourceIdentifier.createFrom(outputResPath); for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); if (channelSelectorToOutputResourcePathParam.get(sel) != null) { Integer paramIdx = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); if (paramIdx != null) { resId.setPathParam(paramIdx, chParamEnt.getValue()); } } } for (Expression var: dependingParameters.keySet()) { int paramIdx = resId.getPathParams().indexOf(var); if (paramIdx >= 0) { resId.setPathParam(paramIdx, (Constant) dependingParameters.get(var)); } } return resId; } public interface IResourceStateValueProvider { Expression getCurrentStateValueOf(ResourceIdentifier resId); Expression getNextStateValueOf(ResourceIdentifier resId); } }