/******************************************************************************* * Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * File: $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.jastor/src/com/ibm/adtech/boca/jastor/inference/OntologyClass.java,v $ * Created by: * Created on: 01/23/2007 * Revision: $Id: OntologyClass.java 172 2007-07-31 14:22:23Z mroy $ * * Contributors: * IBM Corporation - initial API and implementation * Cambridge Semantics Incorporated - Fork to Anzo *******************************************************************************/ package org.openanzo.rdf.jastor.inference; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.openanzo.analysis.RequestAnalysis; import org.openanzo.glitter.Engine; import org.openanzo.glitter.query.PatternSolution; import org.openanzo.glitter.query.QueryResults; import org.openanzo.rdf.BlankNode; import org.openanzo.rdf.INamedGraph; import org.openanzo.rdf.Resource; import org.openanzo.rdf.Statement; import org.openanzo.rdf.URI; import org.openanzo.rdf.Value; import org.openanzo.rdf.jastor.JastorContext; import org.openanzo.rdf.jastor.JastorException; import org.openanzo.rdf.jastor.JavaIdentifierEncoder; import org.openanzo.rdf.jastor.Thing; import org.openanzo.rdf.owl.DatatypeProperty; import org.openanzo.rdf.owl.OWL11Factory; import org.openanzo.rdf.owl.ObjectProperty; import org.openanzo.rdf.owl.Restriction; import org.openanzo.rdf.owl._Thing; import org.openanzo.rdf.owl.utils.OntologyUtils; import org.openanzo.rdf.query.QuadStoreEngineConfig; import org.openanzo.rdf.query.QueryEncoder; import org.openanzo.rdf.rdfs._Property; import org.openanzo.rdf.utils.StatementUtils; import org.openanzo.rdf.vocabulary.OWL; import org.openanzo.rdf.vocabulary.RDF; import org.openanzo.rdf.vocabulary.RDFS; /** * * This class is a wrapper for an ontology class. Most of the time, the containing ontology class is a name classes but occasionally, instances are internally * used as place holders for restrictions. * * @author Ben Szekely ( <a href="mailto:bhszekel@us.ibm.com">bhszekel@us.ibm.com </a>) * */ public class OntologyClass { private final org.openanzo.rdf.owl.Class ontClass; private final INamedGraph ontGraph; private final JastorContext ctx; private final OntologyComment comment; /** * Construct a new OntologyClass to represent a Thing. Such instances will not contain an org.openanzo.owl.Class, but will return basic naming questions. * Several methods such as listProperties will never be called on such an instance so we leave them unmodified. In particular, the file name generation * routines will generate a file for Thing as though it resided with the generated classes. This is wrong, but OK, since such methods will never be called. * * @param ctx * parent context for this class */ public OntologyClass(JastorContext ctx) { this.ctx = ctx; this.ontGraph = ctx.getOntGraph(); comment = null; ontClass = null; } /** * Construct an OntologyClass wrapper around the given org.openanzo.owl.Class. This org.openanzo.owl.Class can be an anonymous restriction on a property in * which case the listProperties call will return the restricted property * * @param ontClass * Jastor class bean * @param ctx * parent context for this class */ public OntologyClass(org.openanzo.rdf.owl.Class ontClass, JastorContext ctx) { this.ontClass = ontClass; this.ctx = ctx; ontGraph = ctx.getOntGraph(); this.comment = OntologyComment.getOntologyComment(ctx.getOntGraph(), ontClass.resource()); } /** * Get the context for this ontology * * @return the context for this ontology */ public JastorContext getContext() { return ctx; } /** * Get the Jastor Class bean for this class * * @return the Jastor Class bean for this class */ public org.openanzo.rdf.owl.Class getOntClass() { return ontClass; } /** * Get the URI for this class * * @return the URI for this class */ public URI getURI() { if (ontClass == null) return RDFS.RESOURCE; return (URI) ontClass.resource(); } /** * Get the local name of this classes uri * * @return the local name of this classes uri */ public String getLocalName() { if (ontClass == null) return RDFS.RESOURCE.getLocalName(); return ((URI) ontClass.resource()).getLocalName(); } /** * Get the comment for this class * * @return the comment for this class */ public OntologyComment getComment() { return comment; } @Override public String toString() { if (ontClass == null) return RDFS.RESOURCE.toString(); return ontClass.uri(); } @Override public boolean equals(Object o) { if (!(o instanceof OntologyClass)) return false; OntologyClass oc = (OntologyClass) o; return oc.getOntClass().equals(getOntClass()); } @Override public int hashCode() { return getOntClass().hashCode(); } /** * Return a string that can be used to represent one of these as an instance variable * * @return a string that can be used to represent one of these as an instance variable */ public String getVariableName() { String ret = getInterfaceClassname(); String first = ret.substring(0, 1).toLowerCase(); return first + ret.substring(1); } /** * Get the full classname for this class's interface * * @return the full classname for this class's interface */ public String getInterfaceFullClassname() { if (ontClass == null) return ctx.getThingInterface().getName(); Resource uri = getURI(); String pkg = ctx.getPackageForClass(uri); if (ctx.isUseEntireURIForIdentifiers()) return pkg + "." + JavaIdentifierEncoder.encode(uri.toString()); else return pkg + "." + JavaIdentifierEncoder.encode(getLocalName()); } /** * Get the full classname for this class's implementation * * @return the full classname for this class's implementation */ public String getImplFullClassname() { return getInterfaceFullClassname() + "Impl"; } /** * Get the full classname for this class's listener * * @return the full classname for this class's listener */ public String getListenerFullClassname() { return getInterfaceFullClassname() + "Listener"; } /** * Get the full classname for this class's listener adapter * * @return the full classname for this class's listener adapter */ public String getListenerAdapterFullClassname() { return getInterfaceFullClassname() + "ListenerAdapter"; } /** * Get the file for this class's interface * * @param baseDir * directory where file is to be created * @return the file for this class's interface */ public File getInterfaceFile(File baseDir) { return new File(baseDir, getInterfaceFullClassname().replace('.', '/') + ".java"); } /** * Get the file for this class's implementation * * @param baseDir * directory where file is to be created * @return the file for this class's implementation */ public File getImplFile(File baseDir) { return new File(baseDir, getImplFullClassname().replace('.', '/') + ".java"); } /** * Get the file for this class's listener * * @param baseDir * directory where file is to be created * @return the file for this class's listener */ public File getListenerFile(File baseDir) { return new File(baseDir, getListenerFullClassname().replace('.', '/') + ".java"); } /** * Get the classname for this class's interface * * @return the classname for this class's interface */ public String getInterfaceClassname() { return getInterfaceFullClassname().substring(getInterfaceFullClassname().lastIndexOf('.') + 1); } /** * Get the classname for this class's implementation * * @return the classname for this class's implementation */ public String getImplClassname() { return getImplFullClassname().substring(getImplFullClassname().lastIndexOf('.') + 1); } /** * Get the classname for this class's listener * * @return the classname for this class's listener */ public String getListenerClassname() { return getListenerFullClassname().substring(getListenerFullClassname().lastIndexOf('.') + 1); } /** * Get the classname for this class's listener adapter * * @return the classname for this class's listener adapter */ public String getListenerAdapterClassname() { return getListenerAdapterFullClassname().substring(getListenerAdapterFullClassname().lastIndexOf('.') + 1); } /** * Get the package name for the class * * @return the package name for the class */ public String getPackageName() { return ctx.getPackageForClass(getURI()); } /** * Get the full classname for this class's parent factory * * @return the full classname for this class's parent factory */ public String getFactoryFullClassname() { if (ontClass == null) { return ctx.getThingFactory().getName(); } URI ontres = ctx.getOntologyForClass(getURI()); // String pkg = ctx.getPackageForOntology(onturi); String pkg = getPackageName(); String classname = null; if (ctx.isUseEntireURIForIdentifiers()) classname = pkg + "." + JavaIdentifierEncoder.encode(ontres.toString()) + "Factory"; else { if (ontres.getLocalName() == null) { System.err.println("ontres null: " + ontres); System.err.println(RDF.TYPE); } classname = pkg + "." + JavaIdentifierEncoder.encode(ontres.getLocalName()) + "Factory"; } return classname; } /** * Get the classname for this class's parent factory * * @return the classname for this class's parent factory */ public String getFactoryClassname() { return getFactoryFullClassname().substring(getFactoryFullClassname().lastIndexOf('.') + 1); } /** * Get the file for this class's parent factory * * @param baseDir * directory where file is to be created * @return the file for this class's parent factory */ public File getFactoryFile(File baseDir) { return new File(baseDir, getFactoryFullClassname().replace('.', '/') + ".java"); } private List<OntologyProperty> propertyListWithExtensionClasses = null; private List<OntologyProperty> propertyListNoExtensionClasses = null; /** * Get list of OntologyProperties for the class * * @param includeExtensionClasses * whether or not to include properties in extensions from subClassOf, interesectionOf, and unionOf * @return list of OntologyProperties for the class */ public List<OntologyProperty> listProperties(boolean includeExtensionClasses) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } try { if (includeExtensionClasses && propertyListWithExtensionClasses != null) return propertyListWithExtensionClasses; if (!includeExtensionClasses && propertyListNoExtensionClasses != null) return propertyListNoExtensionClasses; try { List<OntologyProperty> props = listProperties(includeExtensionClasses, new ArrayList<org.openanzo.rdf.owl.Class>()); List<OntologyProperty> allprops = null; if (includeExtensionClasses) allprops = props; else { allprops = listProperties(true, new ArrayList<org.openanzo.rdf.owl.Class>()); purgeLooseRestrictions(allprops); } purgeLooseRestrictions(props); markDuplicates(props, allprops); if (includeExtensionClasses) propertyListWithExtensionClasses = props; else propertyListNoExtensionClasses = props; return props; } catch (JastorException e) { e.printStackTrace(); return new ArrayList<OntologyProperty>(); } } finally { if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listProps", (end - start)); } } } /** * Get a deep listing of all named extension classes. Unfortunately, we can't use this routine to do much, but we do use to generate type-closure code. * * @return list of all classes that extend this class */ public List<OntologyClass> listAllExtensionClasses() { try { List<org.openanzo.rdf.owl.Class> visited = new ArrayList<org.openanzo.rdf.owl.Class>(); return listAllExtensionClasses(visited); } catch (JastorException e) { e.printStackTrace(); return new ArrayList<OntologyClass>(); } } /** * Get a list of immediate extension classes derived from subClassOf, intersectionOf and unionOf * * @return a list of immediate extension classes derived from subClassOf, intersectionOf and unionOf */ public List<OntologyClass> listImmediateExtensionClasses() { try { return listImmediateExtensionClasses(new ArrayList<org.openanzo.rdf.owl.Class>(), false); } catch (JastorException e) { e.printStackTrace(); return new ArrayList<OntologyClass>(); } } /** * Finds a cardinality restriction in sub-class hierarchy for the given property. This method is needed because some super-classes won't specify a range, * but all of there subclasses will have the same (hopefully) restriction. If not, this approach will surely break. * * @param prop * property to check * @return Restriction for this property in the classes hierarchy * @throws JastorException */ protected Restriction findCardinalityRestrictionInSubClassHierarchy(OntologyProperty prop) throws JastorException { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } try { Restriction[] resHolder = ctx.getSubClassRestriction(getURI().toString(), prop.getURI()); if (resHolder != null) { return resHolder[0]; } List<org.openanzo.rdf.rdfs.Class> subClasses = OntologyUtils.getSubClasses(ontClass, false); // if this a union class, one of its operands might have // a cardinality restriction. Since they are subclassing us, // we should have the same restriction as well. // TODO: we may need to included subclasses that are Unions as well, though // we have never encountered a case of this. So we'd probably want to // move the union case into getSubClasses // TODO: we may also need to check for classes that include this class as an // intersection. Thing unionOf = ontClass.getUnionOf(); if (unionOf != null) { for (Value value : StatementUtils.getCollectionMembers(unionOf.resource(), ontGraph)) { if (value instanceof URI) { org.openanzo.rdf.owl.Class oc = OWL11Factory.getClass((URI) value, ontGraph); subClasses.add(oc); } } } List<org.openanzo.rdf.owl.Class> visited = new ArrayList<org.openanzo.rdf.owl.Class>(); visited.add(ontClass); Restriction res = null; for (org.openanzo.rdf.rdfs.Class c : subClasses) { if (c.isRDFType(org.openanzo.rdf.owl.Class.TYPE)) { if (!visited.contains(c)) { org.openanzo.rdf.owl.Class cc = OWL11Factory.getClass(c.resource(), c.graph()); visited.add(cc); OntologyClass oc = new OntologyClass(cc, ctx); res = oc.findCardinalityRestrictionInSubClassHierarchy(prop, visited); if (res != null) { break; } } } } ctx.addSubClassRestriction(getURI().toString(), prop.getURI(), res); return res; } finally { if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("findCardResSubClass", (end - start)); } } } /** * List all individuals for this type * * @return all individuals for this type */ public List<Resource> listIndividuals() { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } ArrayList<Resource> list = new ArrayList<Resource>(); Iterable<Statement> stmts = ontGraph.find(null, RDF.TYPE, getOntClass().resource()); for (Statement stmt : stmts) { Resource subject = stmt.getSubject(); // protect against generating individuals for RDFS and OWL ontologies if (subject instanceof URI) { URI suburi = (URI) subject; if (suburi.getNamespace().equals(RDFS.NAMESPACE) || suburi.getNamespace().equals(OWL.NAMESPACE) || suburi.getNamespace().equals(RDF.NAMESPACE)) { continue; } list.add(subject); } } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listIndividuals", (end - start)); } return list; } /** * Get the identifier name for the given individual * * @param ind * resource of individual * @return the identifier name for the given individual */ public String getIndividualIdentifierName(Resource ind) { if (individualDuplicateLocalName(ind)) { return JavaIdentifierEncoder.encode(ind.toString()); } else { if (ind instanceof BlankNode) { return JavaIdentifierEncoder.encode(ind.toString()); } else { return JavaIdentifierEncoder.encode(((URI) ind).getLocalName()); } } } /** * Is this an enumerated class * * @return true if this an enumerated class */ public boolean isEnumeratedClass() { return (ontClass.getOneOf() != null); } /** * Return the oneOf classes * * @return the oneOf classes */ public List<Resource> listOneOfClasses() { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } Thing oneOf = ontClass.getOneOf(); List<Resource> list = new ArrayList<Resource>(); for (Value value : StatementUtils.getCollectionMembers(oneOf.resource(), ontGraph)) { if (value instanceof Resource) { list.add((Resource) value); } } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listOneOf", (end - start)); } return list; } private boolean individualDuplicateLocalName(Resource ind) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } try { Iterable<Statement> stmts = ontGraph.find(null, RDF.TYPE, getOntClass().resource()); boolean found = false; for (Statement stmt : stmts) { if (ind instanceof URI && stmt.getSubject() instanceof URI) { URI subject = (URI) stmt.getSubject(); if (subject.getLocalName().equals(((URI) ind).getLocalName())) { if (found) return true; else found = true; } } else if (ind instanceof BlankNode && stmt.getSubject() instanceof BlankNode) { BlankNode subject = (BlankNode) stmt.getSubject(); if (subject.equals(ind)) { if (found) return true; else found = true; } } } return false; } finally { if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("indDupLocalname", (end - start)); } } } private Restriction findCardinalityRestrictionInSubClassHierarchy(OntologyProperty prop, List<org.openanzo.rdf.owl.Class> visited) throws JastorException { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } String query = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX owl: <http://www.w3.org/2002/07/owl#> SELECT ?res WHERE {" + QueryEncoder.encodeForQuery(ontClass.resource()) + " rdfs:subClassOf ?res . ?res owl:onProperty " + QueryEncoder.encodeForQuery(prop.getOntProperty().resource()) + "}"; QuadStoreEngineConfig config = new QuadStoreEngineConfig(ctx.getOntGraphQuadStore()); Engine glitter = new Engine(config); try { QueryResults results = glitter.executeQuery(null, query, Collections.singleton(ontGraph.getNamedGraphUri()), Collections.<URI> emptySet()); Iterator<PatternSolution> iter = results.getSelectResults().iterator(); while (iter.hasNext()) { PatternSolution next = iter.next(); Resource restrictionRes = (Resource) next.getBinding("res"); if (restrictionRes != null) { Restriction restriction = OWL11Factory.getRestriction(restrictionRes, ontGraph); Iterable<Integer> res = restriction.getCardinality(); if (res.iterator().hasNext()) { return restriction; } Iterable<Integer> res2 = restriction.getMaxCardinality(); if (res2.iterator().hasNext()) { return restriction; } } } } catch (Exception e) { throw new JastorException(e, "Error querying for restriction"); } // List<org.openanzo.rdf.rdfs.Class> subClasses = OntologyUtils.getSubClasses(ontClass, false); // Restriction restriction = null; // for (org.openanzo.rdf.rdfs.Class c : subClasses) { // if (c.isRDFType(org.openanzo.rdf.owl.Class.TYPE)) { // org.openanzo.rdf.owl.Class subClass = OWL11Factory.getClass(c.resource(), c.graph()); // if (!visited.contains(subClass) && restriction == null) { // OntologyClass oc = new OntologyClass(subClass, ctx); // restriction = oc.findCardinalityRestrictionInSubClassHierarchy(prop, visited); // } // } // } // return restriction; finally { if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("findCardSubInternal", (end - start)); } } return null; } private final HashMap<String, List<OntologyProperty>> listCache = new HashMap<String, List<OntologyProperty>>(); private List<OntologyProperty> listProperties(boolean includeExtensionClasses, List<org.openanzo.rdf.owl.Class> visitedClasses) throws JastorException { String cacheKey = String.valueOf(includeExtensionClasses + visitedClasses.toString()); List<OntologyProperty> cachedList = listCache.get(cacheKey); if (cachedList != null) { return cachedList; } ArrayList<OntologyProperty> list = new ArrayList<OntologyProperty>(); // we may have visited this class since it was queued up to search. So just add // a final cycle check as a catch-all if (visitedClasses.contains(ontClass)) return list; visitedClasses.add(ontClass); // add properties from immediate superclasses and unions (which will // themselves, recurse) if (includeExtensionClasses) { List<OntologyClass> extClasses = listImmediateExtensionClasses(visitedClasses, false); Iterator<OntologyClass> it = extClasses.iterator(); while (it.hasNext()) { OntologyClass extClass = it.next(); if (!(extClass.getOntClass() instanceof BlankNode)) { List<OntologyProperty> extClassProperties = extClass.listProperties(true, visitedClasses); // this call overwrites the role made in any recursive call // because we only care about role from the perspective of the root // caller setRoleOfProperties(extClassProperties, OntologyProperty.ROLE_EXTENSIONCLASS); // must check for duplicates Iterator<OntologyProperty> itr = extClassProperties.iterator(); while (itr.hasNext()) { OntologyProperty extprop = itr.next(); if (!list.contains(extprop)) list.add(extprop); } } } // merge loose restrictions with actual properties mergeProperties(list); } // check for any restrictions declared here that may apply to properties // from extension classes. Restrictions are contained in anonymous // extension classes // note, we moved this outside the include extension class case because want to get union domain properties // in both cases. Even though union domains are handled elsewhere, we keep this code outside that condition Iterator<OntologyClass> it = listImmediateExtensionClasses(visitedClasses, true).iterator(); while (it.hasNext()) { OntologyClass extClass = it.next(); if (extClass.getOntClass().isRDFType(Restriction.TYPE)) { Restriction res = OWL11Factory.createRestriction(extClass.getOntClass().resource(), ontGraph); _Property prop = res.getOnProperty(); if (prop == null) { System.err.println("Warning: class " + getOntClass().resource() + " has restrictions on unknown properties"); continue; } Iterator<OntologyProperty> itr2 = list.iterator(); OntologyProperty restrictedProp = null; // iterate through the list of properties found so far and see if there is one // the restriction applies to while (itr2.hasNext()) { OntologyProperty op = itr2.next(); if (op.getOntProperty().resource().equals(prop.resource())) { restrictedProp = op; break; } } // add the restriction to the proprety..will be dealt with by // the property if (restrictedProp != null) restrictedProp.addRestriction(res); // if we didn't find a property in the extension classes for the restriction, // we have a few choices to make... else { org.openanzo.rdf.rdfs.Class domain = OntologyProperty.getDomain(prop); if (domain != null && domain.resource() instanceof BlankNode && domain.isRDFType(org.openanzo.rdf.owl.Class.TYPE) && (OWL11Factory.getClass(domain.resource(), ontGraph).getUnionOf() != null)) { // ignore restrictions on union domains, they are taken care of below } else if (domain == null || domain.resource().equals(RDFS.RESOURCE)) { // if the domain is null, then we have a property with no declared domain. Although, we suspect // this is not good OWL, we allow the user to do it anyway and assume the user wants to have // this class as a possible domain. list.add(new OntologyProperty(prop, this)); } else if (domain instanceof BlankNode || !domain.resource().equals(ontClass.resource())) { // add a placeholder for this restriction if it doesn't belong to us. This restriction // will get added to the property from another branch of the type-hierarchy. list.add(new OntologyProperty(prop, res)); } else { // In rare cases, a restriction might be added to this property through // an Intersection, not subclass. This handles that case. Thing intersectionOf = getOntClass().getIntersectionOf(); if (intersectionOf != null) { // if one of the operands is the restriction we are considering // then add the restricted property and the restriction for (Value value : StatementUtils.getCollectionMembers(intersectionOf.resource(), ontGraph)) if (value instanceof Resource) { org.openanzo.rdf.owl.Class op = OWL11Factory.getClass((Resource) value, ontGraph); if (op.equals(res)) { OntologyProperty property = new OntologyProperty(prop, this); // add the restriction because getPrimaryRestriction in the constructor won't // find it. property.addRestriction(res); list.add(property); } } } } } // otherwise, we have a normal restriction on a declared or union domain property, // handeled below } } // end restriction search // finally, add properties declared here List<_Property> declprops = new ArrayList<_Property>(); List<OntologyProperty> udps = ctx.getUnionDomainProperties(getURI()); for (OntologyProperty prop : udps) { declprops.add(prop.getOntProperty()); } // FIND DECLARED PROPERTIES List<_Property> itr = findDeclaredProperties(); for (_Property prop : itr) { declprops.add(prop); } addOpenDomainProperties(declprops); for (_Property prop : declprops) { // make sure that if we have an open domain property // that it is defined in this ontology..skip it otherwise org.openanzo.rdf.rdfs.Class domain = OntologyProperty.getDomain(prop); if (domain == null || domain.resource().equals(RDFS.RESOURCE) || domain.equals(_Thing.TYPE)) { // have to also check if the class of the property is defined in an ontology of any extension class boolean includeODP = ctx.isPropetyAndClassDefinedInSameOntology(prop.resource(), getURI()); if (!includeODP) { for (OntologyClass extClass : listAllExtensionClasses()) { if (ctx.isPropetyAndClassDefinedInSameOntology(prop.resource(), extClass.getURI())) { includeODP = true; break; } } } if (!includeODP) continue; } // more efficient to scan the list than construct an OntologyProperty unnecessarily // to check for List membership because the constructor does a query. boolean found = false; Iterator<OntologyProperty> props = list.iterator(); while (props.hasNext() && !found) { OntologyProperty p = props.next(); if (p.getOntProperty().resource().equals(prop.resource())) found = true; } if (!found) { OntologyProperty prop2 = new OntologyProperty(prop, this); list.add(prop2); } } listCache.put(cacheKey, list); return list; } /** * compute a list of _Property that have no domain, or domain of Resource or Thing */ private void addOpenDomainProperties(List<_Property> propertyList) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } List<_Property> odProps = ctx.getOpenDomainProperties(); for (_Property prop : odProps) { if (!propertyList.contains(prop)) { propertyList.add(prop); } } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("addODProps", (end - start)); } } private List<OntologyClass> listAllExtensionClasses(List<org.openanzo.rdf.owl.Class> visited) throws JastorException { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } visited.add(ontClass); List<OntologyClass> scs = listImmediateExtensionClasses(visited, false); List<OntologyClass> recur = new ArrayList<OntologyClass>(); Iterator<OntologyClass> it = scs.iterator(); while (it.hasNext()) { OntologyClass oc = it.next(); if (!visited.contains(oc.getOntClass())) { List<OntologyClass> list = oc.listAllExtensionClasses(visited); for (int i = 0; i < list.size(); i++) { if (!recur.contains(list.get(i))) { recur.add(list.get(i)); } } } } recur.addAll(scs); if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listAllExt", (end - start)); } return recur; } private List<OntologyClass> listImmediateExtensionClasses(List<org.openanzo.rdf.owl.Class> visited, boolean includeAnon) throws JastorException { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } // get classes from subClassOf List<OntologyClass> list = listImmediateSuperClasses(visited, includeAnon); // get classes from other side of unionOf List<OntologyClass> list2 = listImmediateUnionClasses(visited); for (int i = 0; i < list2.size(); i++) { if (!list.contains(list2.get(i))) list.add(list2.get(i)); } // get classes from intersectionOf list2 = listImmediateIntersectionClasses(visited, includeAnon); for (int i = 0; i < list2.size(); i++) { if (!list.contains(list2.get(i))) list.add(list2.get(i)); } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listImmExt", (end - start)); } return list; } private List<OntologyClass> listImmediateSuperClasses(List<org.openanzo.rdf.owl.Class> visited, boolean includeAnon) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } Iterable<org.openanzo.rdf.rdfs.Class> subClassOf = ontClass.getSubClassOf(); ArrayList<OntologyClass> list = new ArrayList<OntologyClass>(); for (org.openanzo.rdf.rdfs.Class ontClass : subClassOf) { if (!includeAnon && ontClass.resource() instanceof BlankNode) continue; //if (!includeAnon && ((URI) ontClass.resource()).getLocalName() != null && ((URI) ontClass.resource()).getLocalName().equals("Resource")) // continue; if (ontClass.resource() != null && ontClass.resource().equals(_Thing.TYPE)) continue; if (visited.contains(ontClass)) continue; if (ontClass.resource().toString().indexOf("EconomicDemographic") != -1) { System.err.println(ontClass); } if (!ontClass.isRDFType(org.openanzo.rdf.owl.Class.TYPE) && !includeAnon) { continue; } OntologyClass oc = new OntologyClass(OWL11Factory.getClass(ontClass.resource(), ontGraph), ctx); list.add(oc); } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listImmSc", (end - start)); } return list; } /** * This method not returns a list of classes that are a union of us because those are what we want to extend * * @param visited * @return */ private List<OntologyClass> listImmediateUnionClasses(List<org.openanzo.rdf.owl.Class> visited) throws JastorException { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } Iterator<OntologyClass> itr = ctx.getUnionClassExtensions(getURI()).iterator(); ArrayList<OntologyClass> list = new ArrayList<OntologyClass>(); while (itr.hasNext()) { OntologyClass ontologyClass = itr.next(); if (visited.contains(ontologyClass.getOntClass())) continue; list.add(ontologyClass); } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listImmUnion", (end - start)); } return list; } private List<OntologyClass> listImmediateIntersectionClasses(List<org.openanzo.rdf.owl.Class> visited, boolean includeAnon) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } List<OntologyClass> list = new ArrayList<OntologyClass>(); Thing intersectionOf = ontClass.getIntersectionOf(); if (intersectionOf != null) { for (Value value : StatementUtils.getCollectionMembers(intersectionOf.resource(), ontGraph)) { if (value instanceof Resource) { org.openanzo.rdf.owl.Class rangeClazz = OWL11Factory.getClass((Resource) value, ontGraph); if (value instanceof BlankNode) { if (includeAnon) { list.add(new OntologyClass(rangeClazz, ctx)); } } else { list.add(new OntologyClass(rangeClazz, ctx)); } } } } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("listImmIntx", (end - start)); } return list; } /** * Merge any loose restriction properties into the property it comes from * * @param props */ private void mergeProperties(List<OntologyProperty> props) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } // this is innefficient, but the size of these lists should be small. // this list stores loose restrictions that cannot be merged at this // level and must be passed down to // the calling subclass or union class. List<OntologyProperty> unboundlr = new ArrayList<OntologyProperty>(); OntologyProperty lr = findLooseRestriction(props); while (lr != null) { props.remove(lr); OntologyProperty prop = findRealProp(props, lr); if (prop == null) // not sure about this...will follow up later. unboundlr.add(lr); else prop.addRestrictions(lr.getRestrictions()); lr = findLooseRestriction(props); } props.addAll(unboundlr); if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("mergeProps", (end - start)); } } /** * Find a real property for a loose restriction */ private OntologyProperty findRealProp(List<OntologyProperty> props, OntologyProperty lr) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } try { for (OntologyProperty prop : props) { if (prop.isLooseRestriction()) continue; if (prop.getURI().equals(lr.getURI())) { return prop; } } return null; } finally { if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("findRealProp", (end - start)); } } } /** * returns a loose restriction if one exists * * @return */ private OntologyProperty findLooseRestriction(List<OntologyProperty> props) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } try { for (OntologyProperty prop : props) { if (prop.isLooseRestriction()) { return prop; } } } finally { if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("findLR", (end - start)); } } return null; } /** * remove any loose restrictions from this property list * * @param props */ private void purgeLooseRestrictions(List<OntologyProperty> props) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } Iterator<OntologyProperty> it = props.iterator(); while (it.hasNext()) { OntologyProperty prop = it.next(); if (prop.isLooseRestriction()) { // /System.err.println("removing loose res: " + prop); it.remove(); } } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("purgeLR", (end - start)); } } /** * Set the role of the all the given properties. Also make this OntologyClass the activeClass * * @param props * @param role */ private void setRoleOfProperties(List<OntologyProperty> props, int role) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } for (OntologyProperty prop : props) { prop.setRole(role); prop.setActiveClass(this); } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("setRole", (end - start)); } } /** * Go through the list of properties and mark any properties as duplicates... */ private void markDuplicates(List<OntologyProperty> props, List<OntologyProperty> allprops) { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } for (int i = 0; i < allprops.size(); i++) { OntologyProperty propi = allprops.get(i); String namei = propi.getPropertyName(); for (int j = 0; j < props.size(); j++) { OntologyProperty propj = props.get(j); String namej = propj.getPropertyName(); if (!propi.getURI().equals(propj.getURI()) && namei.equals(namej)) { propj.setDuplicateProperty(true); } } } if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("markDup", (end - start)); } } static Set<Resource> calls = new HashSet<Resource>(); private List<_Property> findDeclaredProperties() throws JastorException { long start = 0; if (RequestAnalysis.isAnalysisEnabled()) { start = System.currentTimeMillis(); } List<_Property> properties = ctx.getDeclaredProperties(getURI()); if (properties == null) { properties = new ArrayList<_Property>(); String query = "SELECT ?res WHERE {?res " + QueryEncoder.encodeForQuery(RDF.TYPE) + " " + QueryEncoder.encodeForQuery(DatatypeProperty.TYPE) + " . ?res " + QueryEncoder.encodeForQuery(RDFS.domain) + " " + QueryEncoder.encodeForQuery(ontClass.resource()) + "}"; QuadStoreEngineConfig config = new QuadStoreEngineConfig(ctx.getOntGraphQuadStore()); Engine glitter = new Engine(config); try { QueryResults results = glitter.executeQuery(null, query, Collections.singleton(ontGraph.getNamedGraphUri()), Collections.<URI> emptySet()); Iterator<PatternSolution> sol = results.getSelectResults().iterator(); while (sol.hasNext()) { PatternSolution next = sol.next(); Resource propRes = (Resource) next.getBinding("res"); if (propRes != null) { DatatypeProperty dp = OWL11Factory.getDatatypeProperty(propRes, ontGraph); if (dp.isRDFType(DatatypeProperty.TYPE)) { properties.add(dp); } } } } catch (Exception e) { throw new JastorException(e, "Error querying for properties"); } query = "SELECT ?res WHERE {?res " + QueryEncoder.encodeForQuery(RDF.TYPE) + " " + QueryEncoder.encodeForQuery(ObjectProperty.TYPE) + " . ?res " + QueryEncoder.encodeForQuery(RDFS.domain) + " " + QueryEncoder.encodeForQuery(ontClass.resource()) + "}"; try { QueryResults results = glitter.executeQuery(null, query, Collections.singleton(ontGraph.getNamedGraphUri()), Collections.<URI> emptySet()); Iterator<PatternSolution> iter = results.getSelectResults().iterator(); while (iter.hasNext()) { PatternSolution next = iter.next(); Resource propRes = (Resource) next.getBinding("res"); if (propRes != null) { DatatypeProperty dp = OWL11Factory.getDatatypeProperty(propRes, ontGraph); if (dp.isRDFType(ObjectProperty.TYPE)) { properties.add(dp); } } } } catch (Exception e) { throw new JastorException(e, "Error querying for properties"); } ctx.setDeclaredProperties(getURI(), properties); if (RequestAnalysis.isAnalysisEnabled()) { long end = System.currentTimeMillis(); RequestAnalysis.incrementAnalysisPropertyCount("findDeclProps", (end - start)); } } return properties; } }