edu.cornell.mannlib.vitro.webapp.dao.jena.VClassDaoJena.java Source code

Java tutorial

Introduction

Here is the source code for edu.cornell.mannlib.vitro.webapp.dao.jena.VClassDaoJena.java

Source

/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package edu.cornell.mannlib.vitro.webapp.dao.jena;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hp.hpl.jena.ontology.AllValuesFromRestriction;
import com.hp.hpl.jena.ontology.AnnotationProperty;
import com.hp.hpl.jena.ontology.CardinalityRestriction;
import com.hp.hpl.jena.ontology.ComplementClass;
import com.hp.hpl.jena.ontology.HasValueRestriction;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.IntersectionClass;
import com.hp.hpl.jena.ontology.MaxCardinalityRestriction;
import com.hp.hpl.jena.ontology.MinCardinalityRestriction;
import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.ontology.ProfileException;
import com.hp.hpl.jena.ontology.Restriction;
import com.hp.hpl.jena.ontology.SomeValuesFromRestriction;
import com.hp.hpl.jena.ontology.UnionClass;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.util.iterator.ClosableIterator;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

import edu.cornell.mannlib.vitro.webapp.beans.Classes2Classes;
import edu.cornell.mannlib.vitro.webapp.beans.Ontology;
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
import edu.cornell.mannlib.vitro.webapp.dao.InsertException;
import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao;
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
import edu.cornell.mannlib.vitro.webapp.web.URLEncoder;

public class VClassDaoJena extends JenaBaseDao implements VClassDao {

    protected static final Log log = LogFactory.getLog(VClassDaoJena.class);
    private boolean isUnderlyingStoreReasoned = false;

    public VClassDaoJena(WebappDaoFactoryJena wadf, boolean isUnderlyingStoreReasoned) {
        super(wadf);
        this.isUnderlyingStoreReasoned = isUnderlyingStoreReasoned;
    }

    @Override
    protected OntModel getOntModel() {
        return getOntModelSelector().getTBoxModel();
    }

    protected boolean isUnderlyingStoreReasoned() {
        return this.isUnderlyingStoreReasoned;
    }

    /* ************************************************** */

    public String getLabelForClass(OntClass cls, boolean withPrefix, boolean forPickList) {
        cls.getModel().enterCriticalSection(Lock.READ);
        try {
            if (cls.isAnon()) {
                if (cls.isRestriction()) {
                    Restriction rest = cls.asRestriction();
                    OntProperty onProperty = rest.getOnProperty();
                    String labelStr = "restriction on " + getLabelOrId(onProperty) + ": ";
                    if (rest.isAllValuesFromRestriction() || rest.isSomeValuesFromRestriction()) {
                        Resource fillerRes = null;
                        if (rest.isAllValuesFromRestriction()) {
                            AllValuesFromRestriction avfRest = rest.asAllValuesFromRestriction();
                            fillerRes = avfRest.getAllValuesFrom();
                            labelStr += "all values from ";
                        } else {
                            SomeValuesFromRestriction svfRest = rest.asSomeValuesFromRestriction();
                            fillerRes = svfRest.getSomeValuesFrom();
                            labelStr += "some values from ";
                        }
                        if (fillerRes.canAs(OntClass.class)) {
                            OntClass avf = fillerRes.as(OntClass.class);
                            labelStr += getLabelForClass(avf, withPrefix, forPickList);
                        } else {
                            try {
                                labelStr += getLabelOrId(fillerRes.as(OntResource.class));
                            } catch (Exception e) {
                                labelStr += "???";
                            }
                        }
                    } else if (rest.isHasValueRestriction()) {
                        HasValueRestriction hvRest = rest.asHasValueRestriction();
                        labelStr += "has value ";
                        RDFNode fillerNode = hvRest.getHasValue();
                        try {
                            if (fillerNode.isResource()) {
                                labelStr += getLabelOrId(fillerNode.as(OntResource.class));
                            } else {
                                labelStr += fillerNode.as(Literal.class).getLexicalForm();
                            }
                        } catch (Exception e) {
                            labelStr += "???";
                        }
                    } else if (rest.isMinCardinalityRestriction()) {
                        MinCardinalityRestriction mcRest = rest.asMinCardinalityRestriction();
                        labelStr += "minimum cardinality ";
                        labelStr += mcRest.getMinCardinality();
                    } else if (rest.isMaxCardinalityRestriction()) {
                        MaxCardinalityRestriction mcRest = rest.asMaxCardinalityRestriction();
                        labelStr += "maximum cardinality ";
                        labelStr += mcRest.getMaxCardinality();
                    } else if (rest.isCardinalityRestriction()) {
                        CardinalityRestriction cRest = rest.asCardinalityRestriction();
                        labelStr += "cardinality ";
                        labelStr += cRest.getCardinality();
                    }
                    return labelStr;
                } else if (isBooleanClassExpression(cls)) {
                    String labelStr = "(";
                    if (cls.isComplementClass()) {
                        labelStr += "not ";
                        ComplementClass ccls = cls.as(ComplementClass.class);
                        labelStr += getLabelForClass(ccls.getOperand(), withPrefix, forPickList);
                    } else if (cls.isIntersectionClass()) {
                        IntersectionClass icls = cls.as(IntersectionClass.class);
                        for (Iterator<? extends OntClass> operandIt = icls.listOperands(); operandIt.hasNext();) {
                            OntClass operand = operandIt.next();
                            labelStr += getLabelForClass(operand, withPrefix, forPickList);
                            if (operandIt.hasNext()) {
                                labelStr += " and ";
                            }
                        }
                    } else if (cls.isUnionClass()) {
                        UnionClass icls = cls.as(UnionClass.class);
                        for (Iterator<? extends OntClass> operandIt = icls.listOperands(); operandIt.hasNext();) {
                            OntClass operand = operandIt.next();
                            labelStr += getLabelForClass(operand, withPrefix, forPickList);
                            if (operandIt.hasNext()) {
                                labelStr += " or ";
                            }
                        }
                    }
                    return labelStr + ")";
                } else {
                    // BJL23 2009-02-19
                    // I'm putting the link markup in because I need it,
                    // but obviously we need to factor this out into the display layer.
                    return "<a href=\"vclassEdit?uri=" + URLEncoder.encode(getClassURIStr(cls))
                            + "\">[anonymous class]</a>";
                }
            } else {
                if (withPrefix || forPickList) {
                    OntologyDao oDao = getWebappDaoFactory().getOntologyDao();
                    Ontology o = oDao.getOntologyByURI(cls.getNameSpace());
                    if (o != null) {
                        if (withPrefix) {
                            return (o.getPrefix() == null
                                    ? (o.getName() == null ? "unspec:" + getLabelOrId(cls)
                                            : o.getName() + ":" + getLabelOrId(cls))
                                    : o.getPrefix() + ":" + getLabelOrId(cls));
                        } else {
                            return (getLabelOrId(cls) + (o.getPrefix() == null
                                    ? (o.getName() == null ? " (unspec)" : " (" + o.getName() + ")")
                                    : " (" + o.getPrefix() + ")"));
                        }
                    } else {
                        return getLabelOrId(cls);
                    }
                }
                return getLabelOrId(cls);
            }
        } catch (Exception e) {
            log.error(e, e);
            return "???";
        } finally {
            cls.getModel().leaveCriticalSection();
        }
    }

    public void deleteVClass(VClass cls) {
        deleteVClass(cls, getOntModel());
    }

    public void deleteVClass(String URI) {
        deleteVClass(URI, getOntModel());
    }

    public void deleteVClass(String URI, OntModel ontModel) {
        ontModel.enterCriticalSection(Lock.WRITE);
        getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntClass cls = getOntClass(ontModel, URI);
            if (cls != null) {
                //Remove restriction class.
                Iterator<Resource> restIt = ontModel.listSubjectsWithProperty(OWL.allValuesFrom, cls);
                while (restIt.hasNext()) {
                    Resource restRes = restIt.next();
                    if (restRes.canAs(OntResource.class)) {
                        OntResource restOntRes = restRes.as(OntResource.class);
                        smartRemove(restOntRes, ontModel);
                    }
                }
                restIt = ontModel.listSubjectsWithProperty(OWL.someValuesFrom, cls);
                while (restIt.hasNext()) {
                    Resource restRes = restIt.next();
                    if (restRes.canAs(OntResource.class)) {
                        OntResource restOntRes = restRes.as(OntResource.class);
                        smartRemove(restOntRes, ontModel);
                    }
                }
                removeRulesMentioningResource(cls, ontModel);
                smartRemove(cls, ontModel);
            }
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            ontModel.leaveCriticalSection();
        }
    }

    public void deleteVClass(VClass cls, OntModel ontModel) {
        deleteVClass(cls.getURI(), ontModel);
    }

    public List<String> getDisjointWithClassURIs(String classURI) {
        OntClass ontClass = getOntClass(getOntModel(), classURI);
        List<String> uriList = new ArrayList<String>();
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            for (Iterator<? extends OntClass> i = ontClass.listDisjointWith(); i.hasNext();) {
                OntClass disjointClass = i.next();
                uriList.add(getClassURIStr(disjointClass));
            }
        } catch (ProfileException pe) {
            // Current language profile does not support disjointWith axioms.
            // We'd prefer to return an empty list instead of throwing an exception.
        } finally {
            getOntModel().leaveCriticalSection();
        }
        return uriList;
    }

    public void addDisjointWithClass(String classURI, String disjointClassURI) {
        getOntModel().enterCriticalSection(Lock.WRITE);
        getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntClass ontClass = getOntClass(getOntModel(), classURI);
            OntClass disjointClass = getOntClass(getOntModel(), disjointClassURI);
            ontClass.addDisjointWith(disjointClass);
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            getOntModel().leaveCriticalSection();
        }
    }

    public void removeDisjointWithClass(String classURI, String disjointClassURI) {
        getOntModel().enterCriticalSection(Lock.WRITE);
        getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntClass ontClass = getOntClass(getOntModel(), classURI);
            OntClass disjointClass = getOntClass(getOntModel(), disjointClassURI);
            ontClass.removeDisjointWith(disjointClass);
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            getOntModel().leaveCriticalSection();
        }
    }

    public List<String> getEquivalentClassURIs(String classURI) {
        List<String> equivalentClassURIs = new ArrayList<String>();
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            OntClass ontClass = getOntClass(getOntModel(), classURI);
            ClosableIterator<OntClass> equivalentOntClassIt = ontClass.listEquivalentClasses();
            try {
                for (Iterator<OntClass> eqOntClassIt = equivalentOntClassIt; eqOntClassIt.hasNext();) {
                    OntClass eqClass = eqOntClassIt.next();
                    equivalentClassURIs.add(getClassURIStr(eqClass));
                }
            } finally {
                equivalentOntClassIt.close();
            }
        } catch (ProfileException pe) {
            // Current language profile does not support equivalent classes.
            // We'd prefer to return an empty list instead of throwing an exception
        } catch (Exception e) {
            // we'll try this again using a different method that 
            // doesn't try to convert to OntClass
            List<Resource> supList = this.listDirectObjectPropertyValues(getOntModel().getResource(classURI),
                    OWL.equivalentClass);
            for (Resource res : supList) {
                equivalentClassURIs.add(getClassURIStr(res));
            }
        } finally {
            getOntModel().leaveCriticalSection();
        }
        return equivalentClassURIs;
    }

    public void addSuperclass(VClass vclass, VClass superclass) {
        addSuperclass(vclass.getURI(), superclass.getURI());
    }

    public void addSuperclass(String vclassURI, String superclassURI) {
        Classes2Classes c2c = new Classes2Classes();
        c2c.setSubclassURI(vclassURI);
        c2c.setSuperclassURI(superclassURI);
        insertNewClasses2Classes(c2c);
    }

    public void removeSuperclass(VClass vclass, VClass superclass) {
        removeSuperclass(vclass.getURI(), superclass.getURI());
    }

    public void removeSuperclass(String vclassURI, String superclassURI) {
        Classes2Classes c2c = new Classes2Classes();
        c2c.setSubclassURI(vclassURI);
        c2c.setSuperclassURI(superclassURI);
        deleteClasses2Classes(c2c);
    }

    public void addSubclass(VClass vclass, VClass subclass) {
        addSubclass(vclass.getURI(), subclass.getURI());
    }

    public void addSubclass(String vclassURI, String subclassURI) {
        Classes2Classes c2c = new Classes2Classes();
        c2c.setSubclassURI(subclassURI);
        c2c.setSuperclassURI(vclassURI);
        insertNewClasses2Classes(c2c);
    }

    public void removeSubclass(VClass vclass, VClass subclass) {
        removeSubclass(vclass.getURI(), subclass.getURI());
    }

    public void removeSubclass(String vclassURI, String subclassURI) {
        Classes2Classes c2c = new Classes2Classes();
        c2c.setSubclassURI(subclassURI);
        c2c.setSuperclassURI(vclassURI);
        deleteClasses2Classes(c2c);
    }

    public void addEquivalentClass(String classURI, String equivalentClassURI) {
        getOntModel().enterCriticalSection(Lock.WRITE);
        getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntClass ontClass = getOntClass(getOntModel(), classURI);
            OntClass eqClass = getOntClass(getOntModel(), equivalentClassURI);
            ontClass.addEquivalentClass(eqClass);
            eqClass.addEquivalentClass(ontClass);
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            getOntModel().leaveCriticalSection();
        }
    }

    public void removeEquivalentClass(String classURI, String equivalentClassURI) {
        getOntModel().enterCriticalSection(Lock.WRITE);
        getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntClass ontClass = getOntClass(getOntModel(), classURI);
            OntClass eqClass = getOntClass(getOntModel(), equivalentClassURI);
            ontClass.removeEquivalentClass(eqClass);
            eqClass.removeEquivalentClass(ontClass);
            if (ontClass.isAnon()) {
                smartRemove(ontClass, getOntModel());
            }
            if (eqClass.isAnon()) {
                smartRemove(eqClass, getOntModel());
            }
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            getOntModel().leaveCriticalSection();
        }
    }

    public List<String> getAllSubClassURIs(String classURI) {
        HashSet<String> nodeSet = new HashSet<String>();
        nodeSet.add(classURI);
        getAllSubClassURIs(classURI, nodeSet);
        nodeSet.remove(classURI);
        List<String> outputList = new ArrayList<String>();
        outputList.addAll(nodeSet);
        return outputList;
    }

    public void getAllSubClassURIs(String classURI, HashSet<String> subtree) {
        List<String> directSubclasses = getSubClassURIs(classURI);
        Iterator<String> it = directSubclasses.iterator();
        while (it.hasNext()) {
            String uri = it.next();
            if (!subtree.contains(uri)) {
                subtree.add(uri);
                getAllSubClassURIs(uri, subtree);
            }
        }
    }

    public List<String> getAllSuperClassURIs(String classURI) {

        List<String> superclassURIs = null;

        if (isUnderlyingStoreReasoned()) {
            superclassURIs = new ArrayList<String>();
            Resource cls = ResourceFactory.createResource(classURI);
            StmtIterator superClassIt = getOntModel().listStatements(cls, RDFS.subClassOf, (RDFNode) null);
            while (superClassIt.hasNext()) {
                Statement stmt = superClassIt.nextStatement();
                if (stmt.getObject().canAs(OntResource.class)) {
                    OntResource superRes = stmt.getObject().as(OntResource.class);
                    String test = getClassURIStr(superRes);
                    superclassURIs.add(test);
                }
            }
            return superclassURIs;
        } else {
            HashSet<String> nodeSet = new HashSet<String>();
            nodeSet.add(classURI);
            getAllSuperClassURIs(classURI, nodeSet);
            //nodeSet.remove(classURI);
            return new ArrayList<String>(nodeSet);
        }
    }

    public void getAllSuperClassURIs(String classURI, HashSet<String> subtree) {
        List<String> directSuperclasses = getSuperClassURIs(classURI, true);
        Iterator<String> it = directSuperclasses.iterator();
        while (it.hasNext()) {
            String uri = it.next();
            if (!subtree.contains(uri)) {
                subtree.add(uri);
                getAllSuperClassURIs(uri, subtree);
            }
        }
    }

    public List<VClass> getAllVclasses() {
        List<VClass> classes = new ArrayList<VClass>();
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            ClosableIterator<Individual> classIt = getOntModel().listIndividuals(OWL.Class);
            try {
                while (classIt.hasNext()) {
                    try {
                        Individual classInd = classIt.next();
                        if (classInd.canAs(OntClass.class)) {
                            OntClass cls = classInd.as(OntClass.class);
                            if (!cls.isAnon() && !(NONUSER_NAMESPACES.contains(cls.getNameSpace()))) {
                                classes.add(new VClassJena(cls, getWebappDaoFactory()));
                            }
                        }
                    } catch (ClassCastException cce) {
                        log.error(cce, cce);
                    }
                }
            } finally {
                classIt.close();
            }
        } finally {
            getOntModel().leaveCriticalSection();
        }
        Collections.sort(classes);
        return classes;
    }

    /** 
     * The basic idea here is that we ignore anonymous superclasses for the purpose 
     * of determining whether something is a root class.
     * We also avoid ClassCastExceptions deep in Jena-land by eschewing Jena's 
     * listSuperClasses() method.
     * @author bjl23
     */
    private Iterator<OntClass> smarterListHierarchyRootClasses(OntModel ontModel, String ontologyURI) {
        List<OntClass> rootClassList = new ArrayList<OntClass>();
        ResIterator ci = ontModel.listResourcesWithProperty(RDF.type, OWL.Class);
        try {
            for (ResIterator i = ci; i.hasNext();) {
                try {
                    Resource ontClass = i.nextResource();
                    boolean isRoot = true;
                    for (StmtIterator j = ontClass.listProperties(RDFS.subClassOf); j.hasNext();) {
                        Statement stmt = j.nextStatement();
                        if (!stmt.getObject().isResource()) {
                            continue;
                        }
                        Resource superClass = (Resource) stmt.getObject();
                        if (!superClass.isAnon()
                                && ((ontologyURI == null) || (ontologyURI.equals(superClass.getNameSpace())))
                                && !OWL.Thing.equals(superClass) && !superClass.equals(ontClass)
                                && !(ontModel.contains(ontClass, OWL.equivalentClass, superClass)
                                        || ontModel.contains(superClass, OWL.equivalentClass, ontClass))) {
                            if ((superClass.getNameSpace() != null)
                                    && (!(NONUSER_NAMESPACES.contains(superClass.getNameSpace())))) {
                                isRoot = false;
                                break;
                            }
                        }

                    }
                    if (isRoot && ontClass.canAs(OntClass.class)) {
                        rootClassList.add(ontClass.as(OntClass.class));
                    }
                } catch (ClassCastException cce) {
                    log.error(cce, cce);
                }
            }
        } finally {
            ci.close();
        }
        return rootClassList.iterator();
    }

    public List<VClass> getRootClasses() {
        return getRootClasses(null);
    }

    private List<VClass> getRootClasses(String ontologyURI) {
        List<VClass> rootClasses = new ArrayList<VClass>();
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            Iterator<OntClass> rootIt = smarterListHierarchyRootClasses(getOntModel(), ontologyURI);
            while (rootIt.hasNext()) {
                OntClass cls = rootIt.next();
                if (!cls.isAnon() && cls.getNameSpace() != null
                        && !(NONUSER_NAMESPACES.contains(cls.getNameSpace()))) {
                    rootClasses.add(new VClassJena(cls, getWebappDaoFactory()));
                }
            }
            Collections.sort(rootClasses);
        } finally {
            getOntModel().leaveCriticalSection();
        }
        return rootClasses;
    }

    public List<VClass> getOntologyRootClasses(String ontologyURI) {
        if (ontologyURI == null) {
            throw new RuntimeException("can't find root classes for null ontology URI");
        }
        // return getRootClasses(ontologyURI);
        List<VClass> ontologyRootClasses = new ArrayList<VClass>();
        OntModel ontModel = getOntModel();
        ontModel.enterCriticalSection(Lock.READ);
        try {
            Iterator<Resource> ontClassIt = ontModel.listResourcesWithProperty(RDF.type, OWL.Class);
            while (ontClassIt.hasNext()) {
                Resource ontClass = ontClassIt.next();
                if (ontologyURI.equals(ontClass.getNameSpace())) {
                    boolean root = true;
                    StmtIterator superStmtIt = ontModel.listStatements(ontClass, RDFS.subClassOf, (RDFNode) null);
                    try {
                        while (superStmtIt.hasNext()) {
                            Statement superStmt = superStmtIt.nextStatement();
                            if (superStmt.getObject().isResource()
                                    && ontologyURI.equals(((Resource) superStmt.getObject()).getNameSpace())) {
                                root = false;
                                break;
                            }
                        }
                    } finally {
                        superStmtIt.close();
                    }
                    if (root && ontClass.canAs(OntClass.class)) {
                        ontologyRootClasses
                                .add(new VClassJena((OntClass) ontClass.as(OntClass.class), getWebappDaoFactory()));
                    }
                }
            }
        } finally {
            ontModel.leaveCriticalSection();
        }
        return ontologyRootClasses;
    }

    public List<String> getSubClassURIs(String classURI) {
        List<String> subURIs = new ArrayList<String>();
        OntClass superClass = getOntClass(getOntModel(), classURI);
        try {
            Iterator<OntClass> subIt = superClass.listSubClasses(true);
            while (subIt.hasNext()) {
                OntClass cls = subIt.next();
                subURIs.add(getClassURIStr(cls));
            }
        } catch (Exception e) {
            // we'll try this again using a different method that doesn't try to convert to OntClass
            List<Resource> supList = this.listDirectObjectPropertySubjects(getOntModel().getResource(classURI),
                    RDFS.subClassOf);
            for (Resource res : supList) {
                subURIs.add(res.getURI());
            }
        }
        return subURIs;
    }

    public List<String> getSuperClassURIs(String classURI, boolean direct) {
        List<String> supURIs = new ArrayList<String>();
        OntClass subClass = getOntClass(getOntModel(), classURI);
        try {
            Iterator<OntClass> supIt = subClass.listSuperClasses(direct);
            while (supIt.hasNext()) {
                OntClass cls = (OntClass) supIt.next();
                supURIs.add(getClassURIStr(cls));
            }
        } catch (Exception e) {
            log.debug(e, e);
            // we'll try this again using a different method 
            // that doesn't try to convert to OntClass
            supURIs.clear();
            List<Resource> supList = (direct) ? listDirectObjectPropertyValues(subClass, RDFS.subClassOf)
                    : listObjectPropertyValues(subClass, RDFS.subClassOf);
            for (Resource res : supList) {
                supURIs.add(getClassURIStr(res));
            }
        }
        return supURIs;
    }

    private List<Resource> listObjectPropertyValues(Resource res, Property prop) {
        List<Resource> values = new ArrayList<Resource>();
        StmtIterator stmtIt = res.listProperties(prop);
        while (stmtIt.hasNext()) {
            Statement s = stmtIt.nextStatement();
            if (s.getObject().isResource()) {
                values.add(s.getObject().asResource());
            }
        }
        return values;
    }

    public VClass getTopConcept() {
        VClass top = new VClass();
        if (getOntModel().getProfile().NAMESPACE().equals(RDFS.getURI())) {
            top.setURI(RDF.getURI() + "Resource");
        } else {
            top.setURI((getOntModel().getProfile().THING().getURI() != null)
                    ? (getOntModel().getProfile().THING().getURI())
                    : null);
        }
        if (top.getURI() != null) {
            top.setName(top.getLocalName());
            return top;
        } else {
            return null;
        }
    }

    public VClass getBottomConcept() {
        VClass bottom = new VClass();
        if (getOntModel().getProfile().NAMESPACE().equals(RDFS.getURI())) {
            return null;
        } else {
            bottom.setURI((getOntModel().getProfile().NOTHING().getURI() != null)
                    ? (getOntModel().getProfile().NOTHING().getURI())
                    : null);
        }
        if (bottom.getURI() != null) {
            bottom.setName(bottom.getLocalName());
            return bottom;
        } else {
            return null;
        }
    }

    public VClass getVClassByURI(String URIStr) {
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            OntClass cls = getOntClass(getOntModel(), URIStr);
            if (cls != null) {
                return new VClassJena(cls, getWebappDaoFactory());
            } else {
                return null;
            }
        } finally {
            getOntModel().leaveCriticalSection();
        }
    }

    public void insertNewVClass(VClass cls) throws InsertException {
        insertNewVClass(cls, getOntModelSelector().getTBoxModel());
    }

    public List<VClass> getVClassesForProperty(String propertyURI, boolean domainSide) {
        return getVClassesForProperty(null, propertyURI, domainSide);
    }

    public List<VClass> getVClassesForProperty(String vclassURI, String propertyURI) {
        return getVClassesForProperty(vclassURI, propertyURI, true);
    }

    private List<VClass> getVClassesForProperty(String vclassURI, String propertyURI, boolean domainSide) {
        List<VClass> vClasses = new ArrayList<VClass>();
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            ObjectProperty op = getOntModel().getObjectProperty(propertyURI);
            if (op != null) {
                OntResource superclass = null;
                if (vclassURI != null) {
                    // TODO need a getAllSuperPropertyURIs method in ObjectPropertyDao
                    List<String> superproperties = getWebappDaoFactory().getObjectPropertyDao()
                            .getSuperPropertyURIs(propertyURI, false);
                    superproperties.add(propertyURI);
                    HashSet<String> subjSuperclasses = new HashSet<String>(getAllSuperClassURIs(vclassURI));
                    subjSuperclasses.add(vclassURI);
                    for (String objectPropertyURI : superproperties) {
                        for (Iterator restStmtIt = getOntModel().listStatements(null, OWL.onProperty,
                                getOntModel().getProperty(objectPropertyURI)); restStmtIt.hasNext();) {
                            Statement restStmt = (Statement) restStmtIt.next();
                            Resource restRes = restStmt.getSubject();
                            for (Iterator axStmtIt = getOntModel().listStatements(null, null, restRes); axStmtIt
                                    .hasNext();) {
                                Statement axStmt = (Statement) axStmtIt.next();
                                OntResource subjOntRes = null;
                                if (axStmt.getSubject().canAs(OntResource.class)) {
                                    subjOntRes = axStmt.getSubject().as(OntResource.class);
                                }
                                if ((subjOntRes != null) && (subjSuperclasses.contains(getClassURIStr(subjOntRes)))
                                        && (axStmt.getPredicate().equals(RDFS.subClassOf)
                                                || (axStmt.getPredicate().equals(OWL.equivalentClass)))) {
                                    if (restRes.canAs(AllValuesFromRestriction.class)) {
                                        AllValuesFromRestriction avfRest = restRes
                                                .as(AllValuesFromRestriction.class);
                                        Resource avf = avfRest.getAllValuesFrom();
                                        if (avf.canAs(OntClass.class)) {
                                            superclass = avfRest.getAllValuesFrom().as(OntClass.class);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (superclass == null) {
                    superclass = (domainSide) ? op.getRange() : op.getDomain();
                    if (superclass == null) {
                        //this section to prevent all subclasses of owl:Thing
                        //returned if range is owl:Thing, refer to NIHVIVO-3357 NIHVIVO-3814
                        //This is unfortunate case of warping the model for the ease of the display.
                        return Collections.emptyList();
                    }
                }
                if (superclass != null) {
                    VClass superVclass;
                    if (superclass.isAnon()) {
                        superVclass = getVClassByURI(getClassURIStr(superclass));
                    } else {
                        superVclass = getVClassByURI(superclass.getURI());
                    }
                    if (OWL.Thing.equals(superclass)) {
                        //this section to prevent all subclasses of owl:Thing
                        //returned if range is owl:Thing, refer to NIHVIVO-3357 NIHVIVO-3814
                        //This is unfortunate case of warping the model for the ease of the display.
                        return Collections.emptyList();
                    }
                    if (superVclass != null) {
                        vClasses.add(superVclass);
                        // if this model infers types based on the taxonomy, adding the subclasses will only
                        // waste time for no benefit
                        if (!isUnderlyingStoreReasoned()) {
                            Iterator classURIs = getAllSubClassURIs(getClassURIStr(superclass)).iterator();
                            while (classURIs.hasNext()) {
                                String classURI = (String) classURIs.next();
                                VClass vClass = getVClassByURI(classURI);
                                if (vClass != null)
                                    vClasses.add(vClass);
                            }
                        }
                    }
                }
            }
        } finally {
            getOntModel().leaveCriticalSection();
        }
        return vClasses;
    }

    /////////////////////////////////////////////////////////////////////////////////////////

    public void addVClassesToGroup(VClassGroup group) {
        addVClassesToGroup(group, true);
    }

    @Deprecated
    public void addVClassesToGroup(VClassGroup group, boolean includeUninstantiatedClasses) {
        addVClassesToGroup(group, includeUninstantiatedClasses, false);
    }

    @Deprecated
    public void addVClassesToGroup(VClassGroup group, boolean includeUninstantiatedClasses,
            boolean getIndividualCount) {
        getOntModel().enterCriticalSection(Lock.READ);

        if (getIndividualCount) {
            group.setIndividualCount(getClassGroupInstanceCount(group));
        }

        try {
            if ((group != null) && (group.getURI() != null)) {
                Resource groupRes = ResourceFactory.createResource(group.getURI());
                AnnotationProperty inClassGroup = getOntModel()
                        .getAnnotationProperty(VitroVocabulary.IN_CLASSGROUP);
                if (inClassGroup != null) {
                    ClosableIterator annotIt = getOntModel().listStatements((OntClass) null, inClassGroup,
                            groupRes);
                    try {
                        while (annotIt.hasNext()) {
                            try {
                                Statement annot = (Statement) annotIt.next();
                                Resource cls = annot.getSubject();
                                VClass vcw = getVClassByURI(cls.getURI());
                                if (vcw != null) {
                                    boolean classIsInstantiated = false;
                                    if (getIndividualCount) {
                                        Model aboxModel = getOntModelSelector().getABoxModel();
                                        aboxModel.enterCriticalSection(Lock.READ);
                                        int count = 0;
                                        try {
                                            String countQueryStr = "SELECT COUNT(*) WHERE \n" + "{ ?s a <"
                                                    + cls.getURI() + "> } \n";
                                            Query countQuery = QueryFactory.create(countQueryStr, Syntax.syntaxARQ);
                                            QueryExecution qe = QueryExecutionFactory.create(countQuery, aboxModel);
                                            ResultSet rs = qe.execSelect();
                                            count = Integer.parseInt(
                                                    ((Literal) rs.nextSolution().get(".1")).getLexicalForm());
                                            //count = aboxModel.listStatements(null,RDF.type,cls).toList().size();
                                        } finally {
                                            aboxModel.leaveCriticalSection();
                                        }
                                        vcw.setEntityCount(count);
                                        classIsInstantiated = (count > 0);
                                    } else if (includeUninstantiatedClasses == false) {
                                        // Note: to support SDB models, may want to do this with 
                                        // SPARQL and LIMIT 1 if SDB can take advantage of it
                                        Model aboxModel = getOntModelSelector().getABoxModel();
                                        aboxModel.enterCriticalSection(Lock.READ);
                                        try {
                                            ClosableIterator countIt = aboxModel.listStatements(null, RDF.type,
                                                    cls);
                                            try {
                                                if (countIt.hasNext()) {
                                                    classIsInstantiated = true;
                                                }
                                            } finally {
                                                countIt.close();
                                            }
                                        } finally {
                                            aboxModel.leaveCriticalSection();
                                        }
                                    }

                                    if (includeUninstantiatedClasses || classIsInstantiated) {
                                        group.add(vcw);
                                    }
                                }
                            } catch (ClassCastException cce) {
                                log.error(cce, cce);
                            }
                        }
                    } finally {
                        annotIt.close();
                    }
                }
            }
            java.util.Collections.sort(group.getVitroClassList());
        } finally {
            getOntModel().leaveCriticalSection();
        }
    }

    int getClassGroupInstanceCount(VClassGroup vcg) {
        Model ontModel = getOntModel();
        ontModel.enterCriticalSection(Lock.READ);
        int count = 0;
        try {
            String queryText = "SELECT COUNT( DISTINCT ?instance ) WHERE { \n" + "      ?class <"
                    + VitroVocabulary.IN_CLASSGROUP + "> <" + vcg.getURI() + "> .\n"
                    + "      ?instance a ?class .  \n" + "}";
            Query countQuery = QueryFactory.create(queryText, Syntax.syntaxARQ);
            QueryExecution qe = QueryExecutionFactory.create(countQuery, ontModel);
            ResultSet rs = qe.execSelect();
            count = Integer.parseInt(((Literal) rs.nextSolution().get(".1")).getLexicalForm());
        } catch (Exception ex) {
            log.error(ex, ex);
        } finally {
            ontModel.leaveCriticalSection();
        }
        return count;
    }

    public void addVClassesToGroups(List<VClassGroup> groups) {
        getOntModel().enterCriticalSection(Lock.READ);
        try {
            if (groups != null) {
                Iterator groupIt = groups.iterator();
                while (groupIt.hasNext()) {
                    VClassGroup g = (VClassGroup) groupIt.next();
                    addVClassesToGroup(g);
                }
            }
        } finally {
            getOntModel().leaveCriticalSection();
        }
    }

    public int insertNewVClass(VClass cls, OntModel ontModel) throws InsertException {
        ontModel.enterCriticalSection(Lock.WRITE);
        getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            String errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(cls.getURI());
            if (errMsgStr != null) {
                throw new InsertException(errMsgStr);
            }
            OntClass ontCls = ontModel.createClass(cls.getURI());
            try {
                if (cls.getName() != null && cls.getName().length() > 0) {
                    ontCls.setLabel(cls.getName(), getDefaultLanguage());
                } else {
                    ontCls.removeAll(RDFS.label);
                }
            } catch (Exception e) {
                log.error("error setting label for class " + cls.getURI());
            }
            try {
                if (cls.getGroupURI() != null && cls.getGroupURI().length() > 0) {
                    String badURIErrorStr = checkURI(cls.getGroupURI());
                    if (badURIErrorStr == null) {
                        ontCls.addProperty(IN_CLASSGROUP, getOntModel().getResource(cls.getGroupURI()));
                    } else {
                        log.error(badURIErrorStr);
                    }
                }
            } catch (Exception e) {
                log.error("error linking class " + cls.getURI() + " to class group");
            }
            addPropertyStringValue(ontCls, SHORTDEF, cls.getShortDef(), ontModel);
            addPropertyStringValue(ontCls, EXAMPLE_ANNOT, cls.getExample(), ontModel);
            addPropertyStringValue(ontCls, DESCRIPTION_ANNOT, cls.getDescription(), ontModel);
            addPropertyIntValue(ontCls, DISPLAY_LIMIT, cls.getDisplayLimit(), ontModel);
            addPropertyIntValue(ontCls, DISPLAY_RANK_ANNOT, cls.getDisplayRank(), ontModel);

            ontCls.removeAll(HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT);
            if (HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT != null
                    && cls.getHiddenFromDisplayBelowRoleLevel() != null) { // only need to add if present
                try {
                    ontCls.addProperty(HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT,
                            ResourceFactory.createResource(cls.getHiddenFromDisplayBelowRoleLevel().getURI()));
                } catch (Exception e) {
                    log.error("error adding HiddenFromDisplayBelowRoleLevel annotation to class " + cls.getURI());
                }
            }

            ontCls.removeAll(PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT);
            if (PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT != null
                    && cls.getProhibitedFromUpdateBelowRoleLevel() != null) { // only need to add if present
                try {
                    ontCls.addProperty(PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT,
                            ResourceFactory.createResource(cls.getProhibitedFromUpdateBelowRoleLevel().getURI()));
                } catch (Exception e) {
                    log.error(
                            "error adding ProhibitedFromUpdateBelowRoleLevel annotation to class " + cls.getURI());
                }
            }

            ontCls.removeAll(HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT);
            if (HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT != null
                    && cls.getHiddenFromPublishBelowRoleLevel() != null) { // only need to add if present
                try {
                    ontCls.addProperty(HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT,
                            ResourceFactory.createResource(cls.getHiddenFromPublishBelowRoleLevel().getURI()));
                } catch (Exception e) {
                    log.error("error adding HiddenFromPublishBelowRoleLevel annotation to class " + cls.getURI());
                }
            }

            /* OPTIONAL annotation properties */
            addPropertyStringValue(ontCls, PROPERTY_CUSTOMENTRYFORMANNOT, cls.getCustomEntryForm(), ontModel);
            addPropertyStringValue(ontCls, PROPERTY_CUSTOMDISPLAYVIEWANNOT, cls.getCustomDisplayView(), ontModel);
            addPropertyStringValue(ontCls, PROPERTY_CUSTOMSHORTVIEWANNOT, cls.getCustomShortView(), ontModel);
            addPropertyStringValue(ontCls, PROPERTY_CUSTOMSEARCHVIEWANNOT, cls.getCustomSearchView(), ontModel);
            addPropertyFloatValue(ontCls, SEARCH_BOOST_ANNOT, cls.getSearchBoost(), ontModel);
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            ontModel.leaveCriticalSection();
        }
        return 0;
    }

    public void updateVClass(VClass cls) {
        updateVClass(cls, getOntModel());
    }

    public void updateVClass(VClass cls, OntModel ontModel) {
        ontModel.enterCriticalSection(Lock.WRITE);
        ontModel.getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntClass ontCls = ontModel.getOntClass(cls.getURI());

            if (ontCls != null) {
                updateRDFSLabel(ontCls, cls.getName());
                updatePropertyResourceURIValue(ontCls, IN_CLASSGROUP, cls.getGroupURI(), ontModel);
                updatePropertyStringValue(ontCls, SHORTDEF, cls.getShortDef(), ontModel);
                updatePropertyStringValue(ontCls, EXAMPLE_ANNOT, cls.getExample(), ontModel);
                updatePropertyStringValue(ontCls, DESCRIPTION_ANNOT, cls.getDescription(), ontModel);
                updatePropertyNonNegativeIntValue(ontCls, DISPLAY_LIMIT, cls.getDisplayLimit(), ontModel);
                updatePropertyNonNegativeIntValue(ontCls, DISPLAY_RANK_ANNOT, cls.getDisplayRank(), ontModel);
                updatePropertyFloatValue(ontCls, SEARCH_BOOST_ANNOT, cls.getSearchBoost(), ontModel);

                if (cls.getHiddenFromDisplayBelowRoleLevel() != null) {
                    updatePropertyResourceURIValue(ontCls, HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT,
                            cls.getHiddenFromDisplayBelowRoleLevel().getURI(), ontModel);
                }

                if (cls.getProhibitedFromUpdateBelowRoleLevel() != null) {
                    updatePropertyResourceURIValue(ontCls, PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT,
                            cls.getProhibitedFromUpdateBelowRoleLevel().getURI(), ontModel);
                }

                if (cls.getHiddenFromPublishBelowRoleLevel() != null) {
                    updatePropertyResourceURIValue(ontCls, HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT,
                            cls.getHiddenFromPublishBelowRoleLevel().getURI(), ontModel);
                }

                updatePropertyStringValue(ontCls, PROPERTY_CUSTOMENTRYFORMANNOT, cls.getCustomEntryForm(),
                        ontModel);
                updatePropertyStringValue(ontCls, PROPERTY_CUSTOMDISPLAYVIEWANNOT, cls.getCustomDisplayView(),
                        ontModel);
                updatePropertyStringValue(ontCls, PROPERTY_CUSTOMSHORTVIEWANNOT, cls.getCustomShortView(),
                        ontModel);
                updatePropertyStringValue(ontCls, PROPERTY_CUSTOMSEARCHVIEWANNOT, cls.getCustomSearchView(),
                        ontModel);
            } else {
                log.error("error: cannot find jena class " + cls.getURI() + " for updating");
            }
        } finally {
            getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            ontModel.leaveCriticalSection();
        }
    }

    public void deleteClasses2Classes(Classes2Classes c2c) {
        deleteClasses2Classes(c2c, getOntModelSelector().getTBoxModel());
    }

    public void deleteClasses2Classes(Classes2Classes c2c, OntModel ontModel) {
        ontModel.enterCriticalSection(Lock.WRITE);
        ontModel.getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            OntResource subclass = getOntClass(ontModel, c2c.getSubclassURI());
            OntResource superclass = getOntClass(ontModel, c2c.getSuperclassURI());
            if (subclass == null || superclass == null) {
                log.warn("unable to delete " + c2c.getSubclassURI() + " rdfs:subClassOf " + c2c.getSuperclassURI());
                if (subclass == null) {
                    log.warn(c2c.getSubclassURI() + " not found in the model.");
                }
                if (superclass == null) {
                    log.warn(c2c.getSuperclassURI() + " not found in the model.");
                }
                return;
            }
            Model removal = ModelFactory.createDefaultModel();
            Model additions = ModelFactory.createDefaultModel(); // to repair any rdf:Lists
            removal.add(ontModel.listStatements(subclass, RDFS.subClassOf, superclass));
            if (subclass.isAnon()) {
                Model[] changeSet = getSmartRemoval(subclass, getOntModel());
                removal.add(changeSet[0]);
                additions.add(changeSet[1]);
            }
            if (superclass.isAnon()) {
                Model[] changeSet = getSmartRemoval(superclass, getOntModel());
                removal.add(changeSet[0]);
                additions.add(changeSet[1]);
            }
            ontModel.remove(removal);
            ontModel.add(additions);
        } finally {
            ontModel.getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            ontModel.leaveCriticalSection();
        }
    }

    public void insertNewClasses2Classes(Classes2Classes c2c) {
        insertNewClasses2Classes(c2c, getOntModelSelector().getTBoxModel());
    }

    public void insertNewClasses2Classes(Classes2Classes c2c, OntModel ontModel) {
        ontModel.enterCriticalSection(Lock.WRITE);
        ontModel.getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), true));
        try {
            Resource subclass = ontModel.getResource(c2c.getSubclassURI());
            Resource superclass = ontModel.getResource(c2c.getSuperclassURI());
            if ((subclass != null) && (superclass != null)) {
                ontModel.add(subclass, RDFS.subClassOf, superclass);
            }
        } finally {
            ontModel.getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(), false));
            ontModel.leaveCriticalSection();
        }
    }

    public boolean isSubClassOf(VClass vc1, VClass vc2) {
        if (vc1 == null || vc2 == null) {
            return false;
        }
        return isSubClassOf(vc1.getURI(), vc2.getURI());
    }

    public boolean isSubClassOf(String vclassURI1, String vclassURI2) {
        if (vclassURI1 == null || vclassURI2 == null) {
            return false;
        }
        OntModel ontModel = getOntModel();
        try {
            ontModel.enterCriticalSection(Lock.READ);
            Resource oc1 = ontModel.getResource(vclassURI1);
            Resource oc2 = ontModel.getResource(vclassURI2);
            return ontModel.contains(oc1, RDFS.subClassOf, oc2);
        } finally {
            ontModel.leaveCriticalSection();
        }
    }

}