package xdi2.messaging.container.interceptor.impl;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xdi2.core.ContextNode;
import xdi2.core.Graph;
import xdi2.core.Relation;
import xdi2.core.constants.XDIConstants;
import xdi2.core.constants.XDIDictionaryConstants;
import xdi2.core.features.equivalence.Equivalence;
import xdi2.core.impl.memory.MemoryGraphFactory;
import xdi2.core.syntax.XDIAddress;
import xdi2.core.syntax.XDIStatement;
import xdi2.core.util.CopyUtil;
import xdi2.core.util.XDIAddressUtil;
import xdi2.core.util.iterators.IteratorListMaker;
import xdi2.messaging.Message;
import xdi2.messaging.MessageEnvelope;
import xdi2.messaging.constants.XDIMessagingConstants;
import xdi2.messaging.container.MessagingContainer;
import xdi2.messaging.container.Prototype;
import xdi2.messaging.container.exceptions.Xdi2MessagingException;
import xdi2.messaging.container.execution.ExecutionContext;
import xdi2.messaging.container.execution.ExecutionResult;
import xdi2.messaging.container.impl.AbstractMessagingContainer;
import xdi2.messaging.container.interceptor.InterceptorResult;
import xdi2.messaging.container.interceptor.MessageInterceptor;
import xdi2.messaging.container.interceptor.OperationInterceptor;
import xdi2.messaging.container.interceptor.TargetInterceptor;
import xdi2.messaging.container.interceptor.impl.linkcontract.LinkContractInterceptor;
import xdi2.messaging.operations.GetOperation;
import xdi2.messaging.operations.Operation;
/**
* This interceptor handles $ref and $rep relations.
*
* @author markus
*/
public class RefInterceptor extends AbstractInterceptor<MessagingContainer> implements MessageInterceptor, OperationInterceptor, TargetInterceptor, Prototype<RefInterceptor> {
private static final Logger log = LoggerFactory.getLogger(RefInterceptor.class);
/*
* Prototype
*/
@Override
public RefInterceptor instanceFor(PrototypingContext prototypingContext) {
// done
return this;
}
/*
* Init and shutdown
*/
@Override
public void init(MessagingContainer messagingContainer) throws Exception {
super.init(messagingContainer);
if (! (messagingContainer instanceof AbstractMessagingContainer)) throw new Xdi2MessagingException("Can only add this interceptor to an AbstractMessagingContainer", null, null);
}
/*
* MessageInterceptor
*/
@Override
public InterceptorResult before(Message message, ExecutionContext executionContext, ExecutionResult executionResult) throws Xdi2MessagingException {
resetRefRepRelationsPerMessage(executionContext);
resetCompletedAddressesPerMessage(executionContext);
return InterceptorResult.DEFAULT;
}
@Override
public InterceptorResult after(Message message, ExecutionContext executionContext, ExecutionResult executionResult) throws Xdi2MessagingException {
return InterceptorResult.DEFAULT;
}
/*
* OperationInterceptor
*/
@Override
public InterceptorResult before(Operation operation, Graph operationResultGraph, ExecutionContext executionContext) throws Xdi2MessagingException {
resetRefRepRelationsPerOperation(executionContext);
return InterceptorResult.DEFAULT;
}
@Override
public InterceptorResult after(Operation operation, Graph operationResultGraph, ExecutionContext executionContext) throws Xdi2MessagingException {
// look through the message result to process result $ref/$rep relations
if (operation instanceof GetOperation && operation.getTargetXDIAddress() != null) {
List<Relation> refRepRelations = new IteratorListMaker<Relation> (Equivalence.getAllReferenceAndReplacementRelations(operationResultGraph.getRootContextNode(true))).list();
for (Relation refRepRelation : refRepRelations) {
if (log.isDebugEnabled()) log.debug("In message result: Found $ref/$rep relation: " + refRepRelation);
XDIAddress refRepContextNodeXDIAddress = refRepRelation.getContextNode().getXDIAddress();
// don't follow $ref/$rep relations to target we covered already
boolean skip = false;
for (XDIAddress completedAddress : getCompletedAddressesPerMessage(executionContext)) {
if (refRepContextNodeXDIAddress.equals(completedAddress)) {
if (log.isDebugEnabled()) log.debug("In message result: Skipping $ref/$rep relation " + refRepRelation + " because of already completed address " + completedAddress);
// delete the $rep relation
if (XDIDictionaryConstants.XDI_ADD_REP.equals(refRepRelation.getXDIAddress())) {
refRepRelation.delete();
}
// don't follow this $ref/$rep relation
skip = true;
break;
}
}
if (skip) continue;
// delete the $ref/$rep relation
if (XDIDictionaryConstants.XDI_ADD_REF.equals(refRepRelation.getXDIAddress()) || XDIDictionaryConstants.XDI_ADD_REP.equals(refRepRelation.getXDIAddress())) {
ContextNode refRepTargetContextNode = refRepRelation.followContextNode();
if (refRepTargetContextNode != null) {
refRepRelation.delete();
deleteWhileEmptyAndNoIncomingRelations(refRepTargetContextNode);
}
}
// $get feedback on the source of the $ref/$rep relation
Graph feedbackResultGraph = feedbackGetSourceOfRefRepRelation(refRepContextNodeXDIAddress, operation, executionContext);
// merge the message result
CopyUtil.copyGraph(feedbackResultGraph, operationResultGraph, null);
// done with this $ref/$rep relation
if (log.isDebugEnabled()) log.debug("In message result: After $get feedback on $ref/$rep relation " + refRepRelation + " we now have: " + operationResultGraph);
}
}
// look through the message result to process followed $ref/$rep relations
Relation refRepRelation;
while ((refRepRelation = popRefRepRelationPerOperation(executionContext)) != null) {
// check what to do with this $ref/$rep relation
ContextNode refRepContextNode = refRepRelation.getContextNode();
XDIAddress XDIaddress = refRepRelation.getXDIAddress();
XDIAddress targetXDIAddress = refRepRelation.getTargetXDIAddress();
boolean doReplaceRefRepRelations = XDIDictionaryConstants.XDI_ADD_REP.equals(XDIaddress) || (XDIDictionaryConstants.XDI_ADD_REF.equals(XDIaddress) && Boolean.TRUE.equals(operation.getParameterBoolean(XDIMessagingConstants.XDI_ADD_OPERATION_PARAMETER_DEREF)));
boolean doIncludeRefRelations = (XDIDictionaryConstants.XDI_ADD_REF.equals(XDIaddress) && ! Boolean.TRUE.equals(operation.getParameterBoolean(XDIMessagingConstants.XDI_ADD_OPERATION_PARAMETER_DEREF)));
// replace $ref/$rep relations?
if (doReplaceRefRepRelations) {
ContextNode refRepTargetContextNode = operationResultGraph.getDeepContextNode(targetXDIAddress, true);
if (refRepTargetContextNode != null && ! operationResultGraph.isEmpty()) {
if (log.isDebugEnabled()) log.debug("In message result: Replacing $ref/$rep relation: " + refRepRelation);
Graph tempGraph = MemoryGraphFactory.getInstance().openGraph();
ContextNode tempContextNode = tempGraph.setDeepContextNode(refRepContextNode.getXDIAddress());
CopyUtil.copyContextNodeContents(refRepTargetContextNode, tempContextNode, null);
refRepTargetContextNode.clear();
deleteWhileEmptyAndNoIncomingRelations(refRepTargetContextNode);
CopyUtil.copyGraph(tempGraph, operationResultGraph, null);
tempGraph.close();
} else {
if (log.isDebugEnabled()) log.debug("In message result: Not replacing $ref/$rep relation: " + refRepRelation);
}
}
// include $ref relations?
if (doIncludeRefRelations) {
if (operationResultGraph.containsStatement(refRepRelation.getStatement().getXDIStatement())) {
if (log.isDebugEnabled()) log.debug("In message result: Not including duplicate $ref relation: " + refRepRelation);
} else {
if (log.isDebugEnabled()) log.debug("In message result: Including $ref relation: " + refRepRelation);
CopyUtil.copyStatement(refRepRelation.getStatement(), operationResultGraph, null);
}
}
// done with this $ref/$rep relation
if (log.isDebugEnabled()) log.debug("In message result: We now have: " + operationResultGraph);
}
// done
return InterceptorResult.DEFAULT;
}
/*
* TargetInterceptor
*/
@Override
public XDIAddress targetAddress(XDIAddress targetAddress, Operation operation, Graph operationResultGraph, ExecutionContext executionContext) throws Xdi2MessagingException {
// don't operate on literal node address
if (targetAddress.isLiteralNodeXDIAddress()) return targetAddress;
// remember that we completed this target
if (operation instanceof GetOperation) {
XDIAddress contextNodeXDIAddress = targetAddress;
addCompletedAddressPerMessage(executionContext, contextNodeXDIAddress);
}
// follow any $ref and $rep arcs
XDIAddress followedTargetAddress = followAllRefRepRelations(targetAddress, operation, executionContext);
if (followedTargetAddress != targetAddress) {
targetAddress = followedTargetAddress;
}
// done
return targetAddress;
}
@Override
public XDIStatement targetStatement(XDIStatement targetStatement, Operation operation, Graph operationResultGraph, ExecutionContext executionContext) throws Xdi2MessagingException {
// remember that we completed this target
/*if (operation instanceof GetOperation) {
XDIAddress contextNodeXDIAddress;
if (targetStatement.isContextNodeStatement()) {
contextNodeXDIAddress = targetStatement.gettargetXDIAddress();
addCompletedAddress(executionContext, contextNodeXDIAddress);
}
if (targetStatement.isRelationStatement() &&
( XDIDictionaryConstants.XDI_ADD_REF.equals(targetStatement.getrelationAddress()) ||
XDIDictionaryConstants.XDI_ADD_REP.equals(targetStatement.getrelationAddress()))) {
contextNodeXDIAddress = targetStatement.getContextNodeXDIAddress();
addCompletedAddress(executionContext, contextNodeXDIAddress);
}
}*/
// follow any $ref and $rep arcs
boolean doFollowTargetSubject = true;
if (XDIDictionaryConstants.XDI_ADD_REF.equals(targetStatement.getRelationXDIAddress())) doFollowTargetSubject = false;
if (XDIDictionaryConstants.XDI_ADD_REP.equals(targetStatement.getRelationXDIAddress())) doFollowTargetSubject = false;
if (XDIDictionaryConstants.XDI_ADD_IS_REF.equals(targetStatement.getRelationXDIAddress())) doFollowTargetSubject = false;
if (XDIDictionaryConstants.XDI_ADD_IS_REP.equals(targetStatement.getRelationXDIAddress())) doFollowTargetSubject = false;
boolean doFollowTargetObject = true;
if (XDIDictionaryConstants.XDI_ADD_REF.equals(targetStatement.getRelationXDIAddress())) doFollowTargetObject = false;
if (XDIDictionaryConstants.XDI_ADD_REP.equals(targetStatement.getRelationXDIAddress())) doFollowTargetObject = false;
if (XDIDictionaryConstants.XDI_ADD_IS_REF.equals(targetStatement.getRelationXDIAddress())) doFollowTargetObject = false;
if (XDIDictionaryConstants.XDI_ADD_IS_REP.equals(targetStatement.getRelationXDIAddress())) doFollowTargetObject = false;
if (! targetStatement.isRelationStatement()) doFollowTargetObject = false;
if (targetStatement.isRelationStatement() && XDIConstants.XDI_ADD_COMMON_VARIABLE.equals(targetStatement.getTargetXDIAddress())) doFollowTargetObject = false;
XDIAddress followedTargetSubject = doFollowTargetSubject ? followAllRefRepRelations(targetStatement.getSubject(), operation, executionContext) : targetStatement.getSubject();
Object followedTargetObject = doFollowTargetObject ? followAllRefRepRelations((XDIAddress) targetStatement.getObject(), operation, executionContext) : targetStatement.getObject();
if (followedTargetSubject != targetStatement.getSubject() || followedTargetObject != targetStatement.getObject()) {
targetStatement = XDIStatement.fromComponents(followedTargetSubject, targetStatement.getPredicate(), followedTargetObject);
}
// $ref/$rep relations may have been added now, so let's "forget" them
if (XDIDictionaryConstants.XDI_ADD_REF.equals(targetStatement.getRelationXDIAddress()) ||
XDIDictionaryConstants.XDI_ADD_REP.equals(targetStatement.getRelationXDIAddress())) {
setRefRepRelationPerMessage(executionContext, followedTargetSubject, null);
}
// done
return targetStatement;
}
private static XDIAddress followAllRefRepRelations(XDIAddress contextNodeXDIAddress, Operation operation, ExecutionContext executionContext) throws Xdi2MessagingException {
XDIAddress followedContextNodeXDIAddress = contextNodeXDIAddress;
XDIAddress tempContextNodeXDIAddress;
while (true) {
tempContextNodeXDIAddress = followedContextNodeXDIAddress;
followedContextNodeXDIAddress = followRefRepRelations(tempContextNodeXDIAddress, operation, executionContext);
if (followedContextNodeXDIAddress == tempContextNodeXDIAddress) break;
if (log.isDebugEnabled()) log.debug("In message envelope: Followed " + tempContextNodeXDIAddress + " to " + followedContextNodeXDIAddress);
}
return followedContextNodeXDIAddress;
}
private static XDIAddress followRefRepRelations(XDIAddress contextNodeXDIAddress, Operation operation, ExecutionContext executionContext) throws Xdi2MessagingException {
XDIAddress originalContextNodeXDIAddress = contextNodeXDIAddress;
XDIAddress localAddress = XDIConstants.XDI_ADD_ROOT;
while (! XDIConstants.XDI_ADD_ROOT.equals(contextNodeXDIAddress)) {
// look up $ref/$rep relations
Relation[] refRepRelation = getRefRepRelationPerMessage(executionContext, contextNodeXDIAddress);
Relation refRelation;
Relation repRelation;
// if necessary, $get feedback to find $ref/$rep relations in context
if (refRepRelation == null) {
Graph feedbackResultGraph = feedbackFindRefRepRelationsInContext(contextNodeXDIAddress, operation, executionContext);
// check for $ref/$rep relations in this context
ContextNode contextNode = feedbackResultGraph.getDeepContextNode(contextNodeXDIAddress, false);
refRelation = contextNode == null ? null : Equivalence.getReferenceRelation(contextNode);
repRelation = contextNode == null ? null : Equivalence.getReplacementRelation(contextNode);
// remember $ref/$rep relations in this context
refRepRelation = new Relation[2];
refRepRelation[0] = refRelation;
refRepRelation[1] = repRelation;
setRefRepRelationPerMessage(executionContext, contextNodeXDIAddress, refRepRelation);
} else {
refRelation = refRepRelation[0];
repRelation = refRepRelation[1];
}
// follow $ref/$rep relations
if (refRelation != null) {
ContextNode referenceContextNode = refRelation.followContextNode();
if (referenceContextNode != null) {
if (referenceContextNode.equals(refRelation.getContextNode())) break;
pushRefRepRelationPerOperation(executionContext, refRelation);
return XDIAddressUtil.concatXDIAddresses(referenceContextNode.getXDIAddress(), localAddress);
}
}
if (repRelation != null) {
ContextNode replacementContextNode = repRelation.followContextNode();
if (replacementContextNode != null) {
if (replacementContextNode.equals(repRelation.getContextNode())) break;
pushRefRepRelationPerOperation(executionContext, repRelation);
return XDIAddressUtil.concatXDIAddresses(replacementContextNode.getXDIAddress(), localAddress);
}
}
// continue with parent context node address
localAddress = XDIAddressUtil.concatXDIAddresses(XDIAddressUtil.localXDIAddress(contextNodeXDIAddress, 1), localAddress);
contextNodeXDIAddress = XDIAddressUtil.parentXDIAddress(contextNodeXDIAddress, -1);
if (contextNodeXDIAddress == null) contextNodeXDIAddress = XDIConstants.XDI_ADD_ROOT;
}
// done
return originalContextNodeXDIAddress;
}
/*
* Feedback methods
*/
private static Graph feedbackGetSourceOfRefRepRelation(XDIAddress refRepContextNodeXDIAddress, Operation operation, ExecutionContext executionContext) throws Xdi2MessagingException {
if (log.isDebugEnabled()) log.debug("Initiating $get feedback to get source of $ref/$rep relation: " + refRepContextNodeXDIAddress);
// prepare messaging container
AbstractMessagingContainer messagingContainer = (AbstractMessagingContainer) executionContext.getCurrentMessagingContainer();
// prepare feedback message
MessageEnvelope feedbackMessageEnvelope = new MessageEnvelope();
Message feedbackMessage = feedbackMessageEnvelope.createMessage(operation.getMessage().getSenderXDIAddress());
feedbackMessage.setToPeerRootXDIArc(operation.getMessage().getToPeerRootXDIArc());
Operation feedbackOperation = feedbackMessage.createGetOperation(refRepContextNodeXDIAddress);
if (Boolean.TRUE.equals(operation.getParameterBoolean(XDIMessagingConstants.XDI_ADD_OPERATION_PARAMETER_DEREF))) feedbackOperation.setParameter(XDIMessagingConstants.XDI_ADD_OPERATION_PARAMETER_DEREF, Boolean.TRUE);
// prepare feedback execution result
ExecutionResult feedbackExecutionResult = ExecutionResult.createExecutionResult(feedbackMessageEnvelope);
// feedback
Map<String, Object> operationAttributes = null;
try {
// before feedback: tweak the execution context and messaging container
LinkContractInterceptor linkContractInterceptor = messagingContainer.getInterceptors().getInterceptor(LinkContractInterceptor.class);
if (linkContractInterceptor != null) linkContractInterceptor.setDisabledForOperation(feedbackOperation);
operationAttributes = executionContext.getOperationAttributes();
// execute feedback message
messagingContainer.execute(feedbackOperation, executionContext, feedbackExecutionResult);
} finally {
// after feedback: restore the execution context and messaging container
if (operationAttributes != null) executionContext.setOperationAttributes(operationAttributes);
}
// finish feedback execution result
feedbackExecutionResult.finish();
// done
if (log.isDebugEnabled()) log.debug("Completed $get feedback on source of $ref/$rep relation: " + refRepContextNodeXDIAddress + ", execution result: " + feedbackExecutionResult);
return feedbackExecutionResult.getFinishedOperationResultGraph(feedbackOperation);
}
private static Graph feedbackFindRefRepRelationsInContext(XDIAddress contextNodeXDIAddress, Operation operation, ExecutionContext executionContext) throws Xdi2MessagingException {
if (log.isDebugEnabled()) log.debug("Initiating $get feedback to find $ref/$rep relations in context: " + contextNodeXDIAddress);
// prepare messaging container
AbstractMessagingContainer messagingContainer = (AbstractMessagingContainer) executionContext.getCurrentMessagingContainer();
// prepare feedback messages
MessageEnvelope feedbackMessageEnvelope = new MessageEnvelope();
Message feedbackMessageRef = feedbackMessageEnvelope.createMessage(operation.getMessage().getSenderXDIAddress());
Message feedbackMessageRep = feedbackMessageEnvelope.createMessage(operation.getMessage().getSenderXDIAddress());
feedbackMessageRef.setToPeerRootXDIArc(operation.getMessage().getToPeerRootXDIArc());
feedbackMessageRep.setToPeerRootXDIArc(operation.getMessage().getToPeerRootXDIArc());
Operation feedbackOperationRef = feedbackMessageRef.createGetOperation(XDIStatement.fromRelationComponents(contextNodeXDIAddress, XDIDictionaryConstants.XDI_ADD_REF, XDIConstants.XDI_ADD_COMMON_VARIABLE));
Operation feedbackOperationRep = feedbackMessageRep.createGetOperation(XDIStatement.fromRelationComponents(contextNodeXDIAddress, XDIDictionaryConstants.XDI_ADD_REP, XDIConstants.XDI_ADD_COMMON_VARIABLE));
// prepare feedback execution result
ExecutionResult feedbackExecutionResult = ExecutionResult.createExecutionResult(feedbackMessageEnvelope);
// feedback
Map<String, Object> messageAttributes = null;
Map<String, Object> operationAttributes = null;
try {
// before feedback: tweak the execution context and messaging container
RefInterceptor refInterceptor = messagingContainer.getInterceptors().getInterceptor(RefInterceptor.class);
if (refInterceptor != null) refInterceptor.setDisabledForOperation(feedbackOperationRef);
if (refInterceptor != null) refInterceptor.setDisabledForOperation(feedbackOperationRep);
LinkContractInterceptor linkContractInterceptor = messagingContainer.getInterceptors().getInterceptor(LinkContractInterceptor.class);
if (linkContractInterceptor != null) linkContractInterceptor.setDisabledForOperation(feedbackOperationRef);
if (linkContractInterceptor != null) linkContractInterceptor.setDisabledForOperation(feedbackOperationRep);
messageAttributes = executionContext.getMessageAttributes();
operationAttributes = executionContext.getOperationAttributes();
// execute feedback messages
messagingContainer.execute(feedbackOperationRef, executionContext, feedbackExecutionResult);
messagingContainer.execute(feedbackOperationRep, executionContext, feedbackExecutionResult);
} finally {
// after feedback: restore the execution context and messaging container
if (messageAttributes != null) executionContext.setMessageAttributes(messageAttributes);
if (operationAttributes != null) executionContext.setOperationAttributes(operationAttributes);
}
// finish feedback execution result
feedbackExecutionResult.finish();
// done
if (log.isDebugEnabled()) log.debug("Completed $get feedback to find $ref/$rep relations in context: " + contextNodeXDIAddress + ", execution result: " + feedbackExecutionResult);
return feedbackExecutionResult.makeLightMessagingResponse().getResultGraph();
}
/*
* Helper methods
*/
private static void deleteWhileEmptyAndNoIncomingRelations(ContextNode contextNode) {
ContextNode currentContextNode = contextNode;
ContextNode parentContextNode;
while (currentContextNode.isEmpty() && (! currentContextNode.containsIncomingRelations()) && (! currentContextNode.isRootContextNode())) {
parentContextNode = currentContextNode.getContextNode();
currentContextNode.delete();
currentContextNode = parentContextNode;
}
}
/*
* ExecutionContext helper methods
*/
private static final String EXECUTIONCONTEXT_KEY_REFREPRELATIONS_PER_MESSAGE = RefInterceptor.class.getCanonicalName() + "#refreprelationspermessage";
private static final String EXECUTIONCONTEXT_KEY_REFREPRELATIONS_PER_OPERATION = RefInterceptor.class.getCanonicalName() + "#refreprelationsperoperation";
private static final String EXECUTIONCONTEXT_KEY_COMPLETEDADDRESSES_PER_MESSAGE = RefInterceptor.class.getCanonicalName() + "#completedaddressespermessage";
@SuppressWarnings("unchecked")
private static Map<XDIAddress, Relation[]> getRefRepRelationsPerMessage(ExecutionContext executionContext) {
return (Map<XDIAddress, Relation[]>) executionContext.getMessageAttribute(EXECUTIONCONTEXT_KEY_REFREPRELATIONS_PER_MESSAGE);
}
private static Relation[] getRefRepRelationPerMessage(ExecutionContext executionContext, XDIAddress contextNodeXDIAddress) {
Map<XDIAddress, Relation[]> refRepRelations = getRefRepRelationsPerMessage(executionContext);
Relation[] refRepRelation = refRepRelations.get(contextNodeXDIAddress);
if (log.isDebugEnabled()) log.debug("Get $ref/$rep relation for " + contextNodeXDIAddress + ": " + refRepRelation);
return refRepRelation;
}
private static void setRefRepRelationPerMessage(ExecutionContext executionContext, XDIAddress contextNodeXDIAddress, Relation[] refRepRelation) {
Map<XDIAddress, Relation[]> refRepRelations = getRefRepRelationsPerMessage(executionContext);
refRepRelations.put(contextNodeXDIAddress, refRepRelation);
if (log.isDebugEnabled()) log.debug("Set $ref/$rep relation for " + contextNodeXDIAddress + ": " + refRepRelation);
}
private static void resetRefRepRelationsPerMessage(ExecutionContext executionContext) {
executionContext.putMessageAttribute(EXECUTIONCONTEXT_KEY_REFREPRELATIONS_PER_MESSAGE, new HashMap<XDIAddress, Relation[]> ());
}
@SuppressWarnings("unchecked")
private static Deque<Relation> getRefRepRelationsPerOperation(ExecutionContext executionContext) {
return (Deque<Relation>) executionContext.getOperationAttribute(EXECUTIONCONTEXT_KEY_REFREPRELATIONS_PER_OPERATION);
}
private static Relation popRefRepRelationPerOperation(ExecutionContext executionContext) {
Deque<Relation> refRepRelations = getRefRepRelationsPerOperation(executionContext);
if (refRepRelations.isEmpty()) return null;
Relation refRepRelation = refRepRelations.pop();
if (log.isDebugEnabled()) log.debug("Popping $ref/$rep relation: " + refRepRelation);
return refRepRelation;
}
private static void pushRefRepRelationPerOperation(ExecutionContext executionContext, Relation refRepRelation) {
getRefRepRelationsPerOperation(executionContext).push(refRepRelation);
if (log.isDebugEnabled()) log.debug("Pushing $ref/$rep relation: " + refRepRelation);
}
private static void resetRefRepRelationsPerOperation(ExecutionContext executionContext) {
executionContext.putOperationAttribute(EXECUTIONCONTEXT_KEY_REFREPRELATIONS_PER_OPERATION, new ArrayDeque<Relation> ());
}
@SuppressWarnings("unchecked")
private static Set<XDIAddress> getCompletedAddressesPerMessage(ExecutionContext executionContext) {
return (Set<XDIAddress>) executionContext.getMessageAttribute(EXECUTIONCONTEXT_KEY_COMPLETEDADDRESSES_PER_MESSAGE);
}
private static void addCompletedAddressPerMessage(ExecutionContext executionContext, XDIAddress contextNodeXDIAddress) {
getCompletedAddressesPerMessage(executionContext).add(contextNodeXDIAddress);
if (log.isDebugEnabled()) log.debug("Added completed address: " + contextNodeXDIAddress);
}
private static void resetCompletedAddressesPerMessage(ExecutionContext executionContext) {
executionContext.putMessageAttribute(EXECUTIONCONTEXT_KEY_COMPLETEDADDRESSES_PER_MESSAGE, new HashSet<XDIAddress> ());
}
}