/* * 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; import org.arastreju.sge.context.Context; import org.arastreju.sge.eh.ArastrejuRuntimeException; import org.arastreju.sge.eh.ErrorCodes; import org.arastreju.sge.model.DetachedStatement; import org.arastreju.sge.model.ResourceID; import org.arastreju.sge.model.SimpleResourceID; import org.arastreju.sge.model.Statement; import org.arastreju.sge.model.nodes.ResourceNode; import org.arastreju.sge.model.nodes.SemanticNode; import org.arastreju.sge.model.nodes.views.SNBoolean; import org.arastreju.sge.model.nodes.views.SNScalar; import org.arastreju.sge.model.nodes.views.SNText; import org.arastreju.sge.naming.QualifiedName; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; /** * <p> * Utility class with static methods for Semantic Network OPerationS. * </p> * * <p> * Created Apr 29, 2011 * </p> * * @author Oliver Tigges */ public class SNOPS { // -- TRANSFORMATION ---------------------------------- public static String uri(final ResourceID rid){ return rid.toURI(); } public static QualifiedName qualify(final String uri){ return QualifiedName.create(uri); } public static ResourceID id(final QualifiedName qn){ return new SimpleResourceID(qn); } /** * @param node The node. * @return An isolated ID object. */ public static ResourceID id(final ResourceNode node) { return new SimpleResourceID(node.getQualifiedName()); } /** * Creates a string representation for given node. For a resource node this * will be the URI. * @param node The node. * @return The string representation. */ public static String string(final SemanticNode node) { if (node == null) { return null; } else if (node.isValueNode()) { return node.asValue().getStringValue(); } else { return node.asResource().toURI(); } } /** * Creates a date from given node, which must be a value node. * @param node The node. * @return The string representation. */ public static Date date(final SemanticNode node) { if (node == null) { return null; } else if (node.isValueNode()) { return node.asValue().getTimeValue(); } else { throw new IllegalArgumentException("Cannot convert a resource node to a date value."); } } /** * Converts a semantic node into resource node unless it is null or a value node. * @param node The node. * @return The corresponding resource node or null; */ public static ResourceNode resource(SemanticNode node) { if (node == null || node.isValueNode()) { return null; } else { return node.asResource(); } } // -- ASSOCIATIONS ------------------------------------- public static Set<Statement> associations(final ResourceNode subject, final ResourceID predicate) { final Set<Statement> result = new HashSet<Statement>(); for (Statement assoc : subject.getAssociations()) { if (predicate.equals(assoc.getPredicate())) { result.add(assoc); } } return result; } /** * Fetch the first association corresponding to given predicate. * @param subject The subject. * @param predicate The predicate. * @return The first matching association or null. */ public static Statement fetchAssociation(final ResourceNode subject, final ResourceID predicate) { for (Statement assoc : subject.getAssociations()) { if (predicate.equals(assoc.getPredicate())) { return assoc; } } return null; } /** * Fetch the only association corresponding to given predicate. * @param subject The subject. * @param predicate The predicate. * @return The single association or null. * @throws ArastrejuRuntimeException if more than one association of given predicate present. */ public static Statement singleAssociation(final ResourceNode subject, final ResourceID predicate) { Set<Statement> associations = associations(subject, predicate); if (associations.isEmpty()) { return null; } else if (associations.size() > 1) { throw new ArastrejuRuntimeException(ErrorCodes.GENERAL_RUNTIME_ERROR, "Expected only one association with predicate '" + predicate + "' but found: " + associations); } else { return associations.iterator().next(); } } // -- OBJECTS ----------------------------------------- /** * Fetch the first association's object corresponding to given predicate. * @param subject The subject. * @param predicate The predicate. * @return The first matching object or null. */ public static SemanticNode fetchObject(final ResourceNode subject, final ResourceID predicate) { Set<Statement> associations = associations(subject, predicate); if (associations.isEmpty()) { return null; } else { return associations.iterator().next().getObject(); } } /** * Fetch the first association's object corresponding to given predicate. * @param subject The subject. * @param predicate The predicate. * @return The first matching object or null. */ public static ResourceNode fetchObjectAsResource(final ResourceNode subject, final ResourceID predicate) { for (Statement statement : subject.getAssociations()) { if (predicate.equals(statement.getPredicate()) && statement.getObject().isResourceNode()) { return statement.getObject().asResource(); } } return null; } /** * Fetch the only association corresponding to given predicate. * @param subject The subject. * @param predicate The predicate. * @return The single association or null. * @throws ArastrejuRuntimeException if more than one association of given predicate present. */ public static SemanticNode singleObject(final ResourceNode subject, final ResourceID predicate) { final Statement association = singleAssociation(subject, predicate); if (association != null) { return association.getObject(); } else { return null; } } public static Set<SemanticNode> objects(final ResourceNode subject, final ResourceID predicate){ if (subject == null) { return Collections.emptySet(); } return objects(associations(subject, predicate)); } public static Set<ResourceNode> objectsAsResources(final ResourceNode subject, final ResourceID predicate){ if (subject == null) { return Collections.emptySet(); } final Set<ResourceNode> result = new HashSet<ResourceNode>(); for (Statement assoc : subject.getAssociations()) { if (assoc.getPredicate().equals(predicate) && assoc.getObject().isResourceNode()) { result.add(assoc.getObject().asResource()); } } return result; } public static Set<SemanticNode> objects(final Collection<Statement> assocs){ final Set<SemanticNode> result = new HashSet<SemanticNode>(assocs.size()); for (Statement assoc : assocs) { result.add(assoc.getObject()); } return result; } public static Set<ResourceNode> objectsAsResources(final Collection<Statement> assocs){ final Set<ResourceNode> result = new HashSet<ResourceNode>(assocs.size()); for (Statement assoc : assocs) { if (assoc.getObject().isResourceNode()) { result.add(assoc.getObject().asResource()); } } return result; } // -- PREDICATES -------------------------------------- public static Set<ResourceID> predicates(final ResourceNode subject, final ResourceID predicate){ return predicates(associations(subject, predicate)); } public static Set<ResourceID> predicates(final Collection<Statement> assocs){ final Set<ResourceID> result = new HashSet<ResourceID>(assocs.size()); for (Statement assoc : assocs) { result.add(assoc.getPredicate()); } return result; } // -- SUBJECTS ---------------------------------------- public static Set<ResourceID> subjects(final ResourceNode subject, final ResourceID predicate){ return subjects(associations(subject, predicate)); } public static Set<ResourceID> subjects(final Collection<Statement> assocs){ final Set<ResourceID> result = new HashSet<ResourceID>(assocs.size()); for (Statement assoc : assocs) { result.add(assoc.getSubject()); } return result; } // -- MODIFICATIONS ----------------------------------- /** * Create a new associated statement, that will be added to the subject. */ public static Statement associate(final ResourceNode subject, final ResourceID predicate, final SemanticNode object, final Context... ctx){ return subject.addAssociation(predicate, object, ctx); } /** * Assures that the subject has only this object for given predicate. * @param subject The subject. * @param predicate The predicate. * @param object The object to be set. * @param contexts The contexts. */ public static Statement assure(final ResourceNode subject, final ResourceID predicate, final SemanticNode object, final Context... contexts){ final Statement statement = new DetachedStatement(subject, predicate, object, contexts); final Set<Statement> all = associations(subject, predicate); if (all.isEmpty()) { return subject.addAssociation(predicate, object, contexts); } else if (all.contains(statement)) { for (Statement existing : all) { if (!statement.equals(existing)) { subject.removeAssociation(existing); } } return statement; } else { remove(subject, predicate); return subject.addAssociation(predicate, object, contexts); } } /** * Assures that the subject has only this object for given predicate. * @param subject The subject. * @param predicate The predicate. * @param object The object to be set. * @param contexts The contexts. */ public static Statement assure(final ResourceNode subject, final ResourceID predicate, final Object object, final Context... contexts){ final SemanticNode node; if (object instanceof SemanticNode) { node = (SemanticNode) object; } else if (object instanceof String) { node = new SNText((String) object); } else if (object instanceof Integer) { node = new SNScalar((Integer) object); } else if (object instanceof Boolean) { node = new SNBoolean((Boolean) object); } else { throw new IllegalArgumentException("Unsupported value: " + object); } return assure(subject, predicate, node, contexts); } /** * Assures that the subject has only the given objects for this predicate. * @param subject The subject. * @param predicate The predicate. * @param objects The collection of objects to be added. * @param contexts The contexts. */ public static void assure(final ResourceNode subject, final ResourceID predicate, final Collection<? extends SemanticNode> objects, final Context... contexts){ final List<SemanticNode> existing = new ArrayList<SemanticNode>(); // 1st: remove no longer existing for(Statement assoc: associations(subject, predicate)){ if (!objects.contains(assoc.getObject())){ subject.removeAssociation(assoc); } else { existing.add(assoc.getObject()); } } // 2nd: add not yet existing for (SemanticNode current: objects){ if (!existing.contains(current)){ associate(subject, predicate, current, contexts); } } } /** * Remove all associations of given predicate. * @param subject The subject. * @param predicate The predicate. */ public static void remove(final ResourceNode subject, ResourceID predicate) { for(Statement assoc: associations(subject, predicate)) { subject.removeAssociation(assoc); } } /** * Remove all associations of given predicate. * @param subject The subject. * @param predicate The predicate. * @param object The object. * @return boolean indicating if a corresponding relation has been found and removed. */ public static boolean remove(final ResourceNode subject, ResourceID predicate, SemanticNode object) { boolean removed = false; for(Statement assoc: associations(subject, predicate)) { if (assoc.getObject().equals(object)) { subject.removeAssociation(assoc); removed = true; } } return removed; } }