![JAR search and dependency download from the Maven repository](/logo.png)
org.semanticweb.elk.reasoner.taxonomy.ConcurrentInstanceTaxonomy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elk-reasoner Show documentation
Show all versions of elk-reasoner Show documentation
ELK consequence-based reasoning engine
/*
* #%L
* elk-reasoner
*
* $Id$
* $HeadURL$
* %%
* Copyright (C) 2011 Oxford University Computing Laboratory
* %%
* 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.
* #L%
*/
package org.semanticweb.elk.reasoner.taxonomy;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.log4j.Logger;
import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkEntity;
import org.semanticweb.elk.owl.interfaces.ElkNamedIndividual;
import org.semanticweb.elk.owl.iris.ElkIri;
import org.semanticweb.elk.owl.printers.OwlFunctionalStylePrinter;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceNode;
import org.semanticweb.elk.reasoner.taxonomy.model.TaxonomyNode;
import org.semanticweb.elk.reasoner.taxonomy.model.TaxonomyNodeUtils;
import org.semanticweb.elk.reasoner.taxonomy.model.TypeNode;
import org.semanticweb.elk.reasoner.taxonomy.model.UpdateableBottomNode;
import org.semanticweb.elk.reasoner.taxonomy.model.UpdateableInstanceNode;
import org.semanticweb.elk.reasoner.taxonomy.model.UpdateableTaxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.UpdateableTaxonomyNode;
import org.semanticweb.elk.reasoner.taxonomy.model.UpdateableTypeNode;
import org.semanticweb.elk.util.collections.ArrayHashSet;
import org.semanticweb.elk.util.collections.LazySetUnion;
import org.semanticweb.elk.util.collections.Operations;
import org.semanticweb.elk.util.collections.Operations.FunctorEx;
/**
* Class taxonomy that is suitable for concurrent processing. Taxonomy objects
* are only constructed for consistent ontologies, and some consequences of this
* are hardcoded here.
*
* This class wraps an instance of {@link UpdateableTaxonomy} and lazily
* generates wrappers for its nodes to store direct instances.
*
* @author Yevgeny Kazakov
* @author Frantisek Simancik
* @author Markus Kroetzsch
* @author Pavel Klinov
*/
public class ConcurrentInstanceTaxonomy implements IndividualClassTaxonomy {
// logger for events
private static final Logger LOGGER_ = Logger
.getLogger(ConcurrentInstanceTaxonomy.class);
/** thread safe map from class IRIs to individual nodes */
private final ConcurrentMap individualNodeLookup_;
/** thread safe set of all individual nodes */
private final Set> allIndividualNodes_;
private final UpdateableTaxonomy classTaxonomy_;
private final ConcurrentMap, UpdateableTypeNodeWrapper> wrapperMap_;
private final TypeNodeWrapper bottom_;
public ConcurrentInstanceTaxonomy() {
this(new ConcurrentClassTaxonomy());
}
public ConcurrentInstanceTaxonomy(UpdateableTaxonomy classTaxonomy) {
this.classTaxonomy_ = classTaxonomy;
this.individualNodeLookup_ = new ConcurrentHashMap();
this.allIndividualNodes_ = Collections
.newSetFromMap(new ConcurrentHashMap, Boolean>());
this.wrapperMap_ = new ConcurrentHashMap, UpdateableTypeNodeWrapper>();
this.bottom_ = new BottomTypeNodeWrapper(classTaxonomy_.getUpdateableBottomNode());
}
/**
* Returns the IRI of the given ELK entity.
*
* @return the IRI of the given ELK entity
*/
static ElkIri getKey(ElkEntity elkEntity) {
return elkEntity.getIri();
}
/**
* Obtain a {@link TypeNode} object for a given {@link ElkClass}, or
* {@code null} if none assigned.
*
* @param elkClass
* @return type node object for elkClass, possibly still incomplete
*/
@Override
public TypeNode getTypeNode(ElkClass elkClass) {
TaxonomyNode node = classTaxonomy_.getNode(elkClass);
if (node == classTaxonomy_.getBottomNode()) {
return bottom_;
}
else {
UpdateableTaxonomyNode taxNode = classTaxonomy_.getUpdateableNode(elkClass);
return getCreateUpdateableTypeNode(taxNode);
}
}
/**
* Obtain a {@link TypeNode} object for a given {@link ElkClass}, or
* {@code null} if none assigned.
*
* @param individual
* @return instance node object for elkClass, possibly still incomplete
*/
@Override
public UpdateableInstanceNode getInstanceNode(
ElkNamedIndividual individual) {
return individualNodeLookup_.get(getKey(individual));
}
@Override
public TaxonomyNode getNode(ElkClass elkClass) {
return getTypeNode(elkClass);
}
@Override
public Set extends TypeNode> getTypeNodes() {
Set extends TypeNode> updateableNodes = Operations.map(classTaxonomy_.getUpdateableNodes(), functor_);
return new LazySetUnion>(updateableNodes, Collections.singleton(bottom_));
}
@Override
public Set extends InstanceNode> getInstanceNodes() {
return Collections.unmodifiableSet(allIndividualNodes_);
}
@Override
public Set extends TaxonomyNode> getNodes() {
return classTaxonomy_.getNodes();
}
@Override
public IndividualNode getCreateInstanceNode(Collection members) {
// search if some node is already assigned to some member, and if so
// use this node and update its members if necessary
IndividualNode previous = null;
for (ElkNamedIndividual member : members) {
previous = individualNodeLookup_.get(getKey(member));
if (previous == null)
continue;
synchronized (previous) {
if (previous.getMembers().size() < members.size())
previous.setMembers(members);
else
return previous;
}
//updating the index
for (ElkNamedIndividual newMember : members) {
individualNodeLookup_.put(getKey(newMember), previous);
}
return previous;
}
// TODO: avoid code duplication, the same technique is used for creating
// non-bottom class nodes!
IndividualNode node = new IndividualNode(members);
// we first assign the node to the canonical member to avoid
// concurrency problems
ElkNamedIndividual canonical = node.getCanonicalMember();
previous = individualNodeLookup_.putIfAbsent(getKey(canonical), node);
if (previous != null) {
return previous;
}
allIndividualNodes_.add(node);
if (LOGGER_.isTraceEnabled()) {
LOGGER_.trace(OwlFunctionalStylePrinter.toString(canonical) + ": node created");
}
for (ElkNamedIndividual member : members) {
if (member != canonical)
individualNodeLookup_.put(getKey(member), node);
}
return node;
}
@Override
public boolean removeInstanceNode(ElkNamedIndividual instance) {
IndividualNode node = individualNodeLookup_.get(getKey(instance));
if (node != null) {
if (LOGGER_.isTraceEnabled()) {
LOGGER_.trace("Removing the instance node " + node);
}
List> directTypes = new LinkedList>();
synchronized (node) {
for (ElkNamedIndividual individual : node.getMembers()) {
individualNodeLookup_.remove(getKey(individual));
}
allIndividualNodes_.remove(node);
directTypes.addAll(node.getDirectTypeNodes());
}
// detaching the removed instance node from all its direct types
for (UpdateableTypeNode typeNode : directTypes) {
synchronized (typeNode) {
typeNode.removeDirectInstanceNode(node);
}
}
return true;
} else {
return false;
}
}
@Override
public UpdateableTypeNode getUpdateableTypeNode(ElkClass elkClass) {
return getCreateUpdateableTypeNode(classTaxonomy_.getUpdateableNode(elkClass));
}
@Override
public UpdateableTypeNode getCreateTypeNode(Collection members) {
UpdateableTaxonomyNode taxNode = classTaxonomy_.getCreateNode(members);
return getCreateUpdateableTypeNode(taxNode);
}
@Override
public UpdateableTypeNode getTopNode() {
return getUpdateableTopNode();
}
@Override
public UpdateableTypeNode getUpdateableTopNode() {
return getCreateUpdateableTypeNode(classTaxonomy_.getUpdateableTopNode());
}
@Override
public TypeNode getBottomNode() {
return bottom_;
}
@Override
public UpdateableBottomNode getUpdateableBottomNode() {
return classTaxonomy_.getUpdateableBottomNode();
}
@Override
public UpdateableTaxonomyNode getCreateNode(
Collection members) {
return classTaxonomy_.getCreateNode(members);
}
@Override
public boolean addToBottomNode(ElkClass member) {
return classTaxonomy_.addToBottomNode(member);
}
@Override
public boolean removeNode(UpdateableTaxonomyNode node) {
UpdateableTypeNodeWrapper wrapper = wrapperMap_.get(node);
if (wrapper != null && wrapperMap_.remove(node, wrapper)) {
for (UpdateableInstanceNode instanceNode : wrapper.getDirectInstanceNodes()) {
synchronized(instanceNode) {
instanceNode.removeDirectTypeNode(wrapper);
}
}
}
return classTaxonomy_.removeNode(node);
}
@Override
public UpdateableTaxonomyNode getUpdateableNode(ElkClass elkObject) {
return classTaxonomy_.getUpdateableNode(elkObject);
}
@Override
public Set extends UpdateableTaxonomyNode> getUpdateableNodes() {
return classTaxonomy_.getUpdateableNodes();
}
private UpdateableTypeNodeWrapper getCreateUpdateableTypeNode(UpdateableTaxonomyNode taxNode) {
if (taxNode == null) {
return null;
}
synchronized (taxNode) {
UpdateableTypeNodeWrapper wrapper = wrapperMap_.get(taxNode);
if (wrapper == null) {
wrapper = new UpdateableTypeNodeWrapper(taxNode);
wrapperMap_.put(taxNode, wrapper);
}
return wrapper;
}
}
/**
* Transforms updateable taxonomy nodes into updateable type nodes
*/
private final FunctorEx, UpdateableTypeNodeWrapper> functor_ = new FunctorEx, UpdateableTypeNodeWrapper>(){
@Override
public UpdateableTypeNodeWrapper apply(UpdateableTaxonomyNode node) {
return getCreateUpdateableTypeNode(node);
}
@Override
public UpdateableTaxonomyNode deapply(Object element) {
if (element instanceof UpdateableTypeNodeWrapper) {
return ((UpdateableTypeNodeWrapper) element).getNode();
}
else {
return null;
}
}
};
/**
*
* @author Pavel Klinov
*
* [email protected]
*/
private abstract class TypeNodeWrapper implements TypeNode {
protected final TaxonomyNode classNode_;
TypeNodeWrapper(TaxonomyNode node) {
classNode_ = node;
}
@Override
public Set getMembers() {
return classNode_.getMembers();
}
@Override
public ElkClass getCanonicalMember() {
return classNode_.getCanonicalMember();
}
@Override
public Set extends InstanceNode> getDirectInstanceNodes() {
return Collections.emptySet();
}
@Override
public Set extends InstanceNode> getAllInstanceNodes() {
Set> result;
if (!classNode_.getDirectSubNodes().isEmpty()) {
result = new ArrayHashSet>();
Queue> todo = new LinkedList>();
todo.add(this);
while (!todo.isEmpty()) {
TypeNode next = todo.poll();
result.addAll(next.getDirectInstanceNodes());
for (TypeNode nextSubNode : next
.getDirectSubNodes()) {
todo.add(nextSubNode);
}
}
return Collections.unmodifiableSet(result);
} else {
return Collections.unmodifiableSet(getDirectInstanceNodes());
}
}
@Override
public String toString() {
return classNode_.toString();
}
@Override
public int hashCode() {
return classNode_.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TypeNodeWrapper){
return classNode_ == ((TypeNodeWrapper) obj).classNode_;
}
return false;
}
}
/**
*
* @author Pavel Klinov
*
* [email protected]
*/
private class UpdateableTypeNodeWrapper extends TypeNodeWrapper implements UpdateableTypeNode {
/**
* ElkNamedIndividual nodes whose members are instances of the members of
* this node.
*/
private final Set> directInstanceNodes_;
UpdateableTypeNodeWrapper(UpdateableTaxonomyNode node) {
super(node);
this.directInstanceNodes_ = Collections
.newSetFromMap(new ConcurrentHashMap, Boolean>());
}
private UpdateableTaxonomyNode getNode() {
return (UpdateableTaxonomyNode) classNode_;
}
@Override
public Set extends UpdateableInstanceNode> getDirectInstanceNodes() {
return Collections.unmodifiableSet(directInstanceNodes_);
}
@Override
public void addDirectSuperNode(
UpdateableTaxonomyNode superNode) {
getNode().addDirectSuperNode(superNode);
}
@Override
public void addDirectSubNode(UpdateableTaxonomyNode subNode) {
getNode().addDirectSubNode(subNode);
}
@Override
public boolean removeDirectSubNode(
UpdateableTaxonomyNode subNode) {
return getNode().removeDirectSubNode(subNode);
}
@Override
public boolean removeDirectSuperNode(
UpdateableTaxonomyNode superNode) {
return getNode().removeDirectSuperNode(superNode);
}
@Override
public boolean trySetModified(boolean modified) {
return getNode().trySetModified(modified);
}
@Override
public boolean isModified() {
return getNode().isModified();
}
@Override
public Set getDirectUpdateableSubNodes() {
return Operations.map(getNode().getDirectUpdateableSubNodes(), functor_);
}
@Override
public Set getDirectUpdateableSuperNodes() {
return Operations.map(getNode().getDirectUpdateableSuperNodes(), functor_);
}
@Override
public Set extends TypeNodeWrapper> getDirectSuperNodes() {
return getDirectUpdateableSuperNodes();
}
@Override
public Set extends TypeNode> getAllSuperNodes() {
return getDirectUpdateableSuperNodes();
}
@Override
public Set extends TypeNode> getDirectSubNodes() {
Set extends TypeNode> directSubNodes = getDirectUpdateableSubNodes();
return directSubNodes.isEmpty() ? Collections.singleton(getBottomNode()) : directSubNodes;
}
@Override
public Set extends TypeNode> getAllSubNodes() {
Set extends UpdateableTaxonomyNode> subNodes = TaxonomyNodeUtils.getAllUpdateableSubNodes(getNode());
//this node is not the bottom one, so the bottom must be in the set
return new LazySetUnion>(Operations.map(subNodes, functor_), Collections.singleton(getBottomNode()));
}
@Override
public void addDirectInstanceNode( UpdateableInstanceNode instanceNode) {
if (LOGGER_.isTraceEnabled()) {
LOGGER_.trace(getNode() + ": new direct instance-node " + instanceNode);
}
directInstanceNodes_.add(instanceNode);
}
/*
* This method is not thread safe
*/
@Override
public void removeDirectInstanceNode(
UpdateableInstanceNode instanceNode) {
if (LOGGER_.isTraceEnabled()) {
LOGGER_.trace(getNode() + ": direct instance node removed " + instanceNode);
}
directInstanceNodes_.remove(instanceNode);
}
}
/**
*
* @author Pavel Klinov
*
* [email protected]
*/
private class BottomTypeNodeWrapper extends TypeNodeWrapper {
BottomTypeNodeWrapper(UpdateableBottomNode node) {
super(node);
}
private UpdateableBottomNode getNode() {
return (UpdateableBottomNode) classNode_;
}
@Override
public Set extends TypeNode> getDirectSuperNodes() {
return Operations.map(getNode().getDirectUpdateableSuperNodes(), functor_);
}
@Override
public Set extends TypeNode> getAllSuperNodes() {
return Operations.map(TaxonomyNodeUtils.getAllUpdateableSuperNodes(getNode()), functor_);
}
@Override
public Set extends TypeNode> getDirectSubNodes() {
return Collections.emptySet();
}
@Override
public Set extends TypeNode> getAllSubNodes() {
return Collections.emptySet();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy