throws StoreException
{
super.meet(statementPattern);
// keep a reference to the original parent.
QueryModelNode parent = statementPattern.getParentNode();
Var subjectVar = statementPattern.getSubjectVar();
if (handledSubjects.contains(subjectVar)) {
// we have already expanded the query for this particular subject
return;
}
handledSubjects.add(subjectVar);
/*
* Create this pattern:
*
* ?subject ?predicate ?object. (= the original statementPattern)
* OPTIONAL {
* { ?subject foo:accessAttr1 ?accessAttrValue1. }
* UNION
* { ?subject foo:inheritanceProp ?S1 .
* ?S1 foo:accessAttr1 ?accessAttrValue1.
* }
* { ?subject foo:accessAttr2 ?accessAttrValue2. }
* UNION
* { ?subject foo:inheritanceProp ?S2 .
* ?S2 foo:accessAttr1 ?accessAttrValue2.
* }
* ...
* }
*
* or in terms of the algebra:
*
* LeftJoin(
* SP(?subject, ?predicate, ?object),
* Join(
* Union(
* SP(?subject, accessAttr_1, ?accessAttrValue_1),
* Join (
* SP(?subject, inheritProp ?S_1),
* SP(?S_1, acccessAttr_1, ?accessAttrValue_1)
* )),
* Union(
* SP(?subject, accessAttr_2, ?accessAttrValue_2),
* Join (
* SP(?subject, inheritProp ?S_2),
* SP(?S_2, acccessAttr_2, ?accessAttrValue_2)
* )),
* ...
* )
* )
*/
List<URI> attributes = getAccessAttributes();
if (attributes == null || attributes.size() == 0) {
return;
}
// join of the attribute match expressions.
Join joinOfAttributePatterns = new Join();
URI inheritanceProp = getInheritanceProperty();
Var inheritPredVar = new Var("-acl_inherit_pred", inheritanceProp);
int i = 0;
List<Var> attributeVars = new ArrayList<Var>();
for (URI attribute : attributes) {
Var attributeVar = new Var("-acl_attr_" + i++);
attributeVars.add(attributeVar);
Var attributePredVar = new Var("-acl_attr_pred_" + i, attribute);
// SP(?subject, accessAttr_i, ?accessAttrValue_i)
StatementPattern attributePattern = new StatementPattern(subjectVar, attributePredVar,
attributeVar);
if (inheritanceProp != null) {
// create a union expression for this attribute.
Union union = new Union();
union.addArg(attributePattern);
// the join for checking if the access attribute is inherited.
Join inheritJoin = new Join();
Var inheritVar = new Var("-acl_inherited_value" + i);
// SP (?subject, inheritProp, ?S_i)
StatementPattern inheritPattern = new StatementPattern(subjectVar, inheritPredVar, inheritVar);
inheritJoin.addArg(inheritPattern);
// SP (?S_i, accessAttr_i, ?accessAttrValue_i)
StatementPattern inheritAttrPattern = new StatementPattern(inheritVar, attributePredVar,
attributeVar);
inheritJoin.addArg(inheritAttrPattern);
union.addArg(inheritJoin);
joinOfAttributePatterns.addArg(union);
}
else {
// no inheritance: the attribute can be matched with a simple
// statement pattern
joinOfAttributePatterns.addArg(attributePattern);
}
}
TupleExpr expandedPattern = null;
if (joinOfAttributePatterns.getNumberOfArguments() == 1) {
expandedPattern = new LeftJoin(statementPattern, joinOfAttributePatterns.getArg(0));
}
else {
expandedPattern = new LeftJoin(statementPattern, joinOfAttributePatterns);
}
// build an Or-ed set of filter conditions on the status and team.
Or filterConditions = new Or();
/* first condition is that none are bound: this is the case where the subject
* is not a restricted resource (and therefore has no associated attributes)
*
* And(Not(Bound(?acl_attr1)), Not(Bound(?acl_attr_1), ...)
*/
And and = new And();
for (Var attributeVar : attributeVars) {
and.addArg(new Not(new Bound(attributeVar)));
}
if (and.getArgs().size() == 1) {
filterConditions.addArg(and.getArg(0));
}
else {
filterConditions.addArg(and);
}
if (permissions == null) {
List<URI> roles = getRolesForUser(getCurrentUser());
permissions = getAssignedPermissions(roles, ACL.VIEW);
}
// for each permission, we add an additional condition to the filter,
// checking that either
// team, or status, or both match.
for (URI permission : permissions) {
And permissionCondition = new And();
for (int j = 0; j < attributes.size(); j++) {
URI attribute = attributes.get(j);
URI attributePermissionValue = getAttributeValueForPermission(permission, attribute);
Compare attributeValueCompare = null;
if (attributePermissionValue != null) {
attributeValueCompare = new Compare(attributeVars.get(j), new Var("acl_attr_val_" + j,
attributePermissionValue));
permissionCondition.addArg(attributeValueCompare);
}
}
if (permissionCondition.getNumberOfArguments() == 1) {
filterConditions.addArg(permissionCondition.getArg(0));
}
else {
// add the permission-defined condition to the set of Or-ed
// filter conditions.
filterConditions.addArg(permissionCondition);
}
}
// set the filter conditions on the query pattern
if (filterConditions.getNumberOfArguments() == 1) {
// no second argument in the or
expandedPattern = new Filter(expandedPattern, filterConditions.getArg(0));
}
else {
expandedPattern = new Filter(expandedPattern, filterConditions);
}
// expand the query.
parent.replaceChildNode(statementPattern, expandedPattern);
}