/*******************************************************************************
* 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.frame.api;
import static org.semantictools.frame.model.OntologyType.RDF;
import static org.semantictools.frame.model.OntologyType.XSD;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import org.semantictools.frame.model.BindVocabulary;
import org.semantictools.frame.model.ContainerRestriction;
import org.semantictools.frame.model.Datatype;
import org.semantictools.frame.model.DublinCoreTerms;
import org.semantictools.frame.model.Field;
import org.semantictools.frame.model.Frame;
import org.semantictools.frame.model.ListType;
import org.semantictools.frame.model.OntologyInfo;
import org.semantictools.frame.model.OntologyType;
import org.semantictools.frame.model.RdfType;
import org.semantictools.frame.model.Uri;
import org.semantictools.frame.model.VannVocabulary;
import org.xml.sax.SAXException;
import com.hp.hpl.jena.datatypes.xsd.impl.XMLLiteralType;
import com.hp.hpl.jena.ontology.AllValuesFromRestriction;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.Ontology;
import com.hp.hpl.jena.ontology.Restriction;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.vocabulary.OWL2;
import com.hp.hpl.jena.vocabulary.RDFS;
public class TypeManager {
private static OntologyInfo XSD_INFO = new OntologyInfo("http://www.w3.org/2001/XMLSchema#", "xs", "http://www.w3.org/2001/XMLSchema#", XSD);
private static OntologyInfo OWL_INFO = new OntologyInfo("http://www.w3.org/2002/07/owl", "owl", "http://www.w3.org/2002/07/owl#", RDF);
private static OntologyInfo RDFS_INFO = new OntologyInfo("http://www.w3.org/2000/01/rdf-schema#", "rdfs", "http://www.w3.org/2000/01/rdf-schema#", RDF);
private static OntologyInfo XDT_INFO = new OntologyInfo("http://www.w3.org/2004/10/xpath-datatypes#", "xdt", "http://www.w3.org/2004/10/xpath-datatypes#", XSD);
private static OntologyInfo BIND = new OntologyInfo("http://purl.org/semantictools/v1/vocab/bind#", "bind", "http://purl.org/semantictools/v1/vocab/bind#", RDF);
private Map<String, Frame> uri2Frame = new HashMap<String, Frame>();
private Map<String, Datatype> uri2Datatype = new HashMap<String, Datatype>();
private Map<String, OntologyInfo> uri2Ontology = new HashMap<String, OntologyInfo>();
private Map<String, ListType> elemURI2ListType = new HashMap<String, ListType>();
private Map<String, ListType> listURI2ListType = new HashMap<String, ListType>();
private Set<String> standard = new HashSet<String>();
private Set<String> standardDatatype = new HashSet<String>();
private Set<String> standardLiteralType = new HashSet<String>();
private OntModel ontModel;
public TypeManager() {
ontModel = ModelFactory.createOntologyModel();
addStandard(XSD_INFO);
addStandard(OWL_INFO);
addStandard(RDFS_INFO);
addStandard(XDT_INFO);
addStandard(BIND);
addDayTimeDuration();
addOwlThing();
addResource();
addStandardLiteralTypes();
}
private void addStandardLiteralTypes() {
standardLiteralType.add(RDFS.Literal.getURI());
standardLiteralType.add(RDFS.Datatype.getURI());
standardLiteralType.add(XMLLiteralType.theXMLLiteralType.getURI());
}
public boolean isStandardLiteralType(String typeURI) {
return standardLiteralType.contains(typeURI);
}
private void addDayTimeDuration() {
Datatype duration = getDatatypeByUri(com.hp.hpl.jena.vocabulary.XSD.duration.getURI());
Datatype dayTimeDuration = new Datatype();
dayTimeDuration.setLocalName("dayTimeDuration");
dayTimeDuration.setUri(XDT_INFO.getNamespaceUri() + "dayTimeDuration");
dayTimeDuration.setBase(duration);
add(dayTimeDuration);
}
public void analyzeOntologies() {
markOntologiesWithClasses(ontModel.listStatements(null, com.hp.hpl.jena.vocabulary.RDF.type, com.hp.hpl.jena.vocabulary.RDFS.Class));
markOntologiesWithClasses(ontModel.listStatements(null, com.hp.hpl.jena.vocabulary.RDF.type, com.hp.hpl.jena.vocabulary.OWL.Class));
// List<OntClass> classList = ontModel.listClasses().toList();
// for (OntClass type : classList) {
// String namespace = type.getNameSpace();
// OntologyInfo info = getOntologyByNamespaceUri(namespace);
// if (info != null) {
// info.setHasClasses(true);
// }
// }
}
private void markOntologiesWithClasses(StmtIterator sequence) {
while (sequence.hasNext()) {
String uri = sequence.next().getSubject().getNameSpace();
if (uri != null) {
OntologyInfo info = getOntologyByNamespaceUri(uri);
if (info != null) {
info.setHasClasses(true);
}
}
}
}
public String getXsdBaseURI(Datatype type) {
if (com.hp.hpl.jena.vocabulary.RDFS.Literal.getURI().equals(type.getUri())) {
return com.hp.hpl.jena.vocabulary.XSD.xstring.getURI();
}
String xsdURI = com.hp.hpl.jena.vocabulary.XSD.getURI();
while (type != null) {
if (type.getUri().startsWith(xsdURI)) {
return type.getUri();
}
type = type.getBase();
}
return null;
}
public boolean isStandard(String ontologyURI) {
return standard.contains(ontologyURI);
}
public boolean isStandardDatatype(String namespaceURI) {
return standardDatatype.contains(namespaceURI);
}
private void addStandard(OntologyInfo info) {
add(info);
if (info.getType() == OntologyType.XSD) {
standardDatatype.add(info.getNamespaceUri());
}
standard.add(info.getNamespaceUri());
}
private void addResource() {
OntClass resourceClass = ontModel.createClass(com.hp.hpl.jena.vocabulary.RDFS.Resource.getURI());
Frame resourceFrame = new Frame(this, resourceClass);
add(resourceFrame);
}
private void addOwlThing() {
OntClass thingClass = ontModel.createClass(OWL2.Thing.getURI());
Frame thingFrame = new Frame(this, thingClass);
add(thingFrame);
}
public OntModel getOntModel() {
return ontModel;
}
public void loadDir(File dir) throws IOException, ParserConfigurationException, SAXException {
FrameBuilder builder = new FrameBuilder(this);
builder.setOntModel(ontModel);
builder.loadDir(dir);
}
public void processOntologies() {
List<Ontology> list = ontModel.listOntologies().toList();
for (Ontology ontology : list) {
String prefix = null;
RDFNode prefixNode = ontology.getPropertyValue(VannVocabulary.preferredNamespacePrefix);
if (prefixNode != null) {
prefix = prefixNode.asLiteral().getString();
} else {
prefixNode = ontology.getPropertyValue(BindVocabulary.suggestedPrefix);
prefix = (prefixNode==null) ? null : prefixNode.asLiteral().getString();
}
/**
* We only manage ontologies that have an explicitly declared prefix.
*/
if (prefix == null) {
continue;
}
RDFNode namespaceNode = ontology.getPropertyValue(VannVocabulary.preferredNamespaceUri);
String namespaceURI = (namespaceNode == null) ? ontology.getURI() : namespaceNode.asLiteral().getString();
String label = ontology.getLabel(null);
String ontologyURI = ontology.getURI();
if (label == null) {
RDFNode labelNode = ontology.getPropertyValue(DublinCoreTerms.title);
if (labelNode == null) {
labelNode = ontology.getPropertyValue(DublinCoreElements.title);
}
if (labelNode != null) {
label = labelNode.asLiteral().getString();
}
}
OntologyInfo info = new OntologyInfo();
info.setOntologyURI(ontologyURI);
info.setPrefix(prefix);
info.setNamespaceUri(namespaceURI);
info.setLabel(label);
add(info);
}
analyzeContainers();
}
private void analyzeContainers() {
Collection<Frame> frameList = listFrames();
for (Frame frame : frameList) {
ContainerRestriction r = frame.getContainerRestriction();
if (r != null) {
Uri membershipSubject = r.getMembershipSubject();
Uri membershipPredicate = r.getMembershipPredicate();
Frame subject = getFrameByUri(membershipSubject.stringValue());
if (subject != null) {
Field field = subject.getFieldByURI(membershipPredicate.stringValue());
if (field != null) {
RdfType type = field.getRdfType();
if (type.canAsFrame()) {
Frame target = type.asFrame();
target.addContainer(frame);
}
}
}
}
}
}
public String getQName(String uri) {
int hash = uri.lastIndexOf('#');
int slash = uri.lastIndexOf('/');
int delim = Math.max(hash, slash);
String namespaceURI = uri.substring(0, delim+1);
OntologyInfo info = getOntologyByNamespaceUri(namespaceURI);
if (info == null) return null;
String localName = uri.substring(delim+1);
return info.getPrefix() + ":" + localName;
}
public static String getLocalName(String uri) {
int hash = uri.lastIndexOf('#');
int slash = uri.lastIndexOf('/');
int delim = Math.max(hash, slash);
String localName = uri.substring(delim+1);
return localName;
}
public static String getDefaultNamespacePrefix(String uri) {
int end = uri.length()-1;
int start = uri.lastIndexOf('/', end);
return uri.substring(start+1, end);
}
public static String getNamespace(String uri) {
int hash = uri.lastIndexOf('#');
int slash = uri.lastIndexOf('/');
int delim = Math.max(hash, slash);
String namespaceURI = uri.substring(0, delim+1);
return namespaceURI;
}
/**
* Returns the OntClass that specifies the type of elements contained within a
* List of type listType. If the given listType is not a subclass of rdf:List,
* then this method returns null.
* @param listType The owl:Class that is to be analyzed as a List.
* @return The OntClass for the elements within the specified type of list, or null
* if the listType is not a subclass of rdf:List.
*/
public OntClass getElementType(OntClass listType) {
List<OntClass> superList = listType.listSuperClasses(true).toList();
for (OntClass superType : superList) {
if (superType.isRestriction()) {
Restriction restriction = superType.asRestriction();
if (restriction.isAllValuesFromRestriction() && restriction.onProperty(com.hp.hpl.jena.vocabulary.RDF.first)) {
AllValuesFromRestriction allValues = restriction.asAllValuesFromRestriction();
return allValues.getAllValuesFrom().as(OntClass.class);
}
}
}
return null;
}
public void add(ListType listType) {
add((Frame) listType);
listURI2ListType.put(listType.getUri(), listType);
elemURI2ListType.put(listType.getElementType().getUri(), listType);
}
public ListType getListTypeByElementUri(String uri) {
return elemURI2ListType.get(uri);
}
public ListType getListTypeByListUri(String uri) {
return listURI2ListType.get(uri);
}
public void add(OntologyInfo info) {
// XSD Ontology Type takes precedence
OntologyInfo oldInfo = uri2Ontology.get(info.getNamespaceUri());
if (oldInfo != null) {
OntologyType type =
(oldInfo.getType() == OntologyType.XSD || info.getType()==OntologyType.XSD) ? OntologyType.XSD :
OntologyType.RDF;
info.setType(type);
oldInfo.setType(type);
} else {
uri2Ontology.put(info.getNamespaceUri(), info);
}
}
public OntologyInfo getOntologyByNamespaceUri(String uri) {
return uri2Ontology.get(uri);
}
public Collection<OntologyInfo> listOntologies() {
return uri2Ontology.values();
}
public void add(Frame frame) {
uri2Frame.put(frame.getUri(), frame);
}
public void add(Datatype datatype) {
uri2Datatype.put(datatype.getUri(), datatype);
}
public Datatype getDatatypeByUri(String uri) {
Datatype type = uri2Datatype.get(uri);
if (type == null) {
String namespace = getNamespace(uri);
if (type == null && ( isStandardDatatype(namespace) || uri.startsWith(RDFS_INFO.getNamespaceUri()) )) {
type = new Datatype();
type.setUri(uri);
type.setLocalName(getLocalName(uri));
if (!namespace.equals(XSD_INFO) && !namespace.equals(RDF)) {
OntClass ontClass = ontModel.getOntClass(uri);
if (ontClass != null) {
List<OntClass> superList = ontClass.listSuperClasses().toList();
for (OntClass superClass : superList) {
String superNamespace = superClass.getNameSpace();
if (isStandard(superNamespace) && !isStandardDatatype(superNamespace)) {
continue;
}
if (superClass != null) {
Datatype base = getDatatypeByUri(superClass.getURI());
if (base != null) {
type.setBase(base);
}
}
}
}
}
add(type);
}
}
return type;
}
public Collection<Datatype> listDatatypes() {
return uri2Datatype.values();
}
public Frame getFrameByUri(String uri) {
return uri2Frame.get(uri);
}
public RdfType getTypeByURI(String uri) {
RdfType type = getFrameByUri(uri);
if (type == null) {
type = getDatatypeByUri(uri);
}
return type;
}
public Collection<Frame> listFrames() {
return uri2Frame.values();
}
public Collection<ListType> listListTypes() {
return listURI2ListType.values();
}
public List<Frame> listFramesInOntology(String ontologyURI) {
List<Frame> result = new ArrayList<Frame>();
Iterator<Frame> sequence = listFrames().iterator();
while (sequence.hasNext()) {
Frame frame = sequence.next();
if (frame.getUri().startsWith(ontologyURI)) {
result.add(frame);
}
}
return result;
}
}