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.Channel; 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; /** * Event occurred at a channel * * @author Nitta * */ 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> childEvents = new HashSet<>(); private Map<Selector, Map<ResourcePath, Map.Entry<Integer, Set<Position>>>> channelSelectorToInputOrReferenceResourcePathParam = new HashMap<>(); private Map<Selector, Map<ResourcePath, Map.Entry<Integer, Set<Position>>>> channelSelectorToOutputResourcePathParam = new HashMap<>(); /** * Constructor for an input event channel * * @param channel an input event channel * @param message an message for the channel * @param outputResPath an output side resource path of the channel * @param outputResource an output side resource of the channel */ 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 the values of the channel selectors from the output resource. List<Selector> channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { Map.Entry<Integer, Set<Position>> paramIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); Resource ancestor = outputResource; int idx = outputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; if (idx == paramIdxAndPos.getKey()) break; } ancestor = ancestor.getParent(); } if (ancestor!= null) channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); } } /** * Constructor for a non-event channel * * @param channel a non-event channel * @param inputResPath an input side resource path of the channel * @param inputResource an input side resource of the channel */ public Event(DataTransferChannel channel, ResourcePath inputResPath, Resource inputResource) { this.channel = channel; this.isInput = false; this.inputResourcePath = inputResPath; this.inputResource = inputResource; connectChannelSelectorAndPathParameters(); // Extract the values of the channel selectors from the input resource. List<Selector> channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { if (inputResPath != null) { Map.Entry<Integer, Set<Position>> paramIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); if (paramIdxAndPos != null) { Resource ancestor = inputResource; int idx = inputResPath.getPathParams().size(); while (ancestor != null) { if (ancestor.getResourceHierarchy().getNumParameters() > 0) { idx--; if (idx == paramIdxAndPos.getKey()) break; } ancestor = ancestor.getParent(); } channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); } } } } /** * Constructor for a non-event channel * * @param channel a non-event channel * @param inputResPath an input side resource path of the channel * @param inputResource an input side resource of the channel * @param channelSelectorValues the values of depended channel selectors * @param dependingVarToVal the values of depending channel selectors */ 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 the values of the channel selectors from channelSelectorValues. 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() { List<Selector> channelSelectors = channel.getAllSelectors(); for (Selector sel: channelSelectors) { Set<ResourcePath> inputAndReferenceResPaths = new HashSet<>(channel.getInputResources()); inputAndReferenceResPaths.addAll(channel.getReferenceResources()); for (ResourcePath resPath: inputAndReferenceResPaths) { for (int paramIdx = 0; paramIdx < resPath.getPathParams().size(); paramIdx++) { Expression pathParam = resPath.getPathParams().get(paramIdx); if (pathParam.contains(sel.getExpression())) { for (Map.Entry<Position, Variable> posAndVar: pathParam.getVariables().entrySet()) { Position p = posAndVar.getKey(); Variable v = posAndVar.getValue(); if (v.equals(sel.getExpression())) { Map<ResourcePath, Map.Entry<Integer, Set<Position>>> pathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); if (pathToIdxAndPos == null) { pathToIdxAndPos = new HashMap<>(); channelSelectorToInputOrReferenceResourcePathParam.put(sel, pathToIdxAndPos); } Map.Entry<Integer, Set<Position>> idxAndPos = pathToIdxAndPos.get(resPath); if (idxAndPos == null) { idxAndPos = new AbstractMap.SimpleEntry<>(paramIdx, new HashSet<>()); pathToIdxAndPos.put(resPath, idxAndPos); } idxAndPos.getValue().add(p); } } } } } for (ResourcePath resPath: channel.getOutputResources()) { for (int paramIdx = 0; paramIdx < resPath.getPathParams().size(); paramIdx++) { Expression pathParam = resPath.getPathParams().get(paramIdx); if (pathParam.contains(sel.getExpression())) { for (Map.Entry<Position, Variable> posAndVar: pathParam.getVariables().entrySet()) { Position p = posAndVar.getKey(); Variable v = posAndVar.getValue(); if (v.equals(sel.getExpression())) { Map<ResourcePath, Map.Entry<Integer, Set<Position>>> pathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); if (pathToIdxAndPos == null) { pathToIdxAndPos = new HashMap<>(); channelSelectorToOutputResourcePathParam.put(sel, pathToIdxAndPos); } Map.Entry<Integer, Set<Position>> idxAndPos = pathToIdxAndPos.get(resPath); if (idxAndPos == null) { idxAndPos = new AbstractMap.SimpleEntry<>(paramIdx, new HashSet<>()); pathToIdxAndPos.put(resPath, idxAndPos); } idxAndPos.getValue().add(p); } } } } } } } 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 void addChild(Event child) { childEvents.add(child); } public Set<Event> getChildren() { return childEvents; } /** * Construct channel message, collect descendant events of this event and update the values of the depending channel selectors * * @param resourceStateValueProvider a resourceStateValueProvider to provide current and next resource states * @return calculated message constraint by this event */ public Expression constructMessageAndDescendantEvents(IResourceStateValueProvider resourceStateValueProvider, boolean doesUpdateDependingParameters) { try { Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels = new HashMap<>(); return constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, doesUpdateDependingParameters); } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed e) { e.printStackTrace(); } return null; } private Expression constructMessageAndDesdendantEvents(IResourceStateValueProvider resourceStateValueProvider, Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels, boolean doesUpdateDependingParameters) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork, UnificationFailed { Expression unifiedMessage = null; Expression messageConstraint = null; if (message != null) { unifiedMessage = (Term) message.clone(); } 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); } }; // 1. 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. 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 = messageConstraint; } else { unifiedMessage = 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 = messageConstraint; } else { unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } } else { 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); } if ((messageConstraint = getMessage()) instanceof Term) { unifiedMessage = messageConstraint; } for (ChannelMember leafMember: toResolve) { 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 = messageConstraint; } else { unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } resolved.addAll(toResolve); toResolve.clear(); // 2. Calculate message constraints from remaining members on the channel member dependency graph. for (;;) { // Identify the channel members to resolve next. 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. if (doesUpdateDependingParameters) { 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.getPathParamsAndConstraints().size(); i++) { Expression var = unfilledResPath.getPathParamsAndConstraints().get(i).getKey(); Expression val = filledResPath.getPathParamsAndConstraints().get(i).getKey(); Expression constraint = unfilledResPath.getPathParamsAndConstraints().get(i).getValue(); if (constraint != null && !constraint.equals(val)) { // The value of the path parameter does not satisfy the constraint defined for the parameter. return null; // Not to fire this event. } if (!channel.getAllSelectorVariables().contains(var)) { // Update a depending channel parameter updateDependingParameter(var, val); } } } // Calculate message constraint 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 = messageConstraint; } else { unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } resolved.addAll(toResolve); toResolve.clear(); } // For the channel members that are depended by and depend on no other member. for (ChannelMember remainingMem: channel.getChannelMembers()) { if (!resolved.contains(remainingMem)) { resolved.add(remainingMem); // Calculate message constraint messageConstraint = null; if (channel.getInputChannelMembers().contains(remainingMem)) { // Calculate message constraint from an input state transition messageConstraint = channel.calcMessageConstraintForInputMember(remainingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } else if (channel.getReferenceChannelMembers().contains(remainingMem)) { // Calculate message constraint from a reference state transition messageConstraint = channel.calcMessageConstraintForReferenceMember(remainingMem, null, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); } if (messageConstraint != null) { if (unifiedMessage == null) { unifiedMessage = messageConstraint; } else { unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } } } } } if (inputResource == null) return unifiedMessage; // 3. Propagate parent event message to collect child events and calculate message constraints from child channels. Resource baseResource = inputResource; while (baseResource.getResourceHierarchy().getNumParameters() == 0) { if (baseResource.getParent() == null) break; baseResource = baseResource.getParent(); } Expression parentEventMessage = (Expression) unifiedMessage.clone(); for (Channel childChannel: channel.getChildren()) { // Search the deepest input or reference side resource path in each child channel that matches the channel parameters. ChannelMember inOrRef = null; Set<ChannelMember> channelMembers = new HashSet<>(((DataTransferChannel) childChannel).getInputChannelMembers()); channelMembers.addAll(((DataTransferChannel) childChannel).getReferenceChannelMembers()); for (ChannelMember cm: channelMembers) { if (!cm.isOutside()) { ResourcePath resPath = cm.getResource(); if (resPath.getPathParams().containsAll(childChannel.getAllSelectorVariables())) { inOrRef = cm; break; } } } if (inOrRef != null) { // Collect events for all resources under this event's input resource that matches the deepest input side resource path. for (Resource res: baseResource.getDescendants(inOrRef.getResource().getResourceHierarchy())) { Event childEvent = new Event((DataTransferChannel) childChannel, inOrRef.getResource(), res); childEvent.setMessage(parentEventMessage); messageConstraint = childEvent.constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, true); if (messageConstraint != null) { childEvent.setMessage(messageConstraint); if (unifiedMessage == null) { unifiedMessage = messageConstraint; } else { unifiedMessage = unifiedMessage.unify(messageConstraint); if (unifiedMessage == null) { throw new UnificationFailed(); } } childEvents.add(childEvent); } } } else { // Search the deepest output side resource path in each child channel that matches the channel parameters. ChannelMember out = null; for (ChannelMember cm: ((DataTransferChannel) childChannel).getOutputChannelMembers()) { if (!cm.isOutside()) { ResourcePath resPath = cm.getResource(); if (resPath.getPathParams().containsAll(childChannel.getAllSelectorVariables())) { out = cm; break; } } } if (out != null) { // Collect events for all resources under this event's input resource that matches the deepest output side resource path. for (Resource res: baseResource.getDescendants(out.getResource().getResourceHierarchy())) { Event childEvent = new Event((DataTransferChannel) childChannel, parentEventMessage, out.getResource(), res); childEvent.constructMessageAndDesdendantEvents(resourceStateValueProvider, substitutedPositionsInMessageFromChannels, true); childEvents.add(childEvent); } } } } return unifiedMessage; } 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 ResourceIdentifier getResourceIdentifier(ResourcePath resPath) { ResourceIdentifier resId = ResourceIdentifier.createFrom(resPath); for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); Map<ResourcePath, Map.Entry<Integer, Set<Position>>> inputPathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); if (inputPathToIdxAndPos != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = inputPathToIdxAndPos.get(resPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Variable) { resId.setPathParam(paramIdx, chParamEnt.getValue()); } } } } } for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); Map<ResourcePath, Map.Entry<Integer, Set<Position>>> outputPathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); if (outputPathToIdxAndPos != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = outputPathToIdxAndPos.get(resPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Variable) { 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)); } } for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); Map<ResourcePath, Map.Entry<Integer, Set<Position>>> inputPathToIdxAndPos = channelSelectorToInputOrReferenceResourcePathParam.get(sel); if (inputPathToIdxAndPos != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = inputPathToIdxAndPos.get(resPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); } } } } } for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); Map<ResourcePath, Map.Entry<Integer, Set<Position>>> outputPathToIdxAndPos = channelSelectorToOutputResourcePathParam.get(sel); if (outputPathToIdxAndPos != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = outputPathToIdxAndPos.get(resPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); } } } } } return resId; } public ResourceIdentifier getInputResourceIdentifier(ResourcePath inputResPath) { ResourceIdentifier resId = ResourceIdentifier.createFrom(inputResPath); for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); if (channelSelectorToInputOrReferenceResourcePathParam.get(sel) != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Variable) { 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)); } } for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); if (channelSelectorToInputOrReferenceResourcePathParam.get(sel) != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = channelSelectorToInputOrReferenceResourcePathParam.get(sel).get(inputResPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); } } } } } 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) { Map.Entry<Integer, Set<Position>> pathParamEnt = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Variable) { resId.setPathParam(paramIdx, chParamEnt.getValue()); } } } } } for (Expression var: dependingParameters.keySet()) { int paramIdx = resId.getPathParams().indexOf(var); if (paramIdx >= 0) { resId.setPathParam(paramIdx, dependingParameters.get(var)); } } for (Map.Entry<Selector, Constant> chParamEnt: channelSelectorAndValues) { Selector sel = chParamEnt.getKey(); if (channelSelectorToOutputResourcePathParam.get(sel) != null) { Map.Entry<Integer, Set<Position>> pathParamEnt = channelSelectorToOutputResourcePathParam.get(sel).get(outputResPath); if (pathParamEnt != null) { Integer paramIdx = pathParamEnt.getKey(); if (paramIdx != null) { Expression pathParamExp = resId.getPathParams().get(paramIdx); if (pathParamExp instanceof Term && sel.getExpression() instanceof Variable) { pathParamExp = ((Term) pathParamExp).substitute((Variable) sel.getExpression(), chParamEnt.getValue()); resId.setPathParam(paramIdx, ((Term) pathParamExp).reduce()); } } } } } return resId; } public interface IResourceStateValueProvider { Expression getCurrentStateValueOf(ResourceIdentifier resId); Expression getNextStateValueOf(ResourceIdentifier resId); } }