001    /***************************************************************************/
002    /*  Copyright (C) 2010-2011, Sebastian Hellmann                            */
003    /*  Note: If you need parts of NLP2RDF in another licence due to licence   */
004    /*  incompatibility, please mail hellmann@informatik.uni-leipzig.de        */
005    /*                                                                         */
006    /*  This file is part of NLP2RDF.                                          */
007    /*                                                                         */
008    /*  NLP2RDF is free software; you can redistribute it and/or modify        */
009    /*  it under the terms of the GNU General Public License as published by   */
010    /*  the Free Software Foundation; either version 3 of the License, or      */
011    /*  (at your option) any later version.                                    */
012    /*                                                                         */
013    /*  NLP2RDF is distributed in the hope that it will be useful,             */
014    /*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
015    /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the           */
016    /*  GNU General Public License for more details.                           */
017    /*                                                                         */
018    /*  You should have received a copy of the GNU General Public License      */
019    /*  along with this program. If not, see <http://www.gnu.org/licenses/>.   */
020    /***************************************************************************/
021    
022    package org.nlp2rdf.ontology.olia;
023    
024    import com.hp.hpl.jena.ontology.*;
025    import com.hp.hpl.jena.rdf.model.*;
026    import com.hp.hpl.jena.util.iterator.ExtendedIterator;
027    import com.hp.hpl.jena.vocabulary.RDFS;
028    import org.mindswap.pellet.jena.PelletReasonerFactory;
029    import org.nlp2rdf.ontology.ClassIndexer;
030    import org.nlp2rdf.ontology.OntologyLoader;
031    import org.slf4j.Logger;
032    import org.slf4j.LoggerFactory;
033    
034    import java.util.*;
035    
036    /**
037     * @author Sebastian Hellmann - http://bis.informatik.uni-leipzig.de/SebastianHellmann
038     */
039    public class OLiAOntology {
040        private static Logger log = LoggerFactory.getLogger(OLiAOntology.class);
041        public static String hasTagURI = "http://purl.org/olia/system.owl#hasTag";
042    
043        private final String ontologyUrl;
044        private final OntModel model;
045        private final ClassIndexer classIndexer = new ClassIndexer();
046        private final Map<String, Individual> tagToIndividualMap = new HashMap<String, Individual>();
047        private final DatatypeProperty hasTag;
048    
049        public OLiAOntology(String ontologyUrl, OntologyLoader ontologyLoader) {
050            this.ontologyUrl = ontologyUrl;
051            this.model = ontologyLoader.loadOntology(ontologyUrl, PelletReasonerFactory.THE_SPEC);
052    
053            ontologyLoader.loadImports(model);
054            log.info("finished loading imports");
055            classIndexer.index(model);
056            log.info("finished indexing");
057    
058            hasTag = model.getDatatypeProperty(hasTagURI);
059            assert (hasTag != null) : "hasTag was null";
060    
061            fillMap();
062        }
063    
064    
065        public String getIndividualURIForTag(String tag) {
066            Individual ind = tagToIndividualMap.get(tag);
067            if (ind == null) {
068                log.error("Individual for tag " + tag + " not found returning null, this indicates a mismatch between OLiA and the annotations actually used: " + ontologyUrl);
069                return null;
070            } else {
071                return ind.getURI();
072            }
073        }
074    
075    
076        public Set<String> getClassURIsForTag(String tag) {
077            Individual ind = tagToIndividualMap.get(tag);
078            log.info("Tag: " + tag + " is matching Individual: " + ind);
079            if (ind == null) {
080                return new HashSet<String>();
081            } else {
082                Set<String> s = new HashSet<String>();
083                for (ExtendedIterator<OntClass> it = ind.listOntClasses(true); it.hasNext(); ) {
084                    OntClass oc = it.next();
085                    if (!oc.isAnon()) {
086                        s.add(oc.getURI());
087                        log.debug("found class " + oc + " for ind: " + ind);
088                    } else {
089                        log.debug("skipping anon " + oc + " for ind: " + ind);
090                    }
091                }
092                log.info("returning classes: " + s);
093                return s;
094            }
095        }
096    
097    
098        public OntModel getHierarchy(String classURI) {
099            return classIndexer.getHierarchyForClassURI(classURI);
100        }
101    
102        private void fillMap() {
103            StringBuilder debug = new StringBuilder();
104            debug.append(ontologyUrl + " - Filling Tag2Uri Map\n");
105    
106            //get all individuals of the anotation model
107            for (ExtendedIterator<Individual> it = model.listIndividuals(); it.hasNext(); ) {
108                Individual ind = it.next();
109    
110    
111                if (ind.isAnon()) {
112                    log.error(ind + " was a blanknode, SKIPPING it");
113                    continue;
114                }
115    
116                //get the tag (should be exactly one)
117                List<RDFNode> l = ind.listPropertyValues(hasTag).toList();
118                if (l.size() == 1) {
119                    Literal tag = l.get(0).asLiteral();
120                    Individual previous = null;
121                    //put it in the map, check, if there is something in there already
122                    if ((previous = tagToIndividualMap.put(tag.getLexicalForm(), ind)) != null) {
123                        //then something smells
124                        log.error(ind.toString() + " has an ambigue tag: " + tag.toString() + " previous " + previous.getURI() + " " + ontologyUrl);
125                    }
126    
127                    debug.append("[ " + tag.getLexicalForm() + " -> " + ind.getURI() + " ]\n");
128                } else if (l.size() == 0) {
129                    //skip bnodes
130                    log.error("Action: SKIPPING");
131                    continue;
132                } else if (l.size() != 1) {
133                    //then something smells
134                    log.error(ind.toString() + " has not exactly one " + hasTag + " property value, but " + l.size() + " " + ontologyUrl);
135                    for (RDFNode n : l) {
136                        log.error("" + n);
137                    }
138                }
139    
140            }
141            log.trace(debug.toString());
142            log.debug("total tags: " + tagToIndividualMap.size());
143        }
144    
145        public static void classHierarchy2PropertyHierarchy(OntModel hierarchy, OntModel out, String allowedNamespace) {
146            for (StmtIterator stm = hierarchy.listStatements(null, RDFS.subClassOf, (RDFNode) null); stm.hasNext(); ) {
147                Statement current = stm.nextStatement();
148                Resource subject = current.getSubject();
149    
150                if (!(subject.getURI().startsWith(allowedNamespace))) {
151                    continue;
152                }
153                if (subject.isAnon()) {
154                    continue;
155                }
156                if (current.getObject().isAnon()) {
157                    continue;
158                }
159                String objectURI = current.getObject().asResource().getURI();
160                if (!(objectURI.startsWith(allowedNamespace))) {
161                    continue;
162                }
163                ObjectProperty op = out.createObjectProperty(subject.getURI());
164                op.addSuperProperty(out.createObjectProperty(objectURI));
165            }
166        }
167    
168        public String getOntologyUrl() {
169            return ontologyUrl;
170        }
171    
172        public Map<String, Individual> getTagToIndividualMap() {
173            return tagToIndividualMap;
174        }
175    }