/******************************************************************************* * Copyright 2012 Pearson Education * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package org.semantictools.jsonld; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * LdClass represents an RDF class. * It aggregates all of the restrictions that apply to the RDF class. * It is useful during validation. * * @author Greg McFall * */ public class LdClass implements Serializable, LdType { private static final long serialVersionUID = 1L; private String uri; private Map<String, LdRestriction> restrictions; private List<LdClass> superClassList; private LdTerm term; public LdClass(String classURI) { this.uri = classURI; } public void setURI(String uri) { this.uri = uri; } /** * Return a reference to the RDF class to which the restrictions apply. */ public String getURI() { return uri; } /** * Returns the list of supertypes of this LdClass, or null if there are no * known supertypes. */ public List<LdClass> listSupertypes() { return superClassList; } public void setSupertypes(List<LdClass> superList) { superClassList = superList; } /** * Adds an element to the list of supertypes of this LdClass. */ public void addSupertype(LdClass dr) { if (superClassList == null) { superClassList = new ArrayList<LdClass>(); } if (!superClassList.contains(dr)) { superClassList.add(dr); } } /** * Returns the list of restrictions that apply to this LdClass. */ public List<LdRestriction> listRestrictions() { return restrictions==null ? null : new ArrayList<LdRestriction>(restrictions.values()); } /** * Return the restriction on the specified property. */ public LdRestriction findRestrictionByPropertyURI(String propertyURI) { return (restrictions == null) ? null : restrictions.get(propertyURI); } /** * Add a new restriction that applies to this LdClass. */ public void add(LdRestriction restriction) { if (restrictions == null) { restrictions = new HashMap<String, LdRestriction>(); } restrictions.put(restriction.getPropertyURI(), restriction); } /** * Returns true if the class represented by this domain restriction * has a superclass with the specified URI. */ public boolean hasSuperType(String superURI) { if (superClassList != null) { for (LdClass sr : superClassList) { if (sr.getURI().equals(superURI) || sr.hasSuperType(superURI)) { return true; } } } return false; } /** * Returns the term associated with this RDF class. */ public LdTerm getTerm() { return term; } /** * Sets the term associated with this RDF class */ public void setTerm(LdTerm term) { this.term = term; } public String inferQualifiedPropertyType(String propertyURI) throws AmbiguousRestrictionException { String result = inferQualifiedPropertyType(this, propertyURI); if (result != null) return result; List<LdQualifiedRestriction> list = new ArrayList<LdQualifiedRestriction>(); findQualifiedRestrictions(list, propertyURI); if (list.size()>1) { throw new AmbiguousRestrictionException(list); } return list.isEmpty() ? null : list.get(0).getRangeURI(); } /** * Traverse the super classes looking for a qualified restriction on the specified property. * * @param list The list into which all matching restrictions will be added. * @param propertyURI */ private void findQualifiedRestrictions(List<LdQualifiedRestriction> list, String propertyURI) { if (superClassList == null) return; for (LdClass superclass : superClassList) { LdRestriction r = superclass.findRestrictionByPropertyURI(propertyURI); if (r == null) continue; List<LdQualifiedRestriction> qlist = r.listQualifiedRestrictions(); if (qlist == null || qlist.size()!=1) return; Integer maxCardinality = r.getMaxCardinality(); LdQualifiedRestriction qr = qlist.get(0); int max = maxCardinality==null ? 0 : maxCardinality; int qmax = qr.getMaxCardinality()==null ? 0 : qr.getMaxCardinality(); if (max == qmax) { conditionalAdd(list, qr); } } } /** * Returns true if this RDF class is a subclass of the given otherClass. */ public boolean isSubClassOf(LdClass otherClass) { return hasSuper(this, otherClass.getURI()); } /** * Returns true if the given subClass has an ancestor whose URI is superURI. */ private boolean hasSuper(LdClass subClass, String superURI) { List<LdClass> superList = subClass.listSupertypes(); if (superList != null) { for (LdClass superClass : superList) { if (superClass.getURI().equals(superURI) || hasSuper(superClass, superURI)) return true; } } return false; } /** * Add the given qualified restriction qr to the list, but only if the list does not contain * any restrictions from a domain that is a subtype of the domain associated with qr. */ private void conditionalAdd(List<LdQualifiedRestriction> list, LdQualifiedRestriction qr) { LdClass domain = qr.getRestriction().getDomain(); Iterator<LdQualifiedRestriction> sequence = list.iterator(); while (sequence.hasNext()) { LdQualifiedRestriction other = sequence.next(); LdClass otherDomain = other.getRestriction().getDomain(); if (domain.isSubClassOf(otherDomain)) { // qr is more specific than the other restriction, so // remove the other restriction from the list. sequence.remove(); } if (otherDomain.isSubClassOf(domain)) { // The other restriction is more specific than qr, so ignore qr. return; } } list.add(qr); } private String inferQualifiedPropertyType(LdClass rdfClass, String propertyURI) { if (rdfClass==null) return null; LdRestriction r = findRestrictionByPropertyURI(propertyURI); return (r == null) ? null : r.inferQualifiedRange(); } public String toString() { return "LdClass(" + uri + ")"; } }