package xdi2.messaging.container.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xdi2.core.Graph;
import xdi2.core.Node;
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.XDIStatementUtil;
import xdi2.messaging.container.contributor.Contributor;
import xdi2.messaging.container.contributor.ContributorMap;
import xdi2.messaging.container.contributor.ContributorMount;
import xdi2.messaging.container.contributor.ContributorResult;
import xdi2.messaging.container.contributor.ContributorMap.ContributorFound;
import xdi2.messaging.container.exceptions.Xdi2MessagingException;
import xdi2.messaging.container.execution.ExecutionContext;
import xdi2.messaging.operations.Operation;
public class ContributorExecutor {
private static final Logger log = LoggerFactory.getLogger(ContributorExecutor.class);
private ContributorExecutor() {
}
/*
* Methods for executing contributors
*/
public static ContributorResult executeContributorsAddress(ContributorMap contributorMap, XDIAddress[] contributorXDIAddresses, XDIAddress contributorsAddress, XDIAddress relativeTargetXDIAddress, Operation operation, Graph operationResultGraph, ExecutionContext executionContext) throws Xdi2MessagingException {
ContributorResult contributorResultXDIAddress = ContributorResult.DEFAULT;
// find an address with contributors
XDIAddress relativeNodeXDIAddress = relativeTargetXDIAddress;
List<ContributorFound> contributorFounds = new ArrayList<ContributorFound> ();
contributorFounds.addAll(findHigherContributors(contributorMap, contributorsAddress, relativeNodeXDIAddress));
contributorFounds.addAll(findLowerContributors(contributorMap, contributorsAddress, relativeNodeXDIAddress));
if (contributorFounds.size() == 0) return ContributorResult.DEFAULT;
if (log.isDebugEnabled()) log.debug("For relative target address: " + relativeTargetXDIAddress + " found contributors: " + contributorFounds);
for (ContributorFound contributorFound : contributorFounds) {
XDIAddress contributorXDIAddress = contributorFound.getContributorXDIAddress();
Contributor contributor = contributorFound.getContributor();
// check mount
ContributorMount contributorMount = contributorFound.getContributor().getContributorMount();
if (contributorMount != null &&
contributorMount.operationXDIAddresses().length > 0 &&
! Arrays.asList(contributorMount.operationXDIAddresses()).contains(operation.getOperationXDIAddress())) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (doesn't like operation) " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorXDIAddress + " and relative target address " + relativeTargetXDIAddress + ".");
continue;
}
// skip the contributor?
if (contributor.skip(executionContext)) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (disabled) " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorXDIAddress + " and relative target address " + relativeTargetXDIAddress + ".");
continue;
}
// calculate next addresses
XDIAddress nextRelativeTargetXDIAddress = relativeTargetXDIAddress == null ? null : XDIAddressUtil.removeStartXDIAddress(relativeTargetXDIAddress, contributorXDIAddress);
XDIAddress nextRelativeNodeXDIAddress = nextRelativeTargetXDIAddress;
XDIAddress[] nextContributorXDIAddresses = Arrays.copyOf(contributorXDIAddresses, contributorXDIAddresses.length + 1);
nextContributorXDIAddresses[nextContributorXDIAddresses.length - 1] = contributorXDIAddress;
XDIAddress nextContributorsXDIAddress = XDIAddressUtil.concatXDIAddresses(nextContributorXDIAddresses);
// execute the contributor
if (log.isDebugEnabled()) log.debug("Executing contributor " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorXDIAddress + " and relative target address " + relativeTargetXDIAddress + "." + " Next contributor chain address is " + nextContributorsXDIAddress + ", and next relative target address is " + nextRelativeTargetXDIAddress + ".");
try {
executionContext.pushContributor(contributor, "Contributor: address: " + nextRelativeTargetXDIAddress + " / " + nextContributorsXDIAddress);
// execute sub-contributors (address)
if (! contributor.getContributors().isEmpty()) {
ContributorResult contributorResult = executeContributorsAddress(contributor.getContributors(), nextContributorXDIAddresses, nextContributorsXDIAddress, nextRelativeTargetXDIAddress, operation, operationResultGraph, executionContext);
contributorResultXDIAddress = contributorResultXDIAddress.or(contributorResult);
if (contributorResult.isSkipParentContributors()) {
if (log.isDebugEnabled()) log.debug("Skipping parent contributors according to sub-contributors (address).");
return contributorResultXDIAddress;
}
}
// execute contributor (address)
Graph tempResultGraph = MemoryGraphFactory.getInstance().openGraph();
ContributorResult contributorResult = contributor.executeOnAddress(nextContributorXDIAddresses, nextContributorsXDIAddress, nextRelativeTargetXDIAddress, operation, tempResultGraph, executionContext);
contributorResultXDIAddress = contributorResultXDIAddress.or(contributorResult);
XDIAddress tempNodeXDIAddress = XDIAddressUtil.concatXDIAddresses(nextContributorsXDIAddress, nextRelativeNodeXDIAddress);
Node tempNode = tempResultGraph.getDeepNode(tempNodeXDIAddress, true);
if (tempNode != null) CopyUtil.copyNode(tempNode, operationResultGraph, null);
if (contributorResult.isSkipSiblingContributors()) {
if (log.isDebugEnabled()) log.debug("Skipping sibling contributors (address) according to " + contributor.getClass().getSimpleName() + ".");
return contributorResultXDIAddress;
}
} catch (Exception ex) {
throw executionContext.processException(ex);
} finally {
executionContext.popContributor();
}
}
// done
return contributorResultXDIAddress;
}
public static ContributorResult executeContributorsStatement(ContributorMap contributorMap, XDIAddress contributorAddresses[], XDIAddress contributorsAddress, XDIStatement relativeTargetXDIStatement, Operation operation, Graph operationResultGraph, ExecutionContext executionContext) throws Xdi2MessagingException {
ContributorResult contributorResultXDIStatement = ContributorResult.DEFAULT;
// find an address with contributors
XDIAddress relativeNodeXDIAddress = relativeTargetXDIStatement == null ? null : relativeTargetXDIStatement.getContextNodeXDIAddress();
List<ContributorFound> contributorFounds = new ArrayList<ContributorFound> ();
contributorFounds.addAll(findHigherContributors(contributorMap, contributorsAddress, relativeNodeXDIAddress));
if (contributorFounds.size() == 0) return ContributorResult.DEFAULT;
if (log.isDebugEnabled()) log.debug("For relative target statement: " + relativeTargetXDIStatement + " found contributors: " + contributorFounds);
for (ContributorFound contributorFound : contributorFounds) {
XDIAddress contributorAddress = contributorFound.getContributorXDIAddress();
Contributor contributor = contributorFound.getContributor();
// check mount
ContributorMount contributorMount = contributorFound.getContributor().getContributorMount();
if (contributorMount != null &&
contributorMount.operationXDIAddresses().length > 0 &&
! Arrays.asList(contributorMount.operationXDIAddresses()).contains(operation.getOperationXDIAddress())) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (doesn't like operation) " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + ".");
continue;
}
if (relativeTargetXDIStatement.isContextNodeStatement()) {
if (contributorMount != null &&
contributorMount.contextNodeXDIArcs().length > 0 &&
! Arrays.asList(contributorMount.contextNodeXDIArcs()).contains(relativeTargetXDIStatement.getContextNodeXDIArc())) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (doesn't like context node arc " + relativeTargetXDIStatement.getContextNodeXDIArc() + ") " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + ".");
continue;
}
if (contributorMount != null &&
contributorMount.targetXDIAddresses().length > 0 &&
! Arrays.asList(contributorMount.targetXDIAddresses()).contains(relativeTargetXDIStatement.getTargetXDIAddress())) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (doesn't like target context node address " + relativeTargetXDIStatement.getTargetXDIAddress() + ") " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + ".");
continue;
}
}
if (relativeTargetXDIStatement.isRelationStatement()) {
if (contributorMount != null &&
contributorMount.relationXDIAddresses().length > 0 &&
! Arrays.asList(contributorMount.relationXDIAddresses()).contains(relativeTargetXDIStatement.getRelationXDIAddress())) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (doesn't like relation arc " + relativeTargetXDIStatement.getRelationXDIAddress() + ") " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + ".");
continue;
}
if (contributorMount != null &&
contributorMount.targetXDIAddresses().length > 0 &&
! Arrays.asList(contributorMount.targetXDIAddresses()).contains(relativeTargetXDIStatement.getTargetXDIAddress())) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (doesn't like target context node address " + relativeTargetXDIStatement.getTargetXDIAddress() + ") " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + ".");
continue;
}
}
if (relativeTargetXDIStatement.isLiteralStatement()) {
}
// skip contributor?
if (contributor.skip(executionContext)) {
if (log.isDebugEnabled()) log.debug("Skipping contributor (disabled) " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + ".");
continue;
}
// calculate next addresses
XDIStatement nextRelativeTargetXDIStatement = relativeTargetXDIStatement == null ? null : XDIStatementUtil.removeStartXDIStatement(relativeTargetXDIStatement, contributorAddress);
XDIAddress nextRelativeNodeXDIAddress = nextRelativeTargetXDIStatement == null ? null : nextRelativeTargetXDIStatement.getContextNodeXDIAddress();
XDIAddress[] nextContributorAddresses = Arrays.copyOf(contributorAddresses, contributorAddresses.length + 1);
nextContributorAddresses[nextContributorAddresses.length - 1] = contributorAddress;
XDIAddress nextContributorsAddress = XDIAddressUtil.concatXDIAddresses(nextContributorAddresses);
// execute the contributor
if (log.isDebugEnabled()) log.debug("Executing contributor " + contributor.getClass().getSimpleName() + " with operation " + operation.getOperationXDIAddress() + " on contributor address " + contributorAddress + " and relative target statement " + relativeTargetXDIStatement + "." + " Next contributor chain address is " + nextContributorsAddress + ", and next relative target statement is " + nextRelativeTargetXDIStatement + ".");
try {
executionContext.pushContributor(contributor, "Contributor: statement: " + nextRelativeTargetXDIStatement + " / " + nextContributorsAddress);
// execute sub-contributors (statement)
if (! contributor.getContributors().isEmpty()) {
ContributorResult contributorResult = executeContributorsStatement(contributor.getContributors(), nextContributorAddresses, nextContributorsAddress, nextRelativeTargetXDIStatement, operation, operationResultGraph, executionContext);
contributorResultXDIStatement = contributorResultXDIStatement.or(contributorResult);
if (contributorResult.isSkipParentContributors()) {
if (log.isDebugEnabled()) log.debug("Skipping parent contributors according to sub-contributors (statement).");
return contributorResultXDIStatement;
}
}
// execute contributor (statement)
Graph tempResultGraph = MemoryGraphFactory.getInstance().openGraph();
ContributorResult contributorResult = contributor.executeOnStatement(nextContributorAddresses, nextContributorsAddress, nextRelativeTargetXDIStatement, operation, operationResultGraph, executionContext);
contributorResultXDIStatement = contributorResultXDIStatement.or(contributorResult);
XDIAddress tempNodeXDIAddress = XDIAddressUtil.concatXDIAddresses(nextContributorsAddress, nextRelativeNodeXDIAddress);
Node tempNode = tempResultGraph.getDeepNode(tempNodeXDIAddress, true);
if (tempNode != null) CopyUtil.copyNode(tempNode, operationResultGraph, null);
if (contributorResult.isSkipSiblingContributors()) {
if (log.isDebugEnabled()) log.debug("Skipping sibling contributors (statement) according to " + contributor.getClass().getSimpleName() + ".");
return contributorResultXDIStatement;
}
} catch (Exception ex) {
throw executionContext.processException(ex);
} finally {
executionContext.popContributor();
}
}
// done
return contributorResultXDIStatement;
}
/*
* Methods for finding contributors
*/
public static List<ContributorFound> findHigherContributors(ContributorMap contributorMap, XDIAddress contributorsXDIAddress, XDIAddress relativeNodeXDIAddress) {
if (contributorMap.isEmpty()) return new ArrayList<ContributorFound> ();
List<ContributorFound> higherContributors = new ArrayList<ContributorFound> ();
if (relativeNodeXDIAddress == null) {
} else {
for (Map.Entry<XDIAddress, List<Contributor>> contributorEntry : contributorMap.entrySet()) {
XDIAddress nextContributorXDIAddress = contributorEntry.getKey();
XDIAddress[] matched = XDIAddressUtil.startsWithXDIAddress(XDIAddressUtil.concatXDIAddresses(contributorsXDIAddress, relativeNodeXDIAddress), XDIAddressUtil.concatXDIAddresses(contributorsXDIAddress, nextContributorXDIAddress), false, true);
if (matched == null) continue;
XDIAddress matchedRelativeNodeXDIAddress = XDIAddressUtil.localXDIAddress(matched[0], - contributorsXDIAddress.getNumXDIArcs());
XDIAddress matchedNextContributorXDIAddress = XDIAddressUtil.localXDIAddress(matched[1], - contributorsXDIAddress.getNumXDIArcs());
XDIAddress contributorXDIAddress = matchedRelativeNodeXDIAddress;
List<Contributor> contributors = contributorEntry.getValue();
for (Contributor contributor : contributors) higherContributors.add(new ContributorFound(contributorXDIAddress, contributor));
}
}
if (higherContributors.isEmpty()) {
if (log.isDebugEnabled()) log.debug("Finding higher contributors for " + relativeNodeXDIAddress + ": No matches.");
} else {
if (log.isDebugEnabled()) log.debug("Finding higher contributors for " + relativeNodeXDIAddress + ": Matches at " + higherContributors);
}
return higherContributors;
}
public static List<ContributorFound> findLowerContributors(ContributorMap contributorMap, XDIAddress contributorsXDIAddress, XDIAddress relativeNodeXDIAddress) {
if (contributorMap.isEmpty()) return new ArrayList<ContributorFound> ();
List<ContributorFound> lowerContributors = new ArrayList<ContributorFound> ();
if (relativeNodeXDIAddress == null) {
for (Map.Entry<XDIAddress, List<Contributor>> contributorEntry : contributorMap.entrySet()) {
XDIAddress nextContributorXDIAddress = contributorEntry.getKey();
XDIAddress contributorXDIAddress = nextContributorXDIAddress;
List<Contributor> contributors = contributorEntry.getValue();
for (Contributor contributor : contributors) lowerContributors.add(new ContributorFound(contributorXDIAddress, contributor));
}
} else {
for (Map.Entry<XDIAddress, List<Contributor>> contributorEntry : contributorMap.entrySet()) {
XDIAddress nextContributorXDIAddress = contributorEntry.getKey();
XDIAddress[] matched = XDIAddressUtil.startsWithXDIAddress(XDIAddressUtil.concatXDIAddresses(contributorsXDIAddress, nextContributorXDIAddress), XDIAddressUtil.concatXDIAddresses(contributorsXDIAddress, relativeNodeXDIAddress), true, false);
if (matched == null) continue;
XDIAddress matchedRelativeNodeXDIAddress = XDIAddressUtil.localXDIAddress(matched[1], - contributorsXDIAddress.getNumXDIArcs());
XDIAddress matchedNextContributorXDIAddress = XDIAddressUtil.localXDIAddress(matched[0], - contributorsXDIAddress.getNumXDIArcs());
if (matchedNextContributorXDIAddress.equals(nextContributorXDIAddress)) continue;
XDIAddress contributorLocalXDIAddress = XDIAddressUtil.localXDIAddress(nextContributorXDIAddress, nextContributorXDIAddress.getNumXDIArcs() - matchedNextContributorXDIAddress.getNumXDIArcs());
XDIAddress contributorXDIAddress = XDIAddressUtil.concatXDIAddresses(matchedRelativeNodeXDIAddress, contributorLocalXDIAddress);
List<Contributor> contributors = contributorEntry.getValue();
for (Contributor contributor : contributors) lowerContributors.add(new ContributorFound(contributorXDIAddress, contributor));
}
}
if (lowerContributors.isEmpty()) {
if (log.isDebugEnabled()) log.debug("Finding lower contributors for " + relativeNodeXDIAddress + ": No matches.");
} else {
if (log.isDebugEnabled()) log.debug("Finding lower contributors for " + relativeNodeXDIAddress + ": Matches at " + lowerContributors);
}
return lowerContributors;
}
}