use of won.protocol.agreement.effect.MessageEffectsBuilder in project webofneeds by researchstudio-sat.
the class AgreementProtocolState method recalculate.
/**
* Calculates all agreements present in the specified conversation dataset.
*/
private void recalculate(Dataset conversationDataset) {
if (logger.isDebugEnabled()) {
logger.debug("starting conversation analysis for high-level protocols");
}
pendingProposals.begin(ReadWrite.WRITE);
agreements.begin(ReadWrite.WRITE);
cancelledAgreements.begin(ReadWrite.WRITE);
rejected.begin(ReadWrite.WRITE);
claims.begin(ReadWrite.WRITE);
conversationDataset.begin(ReadWrite.READ);
this.messagesByURI = ConversationMessagesReader.readConversationMessages(conversationDataset);
Set<ConversationMessage> roots = new HashSet<ConversationMessage>();
Collection<ConversationMessage> messages = messagesByURI.values();
Set<DeadReferenceConversationMessage> messagesWithDeadReferences = new HashSet<>();
// filter out messages we don't care about
messages = messages.stream().filter(m -> !m.getMessageType().isHintMessage()).collect(Collectors.toList());
// iterate over messages and interconnect them
messages.stream().forEach(message -> {
message.getPrevious().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addPreviousRef(other);
other.addPreviousInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "msg:previousMessage", uri));
}
});
message.getForwarded().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addForwardedRef(other);
other.addForwardedInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "msg:forwardedMessage", uri));
}
});
message.getAccepts().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addAcceptsRef(other);
other.addAcceptsInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "agr:accepts", uri));
}
});
message.getProposes().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addProposesRef(other);
other.addProposesInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "agr:proposes", uri));
}
});
message.getClaims().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addClaimsRef(other);
other.addClaimsInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "agr:claims", uri));
}
});
message.getRejects().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addRejectsRef(other);
other.addRejectsInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "agr:rejects", uri));
}
});
message.getProposesToCancel().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addProposesToCancelRef(other);
other.addProposesToCancelInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "agr:proposesToCancel", uri));
}
});
message.getRetracts().stream().filter(uri -> !uri.equals(message.getMessageURI())).forEach(uri -> {
ConversationMessage other = messagesByURI.get(uri);
if (other != null) {
message.addRetractsRef(other);
other.addRetractsInverseRef(message);
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "mod:retracts", uri));
}
});
if (message.getRespondingTo() != null && !message.getRespondingTo().equals(message.getMessageURI())) {
ConversationMessage other = messagesByURI.get(message.getRespondingTo());
if (other != null) {
if (other.getSenderAtomURI().equals(message.getSenderAtomURI())) {
if (other.getRespondingToInverseRef() != null && !message.equals(other.getRespondingToInverseRef())) {
throw new InconsistentConversationDataException("Message " + other.getMessageURI() + " has more than one response: " + other.getRespondingToInverseRef().getMessageURI() + " and " + message.getMessageURI());
}
message.setRespondingToRef(other);
other.setRespondingToInverseRef(message);
} else {
// change from respondingTo to remotelyRespondingTo
if (other.getRemotelyRespondingToInverseRef() != null && !message.equals(other.getRemotelyRespondingToInverseRef())) {
throw new InconsistentConversationDataException("Message " + other.getMessageURI() + " has more than one remote response: " + other.getRemotelyRespondingToInverseRef().getMessageURI() + " and " + message.getMessageURI());
}
message.setRemotelyRespondingTo(message.getRespondingTo());
// clear original reference
message.setRespondingTo(null);
message.setRemotelyRespondingToRef(other);
other.setRemotelyRespondingToInverseRef(message);
}
} else {
messagesWithDeadReferences.add(new DeadReferenceConversationMessage(message, "msg:respondingTo", message.getRespondingTo()));
}
}
if (message.getPrevious().isEmpty()) {
roots.add(message);
}
});
//
// now revisit all messages with dead references. Throw an exception if the
// message is not a forwarded message
messagesWithDeadReferences.stream().forEach(deadRef -> {
if (deadRef.message.getMessageType() == WonMessageType.FAILURE_RESPONSE) {
// eg because it failed consistency checks
return;
}
if (deadRef.message.isForwardedMessage()) {
// if it points to a missing message
return;
}
throw new IncompleteConversationDataException(deadRef.message.getMessageURI(), deadRef.deadReference, deadRef.predicate);
});
if (logger.isDebugEnabled()) {
messages.stream().forEach(m -> logger.debug(m.toString()));
}
// link messages to deliveryChains
deliveryChains = messages.stream().map(m -> {
if (logger.isDebugEnabled()) {
logger.debug("deliveryChain for message {}: {}", m.getMessageURI(), m.getDeliveryChain());
}
return m.getDeliveryChain();
}).collect(Collectors.toSet());
// find interleaved delivery chains
deliveryChains.stream().forEach(dc -> deliveryChains.stream().forEach(dc2 -> {
dc.determineRelationshipWith(dc2);
}));
// apply acknowledgment protocol to whole conversation first:
conversation = acknowledgedSelection(conversationDataset, messages);
// on top of this, apply modification and agreement protocol on a per-message
// basis, starting with the root(s)
// expect proposals and agreements to be empty
PriorityQueue<ConversationMessage> currentMessages = new PriorityQueue<ConversationMessage>();
currentMessages.addAll(messages);
// we need to use a priority queue for the messages, which is
// sorted by temporal ordering. Each time we process a message, we
// add the subsequent ones to the queue, the retrieve the
// oldest from the queue for the next iteration.
Set<ConversationMessage> processed = new HashSet<>();
List<ConversationMessage> processedInOrder = null;
if (logger.isDebugEnabled()) {
processedInOrder = new ArrayList<>();
}
ConversationMessage last = null;
while (!currentMessages.isEmpty()) {
ConversationMessage msg = currentMessages.poll();
if (processed.contains(msg)) {
continue;
}
processed.add(msg);
MessageEffectsBuilder effectsBuilder = new MessageEffectsBuilder(msg.getMessageURI());
if (logger.isDebugEnabled() && processedInOrder != null) {
processedInOrder.add(msg);
}
last = msg;
if (!msg.isHeadOfDeliveryChain()) {
continue;
}
if (!msg.isAgreementProtocolMessage()) {
continue;
}
if (msg.isRetractsMessage()) {
removeContentGraphs(conversation, msg);
if (logger.isDebugEnabled()) {
msg.getRetractsRefs().forEach(other -> {
logger.debug("{} retracts {}", msg.getMessageURI(), other.getMessageURI());
});
}
msg.getRetractsRefs().stream().filter(other -> msg != other).filter(other -> other.getSenderAtomURI().equals(msg.getSenderAtomURI())).filter(other -> other.isHeadOfDeliveryChain()).filter(other -> msg.isAfter(other)).forEach(other -> {
if (logger.isDebugEnabled()) {
logger.debug("{} retracts {}: valid, computing effects", msg.getMessageURI(), other.getMessageURI());
}
boolean changedSomething = false;
changedSomething = removeContentGraphs(conversation, other) || changedSomething;
retractedUris.add(other.getMessageURI());
if (other.isProposesMessage() || other.isProposesToCancelMessage()) {
changedSomething = retractProposal(other.getMessageURI()) || changedSomething;
}
if (other.isClaimsMessage()) {
changedSomething = retractClaim(other.getMessageURI()) || changedSomething;
}
if (changedSomething) {
effectsBuilder.retracts(other.getMessageURI());
}
});
if (logger.isDebugEnabled()) {
logger.debug("agreement data: {}", agrDataToString());
}
}
if (msg.isRejectsMessage()) {
removeContentGraphs(conversation, msg);
if (logger.isDebugEnabled()) {
msg.getRejectsRefs().forEach(other -> {
logger.debug("{} rejects {}", msg.getMessageURI(), other.getMessageURI());
});
}
msg.getRejectsRefs().stream().filter(other -> msg != other).filter(other -> other.isProposesMessage() || other.isProposesToCancelMessage() || other.isClaimsMessage()).filter(other -> other.isHeadOfDeliveryChain()).filter(other -> !other.getSenderAtomURI().equals(msg.getSenderAtomURI())).filter(other -> msg.isAfter(other)).filter(other -> {
// Resolution: neither statement has any effect.
return !msg.accepts(other);
}).forEach(other -> {
if (logger.isDebugEnabled()) {
logger.debug("{} rejects {}: valid, computing effects", msg.getMessageURI(), other.getMessageURI());
}
boolean changedSomething = false;
if (other.isProposesMessage() || other.isProposesToCancelMessage()) {
changedSomething = rejectProposal(other.getMessageURI()) || changedSomething;
}
if (other.isClaimsMessage()) {
changedSomething = rejectClaim(other.getMessageURI()) || changedSomething;
}
if (changedSomething) {
effectsBuilder.rejects(other.getMessageURI());
}
});
if (logger.isDebugEnabled()) {
logger.debug("agreement data: {}", agrDataToString());
}
}
if (msg.isProposesMessage()) {
if (logger.isDebugEnabled()) {
msg.getProposesRefs().forEach(other -> {
logger.debug("{} proposes {}", msg.getMessageURI(), other.getMessageURI());
});
}
Model proposalContent = ModelFactory.createDefaultModel();
msg.getProposesRefs().stream().filter(other -> msg != other).filter(other -> other.isHeadOfDeliveryChain()).filter(other -> msg.isAfter(other)).forEach(other -> {
if (logger.isDebugEnabled()) {
logger.debug("{} proposes {}: valid, computing effects", msg.getMessageURI(), other.getMessageURI());
}
boolean changedSomething = propose(conversationDataset, other.getContentGraphs(), proposalContent);
if (changedSomething) {
effectsBuilder.proposes(other.getMessageURI());
}
});
pendingProposals.addNamedModel(msg.getMessageURI().toString(), proposalContent);
if (logger.isDebugEnabled()) {
logger.debug("agreement data: {}", agrDataToString());
}
}
if (msg.isProposesToCancelMessage()) {
if (logger.isDebugEnabled()) {
msg.getProposesToCancelRefs().forEach(other -> {
logger.debug("{} proposesToCancel {}", msg.getMessageURI(), other.getMessageURI());
});
}
Model proposeToCancelContent = ModelFactory.createDefaultModel();
msg.getProposesToCancelRefs().stream().filter(other -> msg != other).filter(other -> other.isHeadOfDeliveryChain()).filter(toCancel -> msg.isAfter(toCancel)).forEach(other -> {
if (logger.isDebugEnabled()) {
logger.debug("{} proposesToCancel {}: valid, computing effects", msg.getMessageURI(), other.getMessageURI());
}
boolean changedSomething = propose(conversationDataset, other.getContentGraphs(), proposeToCancelContent);
if (changedSomething) {
effectsBuilder.proposesToCancel(other.getMessageURI());
}
});
pendingProposals.addNamedModel(msg.getMessageURI().toString(), proposeToCancelContent);
if (logger.isDebugEnabled()) {
logger.debug("agreement data: {}", agrDataToString());
}
}
if (msg.isClaimsMessage()) {
if (logger.isDebugEnabled()) {
msg.getClaimsRefs().forEach(other -> {
logger.debug("{} claims {}", msg.getMessageURI(), other.getMessageURI());
});
}
Model claimContent = ModelFactory.createDefaultModel();
msg.getClaimsRefs().stream().filter(other -> msg != other).filter(other -> other.isHeadOfDeliveryChain()).filter(other -> msg.isAfter(other)).forEach(other -> {
if (logger.isDebugEnabled()) {
logger.debug("{} claims {}: valid, computing effects", msg.getMessageURI(), other.getMessageURI());
}
boolean changedSomething = claim(conversationDataset, other.getContentGraphs(), claimContent);
if (changedSomething) {
effectsBuilder.claims(other.getMessageURI());
}
});
claims.addNamedModel(msg.getMessageURI().toString(), claimContent);
if (logger.isDebugEnabled()) {
logger.debug("agreement data: {}", agrDataToString());
}
}
if (msg.isAcceptsMessage()) {
if (logger.isDebugEnabled()) {
msg.getAcceptsRefs().forEach(other -> {
logger.debug("{} accepts {}", msg.getMessageURI(), other.getMessageURI());
});
}
msg.getAcceptsRefs().stream().filter(other -> msg != other).filter(other -> other.isHeadOfDeliveryChain()).filter(other -> !other.getSenderAtomURI().equals(msg.getSenderAtomURI())).filter(other -> msg.isAfter(other)).filter(other -> {
// Resolution: neither statement has any effect.
return !msg.rejects(other);
}).forEach(other -> {
if (logger.isDebugEnabled()) {
logger.debug("{} accepts {}: valid, computing effects", msg.getMessageURI(), other.getMessageURI());
}
boolean changedSomething = false;
if (other.isProposesMessage() || other.isProposesToCancelMessage()) {
changedSomething = acceptProposal(other.getMessageURI()) || changedSomething;
}
if (other.isClaimsMessage()) {
changedSomething = acceptClaim(other.getMessageURI()) || changedSomething;
}
if (changedSomething) {
effectsBuilder.accepts(other.getMessageURI(), other.getProposesToCancel().stream().collect(Collectors.toSet()));
}
});
if (logger.isDebugEnabled()) {
logger.debug("agreement data: {}", agrDataToString());
}
}
msg.setEffects(effectsBuilder.build());
if (logger.isDebugEnabled() && !msg.getEffects().isEmpty()) {
logger.debug("Effects of message {} : {}", msg.getMessageURI(), msg.getEffects());
}
}
if (logger.isDebugEnabled()) {
logger.debug("messages in the order they were processed:");
if (processedInOrder != null) {
processedInOrder.stream().forEach(x -> logger.debug(x.toString()));
}
logger.debug("finished conversation analysis for high-level protocols");
}
pendingProposals.commit();
agreements.commit();
cancelledAgreements.commit();
rejected.commit();
claims.commit();
conversationDataset.end();
}
Aggregations