/*
* Copyright (C) 2013 lichtflut Forschungs- und Entwicklungsgesellschaft mbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arastreju.sge.model.nodes.views;
import org.arastreju.sge.SNOPS;
import org.arastreju.sge.apriori.Aras;
import org.arastreju.sge.model.ResourceID;
import org.arastreju.sge.model.Statement;
import org.arastreju.sge.model.associations.HalfStatement;
import org.arastreju.sge.model.nodes.ResourceNode;
import org.arastreju.sge.model.nodes.SNResource;
import org.arastreju.sge.model.nodes.SemanticNode;
import org.arastreju.sge.naming.QualifiedName;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* <p>
* Decorator implementing aras:inheritsFrom.
* </p>
*
* <p>
* Created 19.11.12
* </p>
*
* @author Oliver Tigges
*/
public class InheritedDecorator extends ResourceView {
public static InheritedDecorator from(SemanticNode node) {
if (node instanceof InheritedDecorator) {
return (InheritedDecorator) node;
} else if (node instanceof ResourceNode) {
return new InheritedDecorator((ResourceNode) node);
} else {
return null;
}
}
public static void revoke(ResourceNode node, HalfStatement revokedStmt) {
SemanticNode revokeDef = SNOPS.fetchObject(node, Aras.REVOKES);
if (revokeDef == null) {
revokeDef = new SNResource();
node.addAssociation(Aras.REVOKES, revokeDef);
}
revokeDef.asResource().addAssociation(revokedStmt.getPredicate(), revokedStmt.getObject());
}
// ----------------------------------------------------
public InheritedDecorator() {
}
public InheritedDecorator(ResourceNode resource) {
super(resource);
}
public InheritedDecorator(QualifiedName qn) {
super(qn);
}
// ----------------------------------------------------
@Override
public Set<Statement> getAssociations() {
final Set<Statement> directAssocs = super.getAssociations();
final Set<ResourceNode> inheritors = getInheritors(directAssocs);
if (inheritors.isEmpty()) {
return directAssocs;
}
final Set<Statement> result = new HashSet<Statement>();
// 1st: Add all inherited - excluding revoked
final RevocationDef revocationDef = getRevocationDef();
Set<ResourceID> revokedPredicates = revocationDef.getRevokedPredicates();
Set<HalfStatement> revokedStatements = revocationDef.getRevokedStatements();
for (ResourceNode inheritor : inheritors) {
for (Statement inherited : inheritor.getAssociations()) {
HalfStatement halfStatement = HalfStatement.from(inherited);
if (revokedPredicates.contains(inherited.getPredicate())) {
continue;
}
if (revokedStatements.contains(halfStatement) ) {
continue;
}
result.add(halfStatement.toFullStatement(this, inherited.getMetaInfo().inherit()));
}
}
// 3rd: Add all own statements
result.addAll(directAssocs);
return result;
}
// ----------------------------------------------------
protected Set<ResourceNode> getInheritors() {
return getInheritors(super.getAssociations());
}
protected RevocationDef getRevocationDef() {
return getRevocationDef(super.getAssociations());
}
protected Set<Statement> directAssociations() {
return super.getAssociations();
}
// ----------------------------------------------------
private Set<ResourceNode> getInheritors(Collection<Statement> statements){
final Set<ResourceNode> result = new HashSet<ResourceNode>();
for (Statement assoc : statements) {
if (assoc.getPredicate().equals(Aras.INHERITS_FROM) && assoc.getObject().isResourceNode()) {
result.add(assoc.getObject().asResource());
}
}
// Remove this to avoid cycles
result.remove(this);
return result;
}
private RevocationDef getRevocationDef(Collection<Statement> statements) {
for (Statement statement : statements) {
if (Aras.REVOKES.equals(statement.getPredicate()) && statement.getObject().isResourceNode()) {
return new RevocationDef(statement.getObject().asResource());
}
}
return RevocationDef.EMPTY;
}
// ----------------------------------------------------
private static class RevocationDef extends ResourceView {
private static RevocationDef EMPTY = new RevocationDef();
private RevocationDef(ResourceNode resource) {
super(resource);
}
private RevocationDef() {
}
// ----------------------------------------------------
public Set<ResourceID> getRevokedPredicates() {
Set<ResourceID> predicates = new HashSet<ResourceID>();
for (Statement assoc : getAssociations()) {
if (Aras.ANY.equals(assoc.getObject())) {
predicates.add(assoc.getPredicate());
}
}
return predicates;
}
public Set<HalfStatement> getRevokedStatements() {
// return all statements - also those with aras:Any as object.
Set<Statement> associations = getAssociations();
Set<HalfStatement> result = new HashSet<HalfStatement>(associations.size());
for (Statement current : associations) {
result.add(HalfStatement.from(current));
}
return result;
}
}
}