NIHVIVO-1228 NIHVIVO-3202 improved selection of editable properties: support for simple union domains and domain inheritance
This commit is contained in:
parent
fc4a22d292
commit
1ec081dcf3
4 changed files with 397 additions and 400 deletions
|
@ -45,6 +45,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
|
|||
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Ontology;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.InsertException;
|
||||
|
@ -310,107 +311,37 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements
|
|||
}
|
||||
|
||||
public List<DataProperty> getDatapropsForClass(String vclassURI) {
|
||||
// TODO make this more efficient once we figure out our reasoner strategy
|
||||
List<DataProperty> datapropsForClass = new ArrayList();
|
||||
OntModel ontModel = getOntModelSelector().getTBoxModel();
|
||||
try {
|
||||
VClassDao vcDao = getWebappDaoFactory().getVClassDao();
|
||||
HashSet<String> superclassURIs = new HashSet<String>(vcDao.getAllSuperClassURIs(vclassURI));
|
||||
superclassURIs.add(vclassURI);
|
||||
for (String equivURI : vcDao.getEquivalentClassURIs(vclassURI)) {
|
||||
superclassURIs.add(equivURI);
|
||||
superclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
|
||||
}
|
||||
Iterator superclassURIsIt = superclassURIs.iterator();
|
||||
ontModel.enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
Iterator dataprops = ontModel.listDatatypeProperties();
|
||||
while (dataprops.hasNext()) {
|
||||
Object nextObj = dataprops.next();
|
||||
try {
|
||||
com.hp.hpl.jena.ontology.OntProperty jDataprop = (com.hp.hpl.jena.ontology.OntProperty) nextObj;
|
||||
Resource domainRes = jDataprop.getDomain();
|
||||
if (domainRes != null && !NONUSER_NAMESPACES.contains(jDataprop.getNameSpace()) && superclassURIs.contains(domainRes.getURI())) {
|
||||
datapropsForClass.add(datapropFromOntProperty(jDataprop));
|
||||
}
|
||||
// also check restrictions
|
||||
for (Iterator restStmtIt = ontModel.listStatements(null,OWL.onProperty,jDataprop); restStmtIt.hasNext();) {
|
||||
Statement restStmt = (Statement) restStmtIt.next();
|
||||
Resource restRes = restStmt.getSubject();
|
||||
for (Iterator axStmtIt = ontModel.listStatements(null,null,restRes); axStmtIt.hasNext();) {
|
||||
Statement axStmt = (Statement) axStmtIt.next();
|
||||
OntResource subjOntRes = null;
|
||||
if (axStmt.getSubject().canAs(OntResource.class)) {
|
||||
subjOntRes = (OntResource) axStmt.getSubject().as(OntResource.class);
|
||||
}
|
||||
if (
|
||||
( (subjOntRes!=null) && (superclassURIs.contains(getClassURIStr(subjOntRes))) ) &&
|
||||
(axStmt.getPredicate().equals(RDFS.subClassOf) || (axStmt.getPredicate().equals(OWL.equivalentClass)))
|
||||
) {
|
||||
if (restRes.canAs(AllValuesFromRestriction.class) || restRes.canAs(SomeValuesFromRestriction.class)) {
|
||||
datapropsForClass.add(datapropFromOntProperty(jDataprop));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ontModel.leaveCriticalSection();
|
||||
}
|
||||
} catch (ProfileException pe) {
|
||||
// TODO language profile doesn't support data properties.
|
||||
// With RDFS, we might like to return properties with rdfs:range containing a datatype
|
||||
}
|
||||
Collections.sort(datapropsForClass, new DataPropertyRanker());
|
||||
return datapropsForClass;
|
||||
return filterAndConvertToDataProperties(getAllPropInstByVClass(vclassURI));
|
||||
}
|
||||
|
||||
public Collection<DataProperty> getAllPossibleDatapropsForIndividual(String individualURI) {
|
||||
Individual ind = getWebappDaoFactory().getIndividualDao().getIndividualByURI(individualURI);
|
||||
Collection<DataProperty> dpColl = new ArrayList<DataProperty>();
|
||||
List<String> vclassURIs = getVClassURIs(ind);
|
||||
return filterAndConvertToDataProperties(getAllPossiblePropInstForIndividual(individualURI));
|
||||
}
|
||||
|
||||
try {
|
||||
for (VClass currClass : ind.getVClasses( DIRECT )) {
|
||||
List<DataProperty> currList = getDatapropsForClass(currClass.getURI());
|
||||
for (Iterator<DataProperty> dpIter = currList.iterator(); dpIter.hasNext();) {
|
||||
DataProperty dp = (DataProperty) dpIter.next();
|
||||
boolean addIt = true;
|
||||
// some inefficient de-duping
|
||||
for (Iterator<DataProperty> existingIter = dpColl.iterator(); existingIter.hasNext(); ) {
|
||||
DataProperty existingDp = (DataProperty) existingIter.next();
|
||||
try {
|
||||
if (existingDp.getURI().equals(dp.getURI()) &&
|
||||
existingDp.getDomainClassURI().equals(dp.getDomainClassURI()) &&
|
||||
existingDp.getRangeDatatypeURI().equals(dp.getRangeDatatypeURI())) {
|
||||
addIt = false;
|
||||
}
|
||||
} catch (Exception e) { }
|
||||
}
|
||||
if (addIt) {
|
||||
dpColl.add(dp);
|
||||
}
|
||||
}
|
||||
// 2010-01-25 addition by BJL
|
||||
// now change range datatype based on individual
|
||||
// TODO: rethink all these methods to reduce inefficiency
|
||||
for (DataProperty dp : dpColl) {
|
||||
dp.setRangeDatatypeURI(getRequiredDatatypeURI(ind, dp, vclassURIs));
|
||||
}
|
||||
}
|
||||
} catch (ProfileException pe) {
|
||||
// TODO language profile doesn't support data properties.
|
||||
// With RDFS, we might like to return properties with rdfs:range containing a datatype
|
||||
}
|
||||
/*
|
||||
for (DataProperty dp : dpColl) {
|
||||
dp.setDomainClassURI(ind.getVClassURI()); // TODO: improve. This is so the DWR property editing passes the individual's VClass to get the right restrictions
|
||||
}
|
||||
Collections.sort(dpColl, new PropInstSorter()); */
|
||||
return dpColl;
|
||||
private List<DataProperty> filterAndConvertToDataProperties(
|
||||
List<PropertyInstance> propInsts) {
|
||||
List<DataProperty> dataprops = new ArrayList<DataProperty>();
|
||||
for (PropertyInstance propInst : propInsts) {
|
||||
OntModel tboxModel = getOntModel();
|
||||
tboxModel.enterCriticalSection(Lock.READ);
|
||||
boolean add = false;
|
||||
try {
|
||||
add = (propInst.getPropertyURI() != null
|
||||
&& tboxModel.contains(
|
||||
tboxModel.getResource(
|
||||
propInst.getPropertyURI()),
|
||||
RDF.type,
|
||||
OWL.DatatypeProperty));
|
||||
} finally {
|
||||
tboxModel.leaveCriticalSection();
|
||||
}
|
||||
if (add) {
|
||||
DataProperty dataprop = getDataPropertyByURI(propInst.getPropertyURI());
|
||||
dataprop.setRangeDatatypeURI(propInst.getRangeClassURI());
|
||||
dataprops.add(dataprop);
|
||||
}
|
||||
}
|
||||
return dataprops;
|
||||
}
|
||||
|
||||
protected boolean reasoningAvailable() {
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -16,11 +20,15 @@ import org.apache.commons.logging.LogFactory;
|
|||
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.Restriction;
|
||||
import com.hp.hpl.jena.query.Dataset;
|
||||
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.QuerySolution;
|
||||
import com.hp.hpl.jena.query.ResultSet;
|
||||
import com.hp.hpl.jena.query.Syntax;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
@ -30,8 +38,10 @@ import com.hp.hpl.jena.sparql.resultset.ResultSetMem;
|
|||
import com.hp.hpl.jena.vocabulary.OWL;
|
||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Property;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
|
||||
|
@ -431,4 +441,318 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao {
|
|||
return rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* requires SPARQL 1.1 (or ARQ) property path support
|
||||
* @param vclassURI
|
||||
* @return list of property resources with union domains that include the vclass
|
||||
*/
|
||||
protected List<Resource> getPropertiesWithAppropriateDomainFor(String vclassURI) {
|
||||
List<Resource> propertyResList = new ArrayList<Resource>();
|
||||
String queryStr =
|
||||
"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n" +
|
||||
"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" +
|
||||
"PREFIX owl: <http://www.w3.org/2002/07/owl#> \n\n " +
|
||||
"SELECT ?p WHERE { \n" +
|
||||
" { \n" +
|
||||
" ?p rdfs:domain <" + vclassURI + "> . \n" +
|
||||
" } UNION { \n" +
|
||||
" ?parent rdfs:domain <" + vclassURI + "> . \n" +
|
||||
" ?p rdfs:subPropertyOf* ?parent. \n" +
|
||||
" OPTIONAL { \n" +
|
||||
" ?p rdfs:domain ?childDomain \n" +
|
||||
" } \n" +
|
||||
" FILTER (!bound(?childDomain)) \n" +
|
||||
" } UNION { \n" +
|
||||
" ?f rdf:first <" + vclassURI + "> . \n" +
|
||||
" ?u rdf:rest* ?f . \n" +
|
||||
" ?d owl:unionOf ?u . \n" +
|
||||
" ?p rdfs:domain ?d . \n" +
|
||||
" } UNION { \n" +
|
||||
" ?f rdf:first <" + vclassURI + "> . \n" +
|
||||
" ?u rdf:rest* ?f . \n" +
|
||||
" ?d owl:unionOf ?u . \n" +
|
||||
" ?parent rdfs:domain ?d . \n" +
|
||||
" ?p rdfs:subPropertyOf* ?parent. \n" +
|
||||
" OPTIONAL { \n" +
|
||||
" ?p rdfs:domain ?childDomain \n" +
|
||||
" } \n" +
|
||||
" FILTER (!bound(?childDomain)) \n" +
|
||||
" } \n" +
|
||||
" FILTER(?p != owl:bottomDataProperty \n" +
|
||||
" && ?p != owl:bottomObjectProperty) \n" +
|
||||
"}";
|
||||
log.info(queryStr);
|
||||
Query q = QueryFactory.create(queryStr, Syntax.syntaxSPARQL_11);
|
||||
QueryExecution qe = QueryExecutionFactory.create(
|
||||
q, getOntModelSelector().getTBoxModel());
|
||||
try {
|
||||
ResultSet rs = qe.execSelect();
|
||||
while (rs.hasNext()) {
|
||||
QuerySolution qs = rs.nextSolution();
|
||||
propertyResList.add(qs.getResource("p"));
|
||||
}
|
||||
} finally {
|
||||
qe.close();
|
||||
}
|
||||
return propertyResList;
|
||||
}
|
||||
|
||||
public List<PropertyInstance> getAllPossiblePropInstForIndividual(String individualURI) {
|
||||
Individual ind = getWebappDaoFactory().getIndividualDao().getIndividualByURI(individualURI);
|
||||
VClassDao vcDao = getWebappDaoFactory().getVClassDao();
|
||||
|
||||
List<VClass> allTypes = ind.getVClasses(false); // include indirect types
|
||||
|
||||
Set<String> allSuperclassURIs = new HashSet<String>();
|
||||
|
||||
for (VClass type : allTypes) {
|
||||
String classURI = type.getURI();
|
||||
if (classURI != null) {
|
||||
allSuperclassURIs.add(type.getURI());
|
||||
}
|
||||
for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) {
|
||||
allSuperclassURIs.add(equivURI);
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
|
||||
}
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI));
|
||||
}
|
||||
|
||||
List<VClass> vclasses = new ArrayList<VClass>();
|
||||
for(String vclassURI : allSuperclassURIs) {
|
||||
VClass vclass = vcDao.getVClassByURI(vclassURI);
|
||||
if (vclass != null) {
|
||||
vclasses.add(vclass);
|
||||
}
|
||||
}
|
||||
|
||||
List<PropertyInstance> piList = getAllPropInstByVClasses(vclasses);
|
||||
|
||||
for (PropertyInstance pi : piList) {
|
||||
pi.setDomainClassURI(ind.getVClassURI());
|
||||
// TODO: improve. This is so the DWR property editing passes the
|
||||
// individual's VClass to get the right restrictions
|
||||
}
|
||||
|
||||
return piList;
|
||||
}
|
||||
|
||||
/*
|
||||
* sorts VClasses so that subclasses come before superclasses
|
||||
*/
|
||||
private class VClassHierarchyRanker implements Comparator<VClass> {
|
||||
private VClassDao vcDao;
|
||||
public VClassHierarchyRanker(VClassDao vcDao) {
|
||||
this.vcDao = vcDao;
|
||||
}
|
||||
public int compare(VClass vc1, VClass vc2) {
|
||||
if (vcDao.isSubClassOf(vc1, vc2)) {
|
||||
return -1;
|
||||
} else if (vcDao.isSubClassOf(vc2, vc1)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<PropertyInstance> getAllPropInstByVClass(String classURI) {
|
||||
if (classURI==null || classURI.length()<1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
VClassDao vcDao = getWebappDaoFactory().getVClassDao();
|
||||
|
||||
Set<String> allSuperclassURIs = new HashSet<String>();
|
||||
|
||||
allSuperclassURIs.add(classURI);
|
||||
for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) {
|
||||
allSuperclassURIs.add(equivURI);
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
|
||||
}
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI));
|
||||
|
||||
List<VClass> vclasses = new ArrayList<VClass>();
|
||||
for(String vclassURI : allSuperclassURIs) {
|
||||
VClass vclass = vcDao.getVClassByURI(vclassURI);
|
||||
if (vclass != null) {
|
||||
vclasses.add(vclass);
|
||||
}
|
||||
}
|
||||
return getAllPropInstByVClasses(vclasses);
|
||||
}
|
||||
|
||||
private void updatePropertyRangeMap(Map<String, Resource[]> map,
|
||||
String propURI,
|
||||
Resource[] ranges) {
|
||||
Resource[] existingRanges = map.get(propURI);
|
||||
if (existingRanges == null) {
|
||||
map.put(propURI, ranges);
|
||||
} else if (existingRanges[0] == null && existingRanges[1] != null) {
|
||||
existingRanges[0] = ranges[0];
|
||||
map.put(propURI, existingRanges);
|
||||
} else if (existingRanges[0] != null && existingRanges[1] == null) {
|
||||
existingRanges[1] = ranges[1];
|
||||
map.put(propURI, existingRanges);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PropertyInstance> getAllPropInstByVClasses(List<VClass> vclasses) {
|
||||
|
||||
List<PropertyInstance> propInsts = new ArrayList<PropertyInstance>();
|
||||
|
||||
if(vclasses == null || vclasses.isEmpty()) {
|
||||
return propInsts;
|
||||
}
|
||||
|
||||
Collections.sort(vclasses, new VClassHierarchyRanker(this.getWebappDaoFactory().getVClassDao()));
|
||||
|
||||
OntModel ontModel = getOntModelSelector().getTBoxModel();
|
||||
|
||||
try {
|
||||
|
||||
ontModel.enterCriticalSection(Lock.READ);
|
||||
|
||||
// map object property URI to an array of two resources:
|
||||
// the first is the "allValuesFrom" resource and the second is
|
||||
// "someValuesFrom"
|
||||
Map<String, Resource[]> applicableProperties =
|
||||
new HashMap<String, Resource[]>();
|
||||
|
||||
try {
|
||||
for (VClass vclass : vclasses) {
|
||||
if (vclass.isAnonymous()) {
|
||||
continue;
|
||||
}
|
||||
String VClassURI = vclass.getURI();
|
||||
|
||||
OntClass ontClass = getOntClass(ontModel,VClassURI);
|
||||
if (ontClass != null) {
|
||||
List<OntClass> relatedClasses = new ArrayList<OntClass>();
|
||||
relatedClasses.addAll(ontClass.listEquivalentClasses().toList());
|
||||
relatedClasses.addAll(ontClass.listSuperClasses().toList());
|
||||
for (OntClass relatedClass : relatedClasses) {
|
||||
// find properties in restrictions
|
||||
if (relatedClass.isRestriction()) {
|
||||
// TODO: check if restriction is something like
|
||||
// maxCardinality 0 or allValuesFrom owl:Nothing,
|
||||
// in which case the property is NOT applicable!
|
||||
Restriction rest = (Restriction) relatedClass.as(Restriction.class);
|
||||
OntProperty onProperty = rest.getOnProperty();
|
||||
if (onProperty != null) {
|
||||
Resource[] ranges = new Resource[2];
|
||||
if (rest.isAllValuesFromRestriction()) {
|
||||
ranges[0] = (rest.asAllValuesFromRestriction()).getAllValuesFrom();
|
||||
} else if (rest.isSomeValuesFromRestriction()) {
|
||||
ranges[1] = (rest.asSomeValuesFromRestriction()).getSomeValuesFrom();
|
||||
}
|
||||
updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Resource> propertyList =
|
||||
getPropertiesWithAppropriateDomainFor(VClassURI);
|
||||
for (Resource prop : propertyList) {
|
||||
if (prop.getNameSpace() != null
|
||||
&& !NONUSER_NAMESPACES.contains(
|
||||
prop.getNameSpace()) ) {
|
||||
StmtIterator rangeSit = prop.listProperties(
|
||||
RDFS.range);
|
||||
Resource rangeRes = null;
|
||||
while (rangeSit.hasNext()) {
|
||||
Statement s = rangeSit.nextStatement();
|
||||
if (s.getObject().isURIResource()) {
|
||||
rangeRes = (Resource) s.getObject();
|
||||
}
|
||||
}
|
||||
Resource[] ranges = new Resource[2];
|
||||
ranges[0] = rangeRes;
|
||||
updatePropertyRangeMap(
|
||||
applicableProperties, prop.getURI(), ranges);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to get applicable properties " +
|
||||
"by examining property restrictions and domains", e);
|
||||
}
|
||||
|
||||
// make the PropertyInstance objects
|
||||
for (String propertyURI : applicableProperties.keySet()) {
|
||||
OntProperty op = ontModel
|
||||
.getOntProperty(propertyURI);
|
||||
if (op == null) {
|
||||
continue;
|
||||
}
|
||||
String domainURIStr = getURIStr(op.getDomain());
|
||||
Resource[] foundRanges = applicableProperties.get(propertyURI);
|
||||
Resource rangeRes = (foundRanges[0] != null)
|
||||
? foundRanges[0]
|
||||
: (op.getRange() == null && foundRanges[1] != null)
|
||||
? foundRanges[1]
|
||||
: op.getRange();
|
||||
PropertyInstance pi = new PropertyInstance();
|
||||
if (rangeRes != null) {
|
||||
String rangeClassURI;
|
||||
if (rangeRes.isAnon()) {
|
||||
rangeClassURI = PSEUDO_BNODE_NS + rangeRes.getId()
|
||||
.toString();
|
||||
} else {
|
||||
rangeClassURI = (String) rangeRes.getURI();
|
||||
}
|
||||
pi.setRangeClassURI(rangeClassURI);
|
||||
VClass range = getWebappDaoFactory().getVClassDao()
|
||||
.getVClassByURI(rangeClassURI);
|
||||
if (range == null) {
|
||||
range = new VClass();
|
||||
range.setURI(rangeClassURI);
|
||||
range.setName(range.getLocalName());
|
||||
}
|
||||
pi.setRangeClassName(range.getName());
|
||||
} else {
|
||||
pi.setRangeClassURI(OWL.Thing.getURI()); // TODO see above
|
||||
}
|
||||
pi.setDomainClassURI(domainURIStr);
|
||||
VClass domain = getWebappDaoFactory().getVClassDao()
|
||||
.getVClassByURI(domainURIStr);
|
||||
if (domain == null) {
|
||||
domain = new VClass();
|
||||
domain.setURI(domainURIStr);
|
||||
domain.setName(domain.getLocalName());
|
||||
}
|
||||
pi.setDomainClassName(domain.getName());
|
||||
pi.setSubjectSide(true);
|
||||
pi.setPropertyURI(op.getURI());
|
||||
pi.setPropertyName(getLabelOrId(op)); // TODO
|
||||
pi.setRangePublic(getLabelOrId(op));
|
||||
pi.setDomainPublic(getLabelOrId(op));
|
||||
propInsts.add(pi);
|
||||
}
|
||||
} finally {
|
||||
ontModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
return propInsts;
|
||||
|
||||
}
|
||||
|
||||
private String getURIStr(Resource res) {
|
||||
String URIStr;
|
||||
if (res == null) {
|
||||
URIStr = OWL.Thing.getURI(); // TODO: rdf:Resource if using RDF model; or option to turn off entirely
|
||||
} else {
|
||||
if (res.isAnon()) {
|
||||
URIStr = PSEUDO_BNODE_NS+res.getId().toString();
|
||||
} else {
|
||||
URIStr = res.getURI();
|
||||
}
|
||||
}
|
||||
return URIStr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -19,21 +19,14 @@ 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.Restriction;
|
||||
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.QuerySolution;
|
||||
import com.hp.hpl.jena.query.ResultSet;
|
||||
import com.hp.hpl.jena.query.Syntax;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
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.vocabulary.OWL;
|
||||
import com.hp.hpl.jena.vocabulary.RDF;
|
||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
|
@ -45,11 +38,11 @@ import edu.cornell.mannlib.vitro.webapp.dao.PropertyInstanceDao;
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualDeletionEvent;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent;
|
||||
public class PropertyInstanceDaoJena extends JenaBaseDao implements
|
||||
public class PropertyInstanceDaoJena extends PropertyDaoJena implements
|
||||
PropertyInstanceDao {
|
||||
|
||||
public PropertyInstanceDaoJena(WebappDaoFactoryJena wadf) {
|
||||
super(wadf);
|
||||
public PropertyInstanceDaoJena(DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) {
|
||||
super(dwf, wadf);
|
||||
}
|
||||
|
||||
public void deleteObjectPropertyStatement(String subjectURI, String propertyURI, String objectURI) {
|
||||
|
@ -99,298 +92,47 @@ public class PropertyInstanceDaoJena extends JenaBaseDao implements
|
|||
}
|
||||
}
|
||||
|
||||
public Collection<PropertyInstance> getAllPossiblePropInstForIndividual(String individualURI) {
|
||||
Individual ind = getWebappDaoFactory().getIndividualDao().getIndividualByURI(individualURI);
|
||||
VClassDao vcDao = getWebappDaoFactory().getVClassDao();
|
||||
@Override
|
||||
public List<PropertyInstance> getAllPossiblePropInstForIndividual(String individualURI) {
|
||||
return filterAndSort(super.getAllPossiblePropInstForIndividual(individualURI));
|
||||
}
|
||||
|
||||
List<VClass> allTypes = ind.getVClasses(false); // include indirect types
|
||||
@Override
|
||||
public List<PropertyInstance> getAllPropInstByVClass(String vclassURI) {
|
||||
return filterAndSort(super.getAllPropInstByVClass(vclassURI));
|
||||
}
|
||||
|
||||
Set<String> allSuperclassURIs = new HashSet<String>();
|
||||
@Override
|
||||
public List<PropertyInstance> getAllPropInstByVClasses(List<VClass> vclasses) {
|
||||
return filterAndSort(super.getAllPropInstByVClasses(vclasses));
|
||||
}
|
||||
|
||||
for (VClass type : allTypes) {
|
||||
String classURI = type.getURI();
|
||||
if (classURI != null) {
|
||||
allSuperclassURIs.add(type.getURI());
|
||||
}
|
||||
for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) {
|
||||
allSuperclassURIs.add(equivURI);
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
|
||||
}
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI));
|
||||
}
|
||||
|
||||
List<VClass> vclasses = new ArrayList<VClass>();
|
||||
for(String vclassURI : allSuperclassURIs) {
|
||||
VClass vclass = vcDao.getVClassByURI(vclassURI);
|
||||
if (vclass != null) {
|
||||
vclasses.add(vclass);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<PropertyInstance> piList = getAllPropInstByVClasses(vclasses);
|
||||
|
||||
for (PropertyInstance pi : piList) {
|
||||
pi.setDomainClassURI(ind.getVClassURI());
|
||||
// TODO: improve. This is so the DWR property editing passes the
|
||||
// individual's VClass to get the right restrictions
|
||||
private List<PropertyInstance>filterAndSort(List<PropertyInstance> propList) {
|
||||
ArrayList<PropertyInstance> propInsts = new ArrayList<PropertyInstance>();
|
||||
for (PropertyInstance propInst : propList) {
|
||||
OntModel tboxModel = getOntModel();
|
||||
tboxModel.enterCriticalSection(Lock.READ);
|
||||
boolean add = false;
|
||||
try {
|
||||
add = (propInst.getPropertyURI() != null
|
||||
&& tboxModel.contains(
|
||||
tboxModel.getResource(
|
||||
propInst.getPropertyURI()),
|
||||
RDF.type,
|
||||
OWL.ObjectProperty));
|
||||
} finally {
|
||||
tboxModel.leaveCriticalSection();
|
||||
}
|
||||
if (add) {
|
||||
propInsts.add(propInst);
|
||||
}
|
||||
}
|
||||
|
||||
return piList;
|
||||
Collections.sort(propInsts, new PropInstSorter());
|
||||
return propInsts;
|
||||
}
|
||||
|
||||
/*
|
||||
* sorts VClasses so that subclasses come before superclasses
|
||||
*/
|
||||
private class VClassHierarchyRanker implements Comparator<VClass> {
|
||||
private VClassDao vcDao;
|
||||
public VClassHierarchyRanker(VClassDao vcDao) {
|
||||
this.vcDao = vcDao;
|
||||
}
|
||||
public int compare(VClass vc1, VClass vc2) {
|
||||
if (vcDao.isSubClassOf(vc1, vc2)) {
|
||||
return -1;
|
||||
} else if (vcDao.isSubClassOf(vc2, vc1)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Collection<PropertyInstance> getAllPropInstByVClass(String classURI) {
|
||||
if (classURI==null || classURI.length()<1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
VClassDao vcDao = getWebappDaoFactory().getVClassDao();
|
||||
|
||||
Set<String> allSuperclassURIs = new HashSet<String>();
|
||||
|
||||
allSuperclassURIs.add(classURI);
|
||||
for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) {
|
||||
allSuperclassURIs.add(equivURI);
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
|
||||
}
|
||||
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI));
|
||||
|
||||
List<VClass> vclasses = new ArrayList<VClass>();
|
||||
for(String vclassURI : allSuperclassURIs) {
|
||||
VClass vclass = vcDao.getVClassByURI(vclassURI);
|
||||
if (vclass != null) {
|
||||
vclasses.add(vclass);
|
||||
}
|
||||
}
|
||||
return getAllPropInstByVClasses(vclasses);
|
||||
}
|
||||
|
||||
private void updatePropertyRangeMap(Map<String, Resource[]> map,
|
||||
String propURI,
|
||||
Resource[] ranges) {
|
||||
Resource[] existingRanges = map.get(propURI);
|
||||
if (existingRanges == null) {
|
||||
map.put(propURI, ranges);
|
||||
} else if (existingRanges[0] == null && existingRanges[1] != null) {
|
||||
existingRanges[0] = ranges[0];
|
||||
map.put(propURI, existingRanges);
|
||||
} else if (existingRanges[0] != null && existingRanges[1] == null) {
|
||||
existingRanges[1] = ranges[1];
|
||||
map.put(propURI, existingRanges);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<PropertyInstance> getAllPropInstByVClasses(List<VClass> vclasses) {
|
||||
|
||||
List<PropertyInstance> propInsts = new ArrayList<PropertyInstance>();
|
||||
|
||||
if(vclasses == null || vclasses.isEmpty()) {
|
||||
return propInsts;
|
||||
}
|
||||
|
||||
Collections.sort(vclasses, new VClassHierarchyRanker(this.getWebappDaoFactory().getVClassDao()));
|
||||
|
||||
OntModel ontModel = getOntModelSelector().getTBoxModel();
|
||||
|
||||
try {
|
||||
|
||||
ontModel.enterCriticalSection(Lock.READ);
|
||||
|
||||
// map object property URI to an array of two resources:
|
||||
// the first is the "allValuesFrom" resource and the second is
|
||||
// "someValuesFrom"
|
||||
Map<String, Resource[]> applicableProperties =
|
||||
new HashMap<String, Resource[]>();
|
||||
|
||||
try {
|
||||
for (VClass vclass : vclasses) {
|
||||
if (vclass.isAnonymous()) {
|
||||
continue;
|
||||
}
|
||||
String VClassURI = vclass.getURI();
|
||||
|
||||
OntClass ontClass = getOntClass(ontModel,VClassURI);
|
||||
if (ontClass != null) {
|
||||
List<OntClass> relatedClasses = new ArrayList<OntClass>();
|
||||
relatedClasses.addAll(ontClass.listEquivalentClasses().toList());
|
||||
relatedClasses.addAll(ontClass.listSuperClasses().toList());
|
||||
for (OntClass relatedClass : relatedClasses) {
|
||||
// find properties in restrictions
|
||||
if (relatedClass.isRestriction()) {
|
||||
// TODO: check if restriction is something like
|
||||
// maxCardinality 0 or allValuesFrom owl:Nothing,
|
||||
// in which case the property is NOT applicable!
|
||||
Restriction rest = (Restriction) relatedClass.as(Restriction.class);
|
||||
OntProperty onProperty = rest.getOnProperty();
|
||||
if (onProperty != null && onProperty.canAs(ObjectProperty.class)) {
|
||||
Resource[] ranges = new Resource[2];
|
||||
if (rest.isAllValuesFromRestriction()) {
|
||||
ranges[0] = (rest.asAllValuesFromRestriction()).getAllValuesFrom();
|
||||
} else if (rest.isSomeValuesFromRestriction()) {
|
||||
ranges[1] = (rest.asSomeValuesFromRestriction()).getSomeValuesFrom();
|
||||
}
|
||||
updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Resource> propertyList = new ArrayList<Resource>();
|
||||
// find properties with class in domain
|
||||
ResIterator pit = ontModel.listSubjectsWithProperty(
|
||||
RDFS.domain, ontClass);
|
||||
while (pit.hasNext()) {
|
||||
Resource prop = pit.nextResource();
|
||||
propertyList.add(prop);
|
||||
}
|
||||
propertyList.addAll(
|
||||
getPropertiesWithUnionDomainIncluding(VClassURI));
|
||||
for (Resource prop : propertyList) {
|
||||
if (prop.getNameSpace() != null
|
||||
&& !NONUSER_NAMESPACES.contains(
|
||||
prop.getNameSpace()) ) {
|
||||
StmtIterator rangeSit = prop.listProperties(
|
||||
RDFS.range);
|
||||
Resource rangeRes = null;
|
||||
while (rangeSit.hasNext()) {
|
||||
Statement s = rangeSit.nextStatement();
|
||||
if (s.getObject().isURIResource()) {
|
||||
rangeRes = (Resource) s.getObject();
|
||||
}
|
||||
}
|
||||
Resource[] ranges = new Resource[2];
|
||||
ranges[0] = rangeRes;
|
||||
updatePropertyRangeMap(
|
||||
applicableProperties, prop.getURI(), ranges);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to get applicable properties " +
|
||||
"by examining property restrictions and domains", e);
|
||||
}
|
||||
|
||||
// make the PropertyInstance objects
|
||||
for (String propertyURI : applicableProperties.keySet()) {
|
||||
ObjectProperty op = ontModel.getObjectProperty(propertyURI);
|
||||
if (op == null) {
|
||||
continue;
|
||||
}
|
||||
String domainURIStr = getURIStr(op.getDomain());
|
||||
Resource[] foundRanges = applicableProperties.get(propertyURI);
|
||||
Resource rangeRes = (foundRanges[0] != null)
|
||||
? foundRanges[0]
|
||||
: (op.getRange() == null && foundRanges[1] != null)
|
||||
? foundRanges[1]
|
||||
: op.getRange();
|
||||
PropertyInstance pi = new PropertyInstance();
|
||||
if (rangeRes != null) {
|
||||
String rangeClassURI;
|
||||
if (rangeRes.isAnon()) {
|
||||
rangeClassURI = PSEUDO_BNODE_NS+rangeRes.getId().toString();
|
||||
} else {
|
||||
rangeClassURI = (String) rangeRes.getURI();
|
||||
}
|
||||
pi.setRangeClassURI(rangeClassURI);
|
||||
try {
|
||||
pi.setRangeClassName(getWebappDaoFactory().getVClassDao().getVClassByURI(rangeClassURI).getName());
|
||||
//pi.setRangeClassName(getLabel(getOntModel().getOntResource(rangeClassURI)));
|
||||
} catch (NullPointerException e) {/* probably a union or intersection - need to handle this somehow */}
|
||||
} else {
|
||||
pi.setRangeClassURI(OWL.Thing.getURI()); // TODO see above
|
||||
}
|
||||
pi.setDomainClassURI(domainURIStr);
|
||||
try {
|
||||
pi.setDomainClassName(getWebappDaoFactory().getVClassDao().getVClassByURI(domainURIStr).getName());
|
||||
//pi.setDomainClassName(getLabel(getOntModel().getOntResource(op.getDomain().getURI())));
|
||||
} catch (NullPointerException e) {/* probably a union or intersection - need to handle this somehow */}
|
||||
pi.setSubjectSide(true);
|
||||
pi.setPropertyURI(op.getURI());
|
||||
pi.setPropertyName(getLabelOrId(op)); // TODO
|
||||
pi.setRangePublic(getLabelOrId(op));
|
||||
pi.setDomainPublic(getLabelOrId(op));
|
||||
propInsts.add(pi);
|
||||
}
|
||||
} finally {
|
||||
ontModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
Collections.sort(propInsts, new PropInstSorter());
|
||||
return propInsts;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* requires SPARQL 1.1 (or ARQ) property path support
|
||||
* @param vclassURI
|
||||
* @return list of property resources with union domains that include the vclass
|
||||
*/
|
||||
private List<Resource> getPropertiesWithUnionDomainIncluding(String vclassURI) {
|
||||
List<Resource> propertyResList = new ArrayList<Resource>();
|
||||
String queryStr =
|
||||
"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n" +
|
||||
"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" +
|
||||
"PREFIX owl: <http://www.w3.org/2002/07/owl#> \n\n " +
|
||||
"SELECT ?p WHERE { \n" +
|
||||
" ?f rdf:first <" + vclassURI + "> . \n" +
|
||||
" ?u rdf:rest* ?f . \n" +
|
||||
" ?d owl:unionOf ?u . \n" +
|
||||
" ?p rdfs:domain ?d . \n" +
|
||||
"}";
|
||||
Query q = QueryFactory.create(queryStr, Syntax.syntaxSPARQL_11);
|
||||
QueryExecution qe = QueryExecutionFactory.create(
|
||||
q, getOntModelSelector().getTBoxModel());
|
||||
try {
|
||||
ResultSet rs = qe.execSelect();
|
||||
while (rs.hasNext()) {
|
||||
QuerySolution qs = rs.nextSolution();
|
||||
propertyResList.add(qs.getResource("p"));
|
||||
}
|
||||
} finally {
|
||||
qe.close();
|
||||
}
|
||||
return propertyResList;
|
||||
}
|
||||
|
||||
private String getURIStr(Resource res) {
|
||||
String URIStr;
|
||||
if (res == null) {
|
||||
URIStr = OWL.Thing.getURI(); // TODO: rdf:Resource if using RDF model; or option to turn off entirely
|
||||
} else {
|
||||
if (res.isAnon()) {
|
||||
URIStr = PSEUDO_BNODE_NS+res.getId().toString();
|
||||
} else {
|
||||
URIStr = res.getURI();
|
||||
}
|
||||
}
|
||||
return URIStr;
|
||||
}
|
||||
|
||||
private class PropInstSorter implements Comparator {
|
||||
public int compare (Object o1, Object o2) {
|
||||
PropertyInstance pi1 = (PropertyInstance) o1;
|
||||
PropertyInstance pi2 = (PropertyInstance) o2;
|
||||
private class PropInstSorter implements Comparator<PropertyInstance> {
|
||||
public int compare (PropertyInstance pi1, PropertyInstance pi2) {
|
||||
try {
|
||||
if (pi1.getDomainPublic().equals(pi2.getDomainPublic())) {
|
||||
return pi1.getRangeClassName().compareTo(pi2.getRangeClassName());
|
||||
|
|
|
@ -536,7 +536,7 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
|
|||
private PropertyInstanceDao propertyInstanceDao = null;
|
||||
public PropertyInstanceDao getPropertyInstanceDao() {
|
||||
if( propertyInstanceDao == null )
|
||||
propertyInstanceDao = new PropertyInstanceDaoJena(this);
|
||||
propertyInstanceDao = new PropertyInstanceDaoJena(dwf, this);
|
||||
return propertyInstanceDao;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue