package models.dataFlowModel;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import models.algebra.Constant;
import models.algebra.Expression;
import models.algebra.InvalidMessage;
import models.algebra.Parameter;
import models.algebra.ParameterizedIdentifierIsFutureWork;
import models.algebra.Position;
import models.algebra.Term;
import models.algebra.UnificationFailed;
import models.algebra.ValueUndefined;
import models.algebra.Variable;
import models.dataConstraintModel.Channel;
import models.dataConstraintModel.ChannelMember;
import models.dataConstraintModel.ResourcePath;
import models.dataConstraintModel.Selector;
import parser.Parser;
public class DataTransferChannel extends Channel {
protected Set<ChannelMember> inputChannelMembers = null;
protected Set<ChannelMember> outputChannelMembers = null;
protected Set<ChannelMember> referenceChannelMembers = null;
public DataTransferChannel(String channelName) {
super(channelName);
inputChannelMembers = new HashSet<>();
outputChannelMembers = new HashSet<>();
referenceChannelMembers = new HashSet<>();
}
public DataTransferChannel(String channelName, Variable variable) {
super(channelName, variable);
inputChannelMembers = new HashSet<>();
outputChannelMembers = new HashSet<>();
referenceChannelMembers = new HashSet<>();
}
public DataTransferChannel(String channelName, List<Variable> variables) {
super(channelName, variables);
inputChannelMembers = new HashSet<>();
outputChannelMembers = new HashSet<>();
referenceChannelMembers = new HashSet<>();
}
public Set<ChannelMember> getInputChannelMembers() {
return inputChannelMembers;
}
public Set<ChannelMember> getAllInputChannelMembers() {
Set<ChannelMember> allInputChannelMembers = new HashSet<>();
allInputChannelMembers.addAll(inputChannelMembers);
for (Channel child: children) {
allInputChannelMembers.addAll(((DataTransferChannel) child).getAllInputChannelMembers());
}
return allInputChannelMembers;
}
public void setInputChannelMembers(Set<ChannelMember> inputChannelMembers) {
this.inputChannelMembers = inputChannelMembers;
}
private void addInputChannelMember(ChannelMember inputChannelMember) {
inputChannelMembers.add(inputChannelMember);
}
public Set<ChannelMember> getOutputChannelMembers() {
return outputChannelMembers;
}
public void setOutputChannelMembers(Set<ChannelMember> outputChannelMembers) {
this.outputChannelMembers = outputChannelMembers;
}
private void addOutputChannelMember(ChannelMember outputChannelMember) {
outputChannelMembers.add(outputChannelMember);
}
public Set<ChannelMember> getReferenceChannelMembers() {
return referenceChannelMembers;
}
public void setReferenceChannelMembers(Set<ChannelMember> referenceChannelMembers) {
this.referenceChannelMembers = referenceChannelMembers;
}
private void addReferenceChannelMember(ChannelMember referenceChannelMember) {
referenceChannelMembers.add(referenceChannelMember);
}
public void addChannelMemberAsInput(ChannelMember inputChannelMember) {
addChannelMember(inputChannelMember);
addInputChannelMember(inputChannelMember);
}
public void addChannelMemberAsOutput(ChannelMember outputChannelMember) {
addChannelMember(outputChannelMember);
addOutputChannelMember(outputChannelMember);
}
public void addChannelMemberAsReference(ChannelMember referenceChannelMember) {
addChannelMember(referenceChannelMember);
addReferenceChannelMember(referenceChannelMember);
}
public void removeChannelMember(ResourcePath id) {
for (ChannelMember cm: inputChannelMembers) {
if (cm.getResource() == id) {
inputChannelMembers.remove(cm);
super.removeChannelMember(id);
return;
}
}
for (ChannelMember cm: outputChannelMembers) {
if (cm.getResource() == id) {
outputChannelMembers.remove(cm);
super.removeChannelMember(id);
return;
}
}
for (ChannelMember cm: referenceChannelMembers) {
if (cm.getResource() == id) {
referenceChannelMembers.remove(cm);
super.removeChannelMember(id);
return;
}
}
}
public Set<ResourcePath> getInputResources() {
Set<ResourcePath> inputResources = new HashSet<>();
for (ChannelMember member: inputChannelMembers) {
inputResources.add(member.getResource());
}
return inputResources;
}
public Set<ResourcePath> getOutputResources() {
Set<ResourcePath> outputResources = new HashSet<>();
for (ChannelMember member: outputChannelMembers) {
outputResources.add(member.getResource());
}
return outputResources;
}
public Set<ResourcePath> getReferenceResources() {
Set<ResourcePath> referenceResources = new HashSet<>();
for (ChannelMember member: referenceChannelMembers) {
referenceResources.add(member.getResource());
}
return referenceResources;
}
/**
* Derive the update expression of the state of the target channel member.
* @param targetMember a channel member whose state is to be updated
* @return the derived update expression
* @throws ParameterizedIdentifierIsFutureWork
* @throws ResolvingMultipleDefinitionIsFutureWork
* @throws InvalidMessage
* @throws UnificationFailed
* @throws ValueUndefined
*/
public Expression deriveUpdateExpressionOf(ChannelMember targetMember) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
IResourceStateAccessor defaultStateAccessor = new IResourceStateAccessor() {
HashMap<String, Parameter> curStateParams = new HashMap<>();
HashMap<String, Parameter> nextStateParams = new HashMap<>();
@Override
public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) {
String resource = target.getResource().getLeafResourceName();
Parameter curStateParam = curStateParams.get(resource);
if (curStateParam == null) {
curStateParam = new Parameter("cur" + resource);
curStateParams.put(resource, curStateParam);
}
return curStateParam;
}
@Override
public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) {
String resource = target.getResource().getLeafResourceName();
Parameter nextStateParam = nextStateParams.get(resource);
if (nextStateParam == null) {
nextStateParam = new Parameter("next" + target);
nextStateParams.put(resource, nextStateParam);
}
return nextStateParam;
}
@Override
public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) {
String resource = target.getLeafResourceName();
Parameter curStateParam = curStateParams.get(resource);
if (curStateParam == null) {
curStateParam = new Parameter("cur" + resource);
curStateParams.put(resource, curStateParam);
}
return curStateParam;
}
};
return deriveUpdateExpressionOf(targetMember, defaultStateAccessor).getKey();
}
/**
* Derive the state update calculation of the target channel member with a given resource push/pull state accessor.
* @param targetMember a channel member whose state is to be updated
* @param stateAccessor a push/pull resource state accessor
* @return the derived update calculation and the unified message
* @throws ParameterizedIdentifierIsFutureWork
* @throws ResolvingMultipleDefinitionIsFutureWork
* @throws InvalidMessage
* @throws UnificationFailed
* @throws ValueUndefined
*/
public Map.Entry<Expression, Expression> deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor)
throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
return deriveUpdateExpressionOf(targetMember, stateAccessor, null);
}
/**
* Derive the state update calculation of the target channel member with a given resource push/pull state accessor.
* @param targetMember a channel member whose state is to be updated
* @param stateAccessor a push/pull resource state accessor
* @param inputResourceToStateAccessor push/pull resource state accessors (if null, stateAccessor is used.)
* @return the derived update calculation and the unified message
* @throws ParameterizedIdentifierIsFutureWork
* @throws ResolvingMultipleDefinitionIsFutureWork
* @throws InvalidMessage
* @throws UnificationFailed
* @throws ValueUndefined
*/
public Map.Entry<Expression, Expression> deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map<ChannelMember, IResourceStateAccessor> inputResourceToStateAccessor)
throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
if (!getOutputChannelMembers().contains(targetMember)) return null;
// Calculate unified message constraints
Map<ChannelMember, Set<Position>> substitutedPositionsFromChannels = new HashMap<>();
Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsFromChannels);
// Calculate the next state of target resource from the unified message and the current resource state
Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember);
if (unifiedMessage == null) {
// for IOChannel
if (targetMember.getStateTransition().getMessageExpression() instanceof Term) {
unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression();
}
}
return new AbstractMap.SimpleEntry<>(targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage), unifiedMessage);
}
/**
* Derive the state update calculation of the target channel member with a message and a given resource push/pull state accessor.
* @param targetMember a channel member whose state is to be updated
* @param message a message on the channel
* @param stateAccessor a push/pull resource state accessor
* @return the derived update calculation
* @throws ParameterizedIdentifierIsFutureWork
* @throws ResolvingMultipleDefinitionIsFutureWork
* @throws InvalidMessage
* @throws UnificationFailed
* @throws ValueUndefined
*/
public Expression deriveUpdateExpressionOf(ChannelMember targetMember, Term message, IResourceStateAccessor stateAccessor)
throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
if (!getOutputChannelMembers().contains(targetMember)) return null;
// Calculate the next state of target resource from the unified message and the current resource state
Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember);
return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, message);
}
/**
* Fill outside resource paths with a given resource push/pull state accessor.
* @param targetMember a channel member whose state is to be updated
* @param stateAccessor a push/pull resource state accessor
* @return map from a depending channel member to the pair of the filled resource path and the set of the depended channel members
* @throws ParameterizedIdentifierIsFutureWork
* @throws ResolvingMultipleDefinitionIsFutureWork
* @throws InvalidMessage
* @throws UnificationFailed
* @throws ValueUndefined
*/
public Map<ChannelMember, Entry<ResourcePath, Set<ChannelMember>>> fillOutsideResourcePaths(ChannelMember targetMember, IResourceStateAccessor stateAccessor)
throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
if (!getOutputChannelMembers().contains(targetMember)) return null;
return fillOutsideResourcePaths(targetMember, stateAccessor, null).getKey();
}
/**
* Fill outside resource paths with a given resource push/pull state accessor.
* @param targetMember a channel member whose state is to be updated
* @param stateAccessor a push/pull resource state accessor
* @param inputResourceToStateAccessor push/pull resource state accessors (if null, stateAccessor is used.)
* @return map from a depending channel member to the pair of the filled resource path and the set of the depended channel members
* @throws ParameterizedIdentifierIsFutureWork
* @throws ResolvingMultipleDefinitionIsFutureWork
* @throws InvalidMessage
* @throws UnificationFailed
* @throws ValueUndefined
*/
public Map.Entry<Map<ChannelMember, Entry<ResourcePath, Set<ChannelMember>>>, Term> fillOutsideResourcePaths(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map<ChannelMember, IResourceStateAccessor> inputResourceToStateAccessor)
throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
Map<ChannelMember, Entry<ResourcePath, Set<ChannelMember>>> resourcePaths = new HashMap<>();
// Calculate unified message constraints from input and reference state transitions
Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels = new HashMap<>();
Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsInMessageFromChannels);
// Fill outside resource paths
if (unifiedMessage != null) {
for (ChannelMember cm: getInputChannelMembers()) {
if (cm.isOutside()) {
Set<Position> dependingVarPosInMessage = new HashSet<>();
ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPosInMessage);
Set<ChannelMember> dependingChannelMembers = new HashSet<>();
for (ChannelMember otherCm: substitutedPositionsInMessageFromChannels.keySet()) {
for (Position otherPos: substitutedPositionsInMessageFromChannels.get(otherCm)) {
for (Position thisPos: dependingVarPosInMessage) {
if (thisPos.isAncestorOf(otherPos)) {
dependingChannelMembers.add(otherCm);
break;
}
}
if (dependingChannelMembers.contains(otherCm)) break;
}
}
resourcePaths.put(cm, new AbstractMap.SimpleEntry<>(filledResPath, dependingChannelMembers));
}
}
for (ChannelMember cm: getReferenceChannelMembers()) {
if (cm.isOutside()) {
Set<Position> dependingVarPosInMessage = new HashSet<>();
ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPosInMessage);
Set<ChannelMember> dependingChannelMembers = new HashSet<>();
for (ChannelMember otherCm: substitutedPositionsInMessageFromChannels.keySet()) {
for (Position otherPos: substitutedPositionsInMessageFromChannels.get(otherCm)) {
for (Position thisPos: dependingVarPosInMessage) {
if (thisPos.isAncestorOf(otherPos)) {
dependingChannelMembers.add(otherCm);
break;
}
}
if (dependingChannelMembers.contains(otherCm)) break;
}
}
resourcePaths.put(cm, new AbstractMap.SimpleEntry<>(filledResPath, dependingChannelMembers));
}
}
for (ChannelMember cm: getOutputChannelMembers()) {
if (cm.isOutside()) {
Set<Position> dependingVarPosInMessage = new HashSet<>();
ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPosInMessage);
Set<ChannelMember> dependingChannelMembers = new HashSet<>();
for (ChannelMember otherCm: substitutedPositionsInMessageFromChannels.keySet()) {
for (Position otherPos: substitutedPositionsInMessageFromChannels.get(otherCm)) {
for (Position thisPos: dependingVarPosInMessage) {
if (thisPos.isAncestorOf(otherPos)) {
dependingChannelMembers.add(otherCm);
break;
}
}
if (dependingChannelMembers.contains(otherCm)) break;
}
}
resourcePaths.put(cm, new AbstractMap.SimpleEntry<>(filledResPath, dependingChannelMembers));
}
}
}
return new AbstractMap.SimpleEntry<>(resourcePaths, unifiedMessage);
}
/**
* Get the dependency from the values of the 'path parameters' of a channel member to the state values of other channel members.
*
* @return a map from a depending channel member to depended channel members
*/
public Map<ChannelMember, Set<ChannelMember>> getMemberDependency() {
Map<ChannelMember, Set<ChannelMember>> dependency = new HashMap<>();
// Collect depended channel members and their positions in the message
Map<ChannelMember, Set<Position>> substitutedPositionsInMessage = getDependedChannelMembersAndTheirPositionsInMessage();
// Resolve dependency for each outside resource path
if (substitutedPositionsInMessage != null) {
for (ChannelMember cm: getInputChannelMembers()) {
if (cm.isOutside()) {
Set<Position> dependingVarPosInMessage = getPossitionsInMessageThatChannelMemberDependsOn(cm.getResource(), cm.getStateTransition().getMessageExpression());
Set<ChannelMember> dependingChannelMembers = new HashSet<>();
for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) {
for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) {
for (Position thisPos: dependingVarPosInMessage) {
if (thisPos.isAncestorOf(otherPos) && otherCm != cm) {
dependingChannelMembers.add(otherCm);
break;
}
}
if (dependingChannelMembers.contains(otherCm)) break;
}
}
dependency.put(cm, dependingChannelMembers);
}
}
for (ChannelMember cm: getReferenceChannelMembers()) {
if (cm.isOutside()) {
Set<Position> dependingVarPosInMessage = getPossitionsInMessageThatChannelMemberDependsOn(cm.getResource(), cm.getStateTransition().getMessageExpression());
Set<ChannelMember> dependingChannelMembers = new HashSet<>();
for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) {
for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) {
for (Position thisPos: dependingVarPosInMessage) {
if (thisPos.isAncestorOf(otherPos) && otherCm != cm) {
dependingChannelMembers.add(otherCm);
break;
}
}
if (dependingChannelMembers.contains(otherCm)) break;
}
}
dependency.put(cm, dependingChannelMembers);
}
}
for (ChannelMember cm: getOutputChannelMembers()) {
if (cm.isOutside()) {
Set<Position> dependingVarPosInMessage = getPossitionsInMessageThatChannelMemberDependsOn(cm.getResource(), cm.getStateTransition().getMessageExpression());
Set<ChannelMember> dependingChannelMembers = new HashSet<>();
for (ChannelMember otherCm: substitutedPositionsInMessage.keySet()) {
for (Position otherPos: substitutedPositionsInMessage.get(otherCm)) {
for (Position thisPos: dependingVarPosInMessage) {
if (thisPos.isAncestorOf(otherPos) && otherCm != cm) {
dependingChannelMembers.add(otherCm);
break;
}
}
if (dependingChannelMembers.contains(otherCm)) break;
}
}
dependency.put(cm, dependingChannelMembers);
}
}
}
return dependency;
}
private Term calcUnifiedMessage(ChannelMember targetMember, IResourceStateAccessor stateAccessor,
Map<ChannelMember, IResourceStateAccessor> inputResourceToStateAccessor, Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels)
throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork, UnificationFailed {
Set<Term> messageConstraints = new HashSet<>();
// Calculate message constraints from input state transitions
for (ChannelMember inputMember: getInputChannelMembers()) {
Expression messageConstraintByInput = calcMessageConstraintForInputMember(inputMember, targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsInMessageFromChannels);
messageConstraints.add((Term) messageConstraintByInput);
}
// Calculate message constraints from reference state transitions
for (ChannelMember referenceMember: getReferenceChannelMembers()) {
Expression messageConstraintByReference = calcMessageConstraintForReferenceMember(referenceMember, targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsInMessageFromChannels);
messageConstraints.add((Term) messageConstraintByReference);
}
// Unify message constraints
Term unifiedMessage = null;
for (Term messageContraint: messageConstraints) {
if (unifiedMessage == null) {
unifiedMessage = messageContraint;
} else {
unifiedMessage = (Term) unifiedMessage.unify(messageContraint);
if (unifiedMessage == null) {
throw new UnificationFailed();
}
}
}
return unifiedMessage;
}
public Expression calcMessageConstraintForInputMember(ChannelMember inputMember, ChannelMember targetMember, IResourceStateAccessor stateAccessor,
Map<ChannelMember, IResourceStateAccessor> inputResourceToStateAccessor, Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels)
throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork {
Expression curInputStateAccessor = null;
Expression nextInputStateAccessor = null;
if (inputResourceToStateAccessor == null) {
curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputMember, targetMember);
nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputMember, targetMember);
} else {
curInputStateAccessor = inputResourceToStateAccessor.get(inputMember).getCurrentStateAccessorFor(inputMember, targetMember);
nextInputStateAccessor = inputResourceToStateAccessor.get(inputMember).getNextStateAccessorFor(inputMember, targetMember);
}
Set<Position> substitutedPositionsInMessage = new HashSet<>();
Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor, substitutedPositionsInMessage);
if (substitutedPositionsInMessage.size() > 0) substitutedPositionsInMessageFromChannels.put(inputMember, substitutedPositionsInMessage);
return messageConstraintByInput;
}
public Expression calcMessageConstraintForReferenceMember(ChannelMember referenceMember, ChannelMember targetMember, IResourceStateAccessor stateAccessor,
Map<ChannelMember, IResourceStateAccessor> inputResourceToStateAccessor, Map<ChannelMember, Set<Position>> substitutedPositionsInMessageFromChannels)
throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork {
Expression curInputStateAccessor = null;
if (inputResourceToStateAccessor == null) {
curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(referenceMember, targetMember);
} else {
curInputStateAccessor = inputResourceToStateAccessor.get(referenceMember).getCurrentStateAccessorFor(referenceMember, targetMember);
}
Set<Position> substitutedPositions = new HashSet<>();
Expression messageConstraintByReference = referenceMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, substitutedPositions);
if (substitutedPositions.size() > 0) substitutedPositionsInMessageFromChannels.put(referenceMember, substitutedPositions);
return messageConstraintByReference;
}
/**
* Get depended channel members and their positions in the message.
*
* @return depended channel members and their positions in the message
*/
private Map<ChannelMember, Set<Position>> getDependedChannelMembersAndTheirPositionsInMessage() {
Map<ChannelMember, Set<Position>> channelMembersMessageDependsOn = new HashMap<>();
// Collect channel members that the message depends on from input state transitions
for (ChannelMember inputMember: getInputChannelMembers()) {
Set<Position> substitutedPositionsInMessage = new HashSet<>();
Expression messageTerm = inputMember.getStateTransition().getMessageExpression();
Expression curStateTerm = inputMember.getStateTransition().getCurStateExpression();
Expression nextStateTerm = inputMember.getStateTransition().getNextStateExpression();
HashMap<Position, Variable> messageVars = messageTerm.getVariables();
for (Entry<Position, Variable> varEnt: messageVars.entrySet()) {
Variable var = varEnt.getValue();
if (curStateTerm.getVariables().values().contains(var) || nextStateTerm.getVariables().values().contains(var)) {
if (messageTerm instanceof Term) {
substitutedPositionsInMessage.add(varEnt.getKey());
} else if (messageTerm instanceof Variable) {
if (messageTerm.equals(var)) {
substitutedPositionsInMessage.add(new Position());
}
}
}
}
if (substitutedPositionsInMessage.size() > 0) channelMembersMessageDependsOn.put(inputMember, substitutedPositionsInMessage);
}
// Collect channel members that the message depends on from reference state transitions
for (ChannelMember referenceMember: getReferenceChannelMembers()) {
Set<Position> substitutedPositionsInMessage = new HashSet<>();
Expression messageTerm = referenceMember.getStateTransition().getMessageExpression();
Expression curStateTerm = referenceMember.getStateTransition().getCurStateExpression();
// Expression nextStateTerm = referenceMember.getStateTransition().getNextStateExpression();
HashMap<Position, Variable> messageVars = messageTerm.getVariables();
for (Entry<Position, Variable> varEnt: messageVars.entrySet()) {
Variable var = varEnt.getValue();
if (curStateTerm.getVariables().values().contains(var)) {
if (messageTerm instanceof Term) {
substitutedPositionsInMessage.add(varEnt.getKey());
} else if (messageTerm instanceof Variable) {
if (messageTerm.equals(var)) {
substitutedPositionsInMessage.add(new Position());
}
}
}
}
if (substitutedPositionsInMessage.size() > 0) channelMembersMessageDependsOn.put(referenceMember, substitutedPositionsInMessage);
}
return channelMembersMessageDependsOn;
}
public ResourcePath fillOutsideResourcePath(ResourcePath resource, Expression unifiedMessage, Expression messageTerm, Set<Position> dependingVarPosInMessage)
throws ResolvingMultipleDefinitionIsFutureWork {
ResourcePath filledResourcePath = new ResourcePath(resource);
Map<Variable, Entry<Position, Expression>> bindings = new HashMap<>();
Map<Position, Variable> messageVars = messageTerm.getVariables();
for (Entry<Position, Variable> messageVarEnt: messageVars.entrySet()) {
Variable var = messageVarEnt.getValue();
Position varPos = messageVarEnt.getKey();
Expression valueCalc = unifiedMessage.getSubTerm(varPos);
if (valueCalc != null) {
if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork();
bindings.put(var, new AbstractMap.SimpleEntry<>(varPos, valueCalc));
}
}
List<Map.Entry<Expression, Expression>> dstParams = filledResourcePath.getPathParamsAndConstraints();
for (int i = 0; i < filledResourcePath.getPathParams().size(); i++) {
Expression pathParam = dstParams.get(i).getKey();
Expression pathValue = dstParams.get(i).getValue();
if (pathParam instanceof Variable) {
if (pathValue == null) {
if (bindings.get((Variable) pathParam) != null) {
filledResourcePath.replacePathParam(i, bindings.get((Variable) pathParam).getValue(), null); // Replace a path parameter with a value in the unified message.
dependingVarPosInMessage.add(bindings.get((Variable) pathParam).getKey()); // The position of the replaced variable in the message.
}
} else {
// If the path parameter has a constraint.
if (pathValue instanceof Term) {
Map<Position, Variable> pathValueVars = ((Term) pathValue).getVariables();
for (Variable var: bindings.keySet()) {
if (pathValueVars.values().contains(var)) { // var is a subterm of a path parameter
pathValue = ((Term) pathValue).substitute(var, bindings.get(var).getValue()); // Substitute a value in the unified message to var.
dependingVarPosInMessage.add(bindings.get((Variable) var).getKey()); // The position of the replaced variable in the message.
}
}
if (!(pathValue instanceof Constant)) {
pathValue = ((Term) pathValue).reduce();
}
filledResourcePath.replacePathParam(i, pathValue, null); // Replace a path parameter with the substituted term.
}
}
} else if (pathParam instanceof Term) {
Map<Position, Variable> pathParamVars = ((Term) pathParam).getVariables();
for (Variable var: bindings.keySet()) {
if (pathParamVars.values().contains(var)) { // var is a subterm of a path parameter
pathParam = ((Term) pathParam).substitute(var, bindings.get(var).getValue()); // Substitute a value in the unified message to var.
dependingVarPosInMessage.add(bindings.get((Variable) var).getKey()); // The position of the replaced variable in the message.
}
}
if (!(pathParam instanceof Constant)) {
pathParam = ((Term) pathParam).reduce();
}
filledResourcePath.replacePathParam(i, pathParam, null); // Replace a path parameter with the substituted term.
}
}
return filledResourcePath;
}
private Set<Position> getPossitionsInMessageThatChannelMemberDependsOn(ResourcePath resourcePath, Expression messageTerm) {
Set<Position> dependingVarPosInMessage = new HashSet<>();
Map<Position, Variable> messageVars = messageTerm.getVariables();
for (Map.Entry<Expression, Expression> pathParamEnt: resourcePath.getPathParamsAndConstraints()) {
Expression pathParam = pathParamEnt.getKey();
if (pathParam instanceof Variable) {
for (Entry<Position, Variable> messageVarEnt: messageVars.entrySet()) {
Variable var = messageVarEnt.getValue();
Position varPos = messageVarEnt.getKey();
if (pathParam.equals(var)) {
dependingVarPosInMessage.add(varPos);
}
}
} else if (pathParam instanceof Term) {
Map<Position, Variable> pathParamVars = ((Term) pathParam).getVariables();
for (Entry<Position, Variable> messageVarEnt: messageVars.entrySet()) {
Variable var = messageVarEnt.getValue();
Position varPos = messageVarEnt.getKey();
if (pathParamVars.values().contains(var)) {
dependingVarPosInMessage.add(varPos);
}
}
}
}
return dependingVarPosInMessage;
}
@Override
public String toString() {
String channelSource = "";
if (isNative()) {
channelSource += Parser.NATIVE + " ";
}
if (parent == null) {
channelSource += Parser.CHANNEL + " " + getChannelName();
} else {
channelSource += Parser.SUB_CHANNEL + " " + getChannelName();
}
if (getSelectors().size() > 0) {
channelSource += "(";
String delimitor = "";
for (Selector selector: getSelectors()) {
channelSource += delimitor + selector.getExpression().toString();
delimitor = ", ";
}
channelSource += ")";
}
channelSource += " {\n";
for (ChannelMember inputMember: inputChannelMembers) {
channelSource += "\t " + Parser.IN + " " + inputMember + "\n";
}
for (ChannelMember refMember: referenceChannelMembers) {
channelSource += "\t " + Parser.REF + " " + refMember + "\n";
}
for (ChannelMember outputMember: outputChannelMembers) {
channelSource += "\t " + Parser.OUT + " " + outputMember + "\n";
}
for (Channel childCh: getChildren()) {
channelSource += childCh.toString();
}
channelSource += "}\n";
return channelSource;
}
public interface IResourceStateAccessor {
Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from);
Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from);
Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes);
}
}