001 // This file is part of the Attempto Java Packages.
002 // Copyright 2008, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
003 //
004 // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
005 // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
006 // either version 3 of the License, or (at your option) any later version.
007 //
008 // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
009 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
010 // PURPOSE. See the GNU Lesser General Public License for more details.
011 //
012 // You should have received a copy of the GNU Lesser General Public License along with the Attempto
013 // Java Packages. If not, see http://www.gnu.org/licenses/.
014
015 package ch.uzh.ifi.attempto.acewiki.core.ontology;
016
017 import java.io.File;
018 import java.io.FileInputStream;
019 import java.io.FileOutputStream;
020 import java.io.IOException;
021 import java.io.StringWriter;
022 import java.net.URI;
023 import java.net.URISyntaxException;
024 import java.util.ArrayList;
025 import java.util.Collection;
026 import java.util.HashMap;
027 import java.util.HashSet;
028 import java.util.Hashtable;
029 import java.util.List;
030 import java.util.Set;
031
032 import org.coode.owlapi.owlxml.renderer.OWLXMLRenderer;
033 import org.mindswap.pellet.owlapi.Reasoner;
034 import org.semanticweb.owl.apibinding.OWLManager;
035 import org.semanticweb.owl.inference.OWLReasoner;
036 import org.semanticweb.owl.inference.OWLReasonerException;
037 import org.semanticweb.owl.io.StringInputSource;
038 import org.semanticweb.owl.model.OWLClass;
039 import org.semanticweb.owl.model.OWLIndividual;
040 import org.semanticweb.owl.model.OWLOntology;
041 import org.semanticweb.owl.model.OWLOntologyCreationException;
042 import org.semanticweb.owl.model.OWLOntologySetProvider;
043 import org.semanticweb.owl.model.OWLSubClassAxiom;
044 import org.semanticweb.owl.util.OWLOntologyMerger;
045
046 import uk.ac.manchester.cs.owl.OWLClassImpl;
047 import uk.ac.manchester.cs.owl.OWLDataFactoryImpl;
048 import ch.uzh.ifi.attempto.acewiki.Logger;
049
050 /**
051 * This class represents an AceWiki ontology which consists of ontology element definitions and
052 * of ontological statements. Each ontology element has its own article that consists of ontological
053 * statements.
054 *
055 * @author Tobias Kuhn
056 */
057 public class Ontology {
058
059 private static final HashMap<String, Ontology> ontologies = new HashMap<String, Ontology>();
060
061 private ArrayList<OntologyElement> elements = new ArrayList<OntologyElement>();
062 private Hashtable<String, OntologyElement> wordIndex = new Hashtable<String, OntologyElement>();
063 private Hashtable<Long, OntologyElement> idIndex = new Hashtable<Long, OntologyElement>();
064
065 private final String name;
066 private final String baseURI;
067 private long idCount = 0;
068 private long stateID = 0;
069
070 private OWLReasoner reasoner;
071 private OWLOntology differentIndividualsAxiom;
072
073 /**
074 * Creates a new empty ontology with the given name and base URI.
075 *
076 * @param name The name of the ontology.
077 * @param baseURI The base URI that is used to identify the ontology elements.
078 */
079 private Ontology(String name, String baseURI) {
080 this.name = name.toString(); // null value throws an exception
081 this.baseURI = baseURI;
082 if (baseURI == null) {
083 baseURI = "";
084 }
085 ontologies.put(name, this);
086 }
087
088 /**
089 * Loads an ontology (or creates an empty ontology if the ontology cannot be found). The complete
090 * URI of the ontology is baseURI + name.
091 *
092 * @param name The name of the ontology.
093 * @param baseURI The base URI that is used to identify the ontology elements.
094 * @return The loaded ontology.
095 */
096 public synchronized static Ontology loadOntology(String name, String baseURI) {
097 if (ontologies.get(name) != null) {
098 return ontologies.get(name);
099 }
100 Ontology ontology = new Ontology(name, baseURI);
101 ontology.log("loading ontology");
102 File dataDir = new File("data/" + name);
103 if (dataDir.exists()) {
104 for (File file : dataDir.listFiles()) {
105 try {
106 long id = new Long(file.getName());
107 ontology.log("reading file: " + file.getName());
108 FileInputStream in = new FileInputStream(file);
109 byte[] bytes = new byte[in.available()];
110 in.read(bytes);
111 in.close ();
112 String s = new String(bytes);
113 OntologyElement.loadOntologyElement(s, id, ontology);
114 } catch (NumberFormatException ex) {
115 ontology.log("ignoring file: " + file.getName());
116 } catch (IOException ex) {
117 ontology.log("cannot read file: " + file.getName());
118 }
119 }
120 } else {
121 ontology.log("no data found; blank ontology is created");
122 }
123 ontology.refreshReasoner();
124 return ontology;
125 }
126
127 synchronized void save(OntologyElement oe) {
128 if (!(new File("data")).exists()) (new File("data")).mkdir();
129 if (!(new File("data/" + name)).exists()) (new File("data/" + name)).mkdir();
130
131 if (!elements.contains(oe)) {
132 (new File("data/" + name + "/" + oe.getId())).delete();
133 return;
134 }
135
136 try {
137 FileOutputStream out = new FileOutputStream("data/" + name + "/" + oe.getId());
138 out.write(oe.serialize().getBytes("UTF-8"));
139 out.close();
140 } catch (IOException ex) {
141 ex.printStackTrace();
142 }
143 }
144
145 synchronized void register(OntologyElement element) {
146 if (elements.contains(element)) {
147 log("error: element already registered");
148 throw new RuntimeException("Registration failed: Element is already registered.");
149 }
150
151 log("register: " + element);
152 stateID++;
153
154 if (element.getId() == -1) {
155 element.setId(nextId());
156 }
157 elements.add(element);
158 idIndex.put(element.getId(), element);
159 if (element.getId() > idCount) idCount = element.getId();
160
161 for (String word : element.getWords()) {
162 if (word == null) continue;
163
164 if (wordIndex.get(word) == null) {
165 wordIndex.put(word, element);
166 } else if (wordIndex.get(word) != element) {
167 log("error: word already used");
168 throw new RuntimeException("Registration failed: The word '" + word + "' is already used.");
169 }
170 }
171
172 if (element instanceof Individual) {
173 updateDifferentIndividualsAxiom();
174 }
175
176 }
177
178 synchronized void removeFromWordIndex(OntologyElement oe) {
179 for (String word : oe.getWords()) {
180 if (word != null) {
181 wordIndex.remove(word);
182 }
183 }
184 }
185
186 synchronized void addToWordIndex(OntologyElement oe) {
187 for (String word : oe.getWords()) {
188 if (word != null) {
189 if (wordIndex.get(word) == null) {
190 wordIndex.put(word, oe);
191 } else if (wordIndex.get(word) != oe) {
192 throw new RuntimeException("Word update failed: The word '" + word + "' is already used.");
193 }
194 }
195 }
196 }
197
198 /**
199 * Removes the given ontology element from the ontology.
200 *
201 * @param element The ontology element to be removed.
202 */
203 public synchronized void remove(OntologyElement element) {
204 if (!elements.contains(element)) {
205 log("error: unknown element");
206 return;
207 }
208
209 log("remove: " + element.getWord());
210 stateID++;
211
212 for (String word : element.getWords()) {
213 if (word == null) continue;
214 wordIndex.remove(word);
215 }
216 elements.remove(element);
217 idIndex.remove(element.getId());
218 for (Sentence s : element.getSentences()) {
219 retractSentence(s);
220 }
221 save(element);
222
223 if (element instanceof Individual) {
224 updateDifferentIndividualsAxiom();
225 }
226
227 }
228
229 /**
230 * Returns all the sentences that use the given word form (by word number) of the given
231 * ontology element.
232 *
233 * @param element The ontology element.
234 * @param wordNumber The word number.
235 * @return A list of all sentence that contain the word.
236 */
237 public synchronized List<Sentence> getReferences(OntologyElement element, int wordNumber) {
238 List<Sentence> list = new ArrayList<Sentence>();
239 for (OntologyElement el : elements) {
240 for (Sentence s : el.getSentences()) {
241 if ((wordNumber == -1 && s.contains(element)) || (wordNumber > -1 && s.contains(element, wordNumber))) {
242 list.add(s);
243 }
244 }
245 }
246 return list;
247 }
248
249 /**
250 * Returns all the sentences that use the given ontology element (no matter which word form
251 * is used).
252 *
253 * @param element The ontology element.
254 * @return A list of all sentence that contain the ontology element.
255 */
256 public synchronized List<Sentence> getReferences(OntologyElement element) {
257 return getReferences(element, -1);
258 }
259
260 /**
261 * Returns the ontology element with the given name, or null if there is no such element.
262 *
263 * @param name The name of the ontology element.
264 * @return The ontology element.
265 */
266 public OntologyElement get(String name) {
267 return wordIndex.get(name);
268 }
269
270 OntologyElement get(long id) {
271 return idIndex.get(id);
272 }
273
274 /**
275 * Returns all ontology elements.
276 *
277 * @return A collection of all ontology elements.
278 */
279 public Collection<OntologyElement> getOntologyElements() {
280 return new ArrayList<OntologyElement>(elements);
281 }
282
283 /**
284 * Returns true if the given ontology element is contained by the ontology (identity check).
285 *
286 * @param ontologyElement The ontology element.
287 * @return true if the ontology element is contained by the ontology.
288 */
289 public boolean contains(OntologyElement ontologyElement) {
290 return elements.contains(ontologyElement);
291 }
292
293 /**
294 * Returns the name of the ontology.
295 *
296 * @return The name of the ontology.
297 */
298 public String getName() {
299 return name;
300 }
301
302 /**
303 * Returns the URI of the ontology (baseURI + name).
304 *
305 * @return The URI of the ontology.
306 */
307 public String getURI() {
308 return baseURI + name;
309 }
310
311 /**
312 * Returns the complete ontology as an OWL/XML formatted string. All sentences that participate in
313 * reasoning are included.
314 *
315 * @return A string that contains the complete ontology in OWL/XML format.
316 */
317 public synchronized String getOWLOntologyAsXML() {
318 StringWriter sw = new StringWriter();
319 try {
320 OWLXMLRenderer renderer = new OWLXMLRenderer(OWLManager.createOWLOntologyManager());
321 renderer.render(getOWLOntology(), sw);
322 sw.close();
323 } catch (Exception ex) {
324 ex.printStackTrace();
325 }
326 return sw.toString();
327 }
328
329 /**
330 * Returns an OWL ontology object that contains the complete ontology. More precisely, all sentences
331 * that participate in reasoning are included.
332 *
333 * @return An OWL ontology object containing the complete ontology.
334 */
335 public synchronized OWLOntology getOWLOntology() {
336 OWLOntologySetProvider setProvider = new OWLOntologySetProvider() {
337
338 public Set<OWLOntology> getOntologies() {
339 HashSet<OWLOntology> ontologies = new HashSet<OWLOntology>();
340 for (OntologyElement el : elements) {
341 for (Sentence s : el.getSentences()) {
342 if (!s.isReasonerParticipant() || !s.isIntegrated()) continue;
343
344 OWLOntology o = s.getOWLOntology();
345 if (o != null) ontologies.add(o);
346 }
347 }
348 ontologies.add(differentIndividualsAxiom);
349 return ontologies;
350 }
351
352 };
353
354 URI uri = null;
355 try {
356 uri = new URI("http://attempto.ifi.uzh.ch/default/");
357 uri = new URI(getURI());
358 } catch (URISyntaxException ex) {
359 ex.printStackTrace();
360 }
361
362 OWLOntology owlOntology = null;
363 try {
364 OWLOntologyMerger ontologyMerger = new OWLOntologyMerger(setProvider);
365 owlOntology = ontologyMerger.createMergedOntology(OWLManager.createOWLOntologyManager(), uri);
366 } catch (Exception ex) {
367 ex.printStackTrace();
368 }
369 return owlOntology;
370 }
371
372 private synchronized void refreshReasoner() {
373 log("refresh reasoner");
374
375 if (reasoner == null) {
376 // for Pellet:
377 reasoner = new Reasoner(OWLManager.createOWLOntologyManager());
378 // for HermiT: (doesn't work for some reason...)
379 //reasoner = (new ReasonerFactory()).createReasoner(OWLManager.createOWLOntologyManager());
380 } else {
381 clearOntologies();
382 }
383 updateDifferentIndividualsAxiom();
384
385 log("reasoner: loading statements");
386 HashSet<OWLOntology> ontologies = new HashSet<OWLOntology>();
387
388 for (OntologyElement oe : elements) {
389 for (Sentence s : oe.getSentences()) {
390 if (s.isReasonerParticipant() && s.isIntegrated()) {
391 OWLOntology o = s.getOWLOntology();
392 if (o != null) ontologies.add(o);
393 }
394 }
395 }
396 try {
397 reasoner.loadOntologies(ontologies);
398 } catch (OWLReasonerException ex) {
399 ex.printStackTrace();
400 }
401 log("reasoner: statements loaded");
402 }
403
404 /**
405 * Refreshes the given ontology element. All sentences that use the ontology element are
406 * updated.
407 *
408 * @param element The ontology element to be refreshed.
409 */
410 synchronized void refresh(OntologyElement element) {
411 for (Sentence s : getReferences(element)) {
412 if (s.isIntegrated()) {
413 retractSentence(s);
414 s.parse();
415 commitSentence(s);
416 } else {
417 s.parse();
418 }
419 }
420 save(element);
421 }
422
423 /**
424 * Uses the ontology manager to read an OWL ontology from a string (that contains an ontology
425 * in OWL-XML format).
426 *
427 * @param owlxml The serialized OWL-XML ontology.
428 * @return The OWL ontology object.
429 * @throws OWLOntologyCreationException If the string cannot be parsed.
430 */
431 public OWLOntology readOWLOntology(String owlxml) throws OWLOntologyCreationException {
432 return OWLManager.createOWLOntologyManager().loadOntology(new StringInputSource(owlxml));
433 }
434
435 /**
436 * Commits the sentence. This means that it is added to the reasoner. An integer value is returned
437 * that denotes the success or failure of the operation:
438 * 0 is returned if the operation succeeds.
439 * 1 is returned if it fails because the sentence introduces inconsistency into the knowledge base.
440 * 2 is returned if the reasoner runs out of memory (this can occur sometimes with large ontologies).
441 *
442 * @param sentence The sentence to be commited.
443 * @return An integer value denoting the success/failure of the operation.
444 */
445 synchronized int commitSentence(Sentence sentence) {
446 if (reasoner == null || sentence == null || sentence.isIntegrated()) return 0;
447
448 if (!sentence.isReasonerParticipant()) {
449 sentence.setIntegrated(true);
450 return 0;
451 }
452
453 log("commit sentence");
454
455 try {
456 loadOntology(sentence.getOWLOntology());
457 } catch (OutOfMemoryError err) {
458 log("error: out of memory");
459 System.gc();
460 refreshReasoner();
461 return 2;
462 }
463
464 log("check for consistency");
465 if (isConsistent()) {
466 log("consistent!");
467 sentence.setIntegrated(true);
468 stateID++;
469 return 0;
470 } else {
471 log("not consistent!");
472 unloadOntology(sentence.getOWLOntology());
473 return 1;
474 }
475 }
476
477 /**
478 * Retracts the sentence. This means that the sentence is removed from the reasoner.
479 *
480 * @param sentence The sentence to be retracted.
481 */
482 synchronized void retractSentence(Sentence sentence) {
483 if (
484 reasoner == null ||
485 sentence == null ||
486 !sentence.isIntegrated() ||
487 !sentence.isReasonerParticipant()
488 ) return;
489
490 log("retract sentence");
491 stateID++;
492 unloadOntology(sentence.getOWLOntology());
493 sentence.setIntegrated(false);
494 }
495
496 void log(String text) {
497 Logger.log(name, "onto", 0, "onto", text);
498 }
499
500 /**
501 * Updates the axiom that states that all named individuals are different. Thus, unique
502 * name assumption is applied.
503 */
504 private synchronized void updateDifferentIndividualsAxiom() {
505 if (reasoner == null) return;
506
507 if (differentIndividualsAxiom != null) {
508 unloadOntology(differentIndividualsAxiom);
509 }
510
511 String owlString =
512 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n" +
513 "<Ontology " +
514 "xml:base=\"http://www.w3.org/2006/12/owl11-xml#\" " +
515 "xmlns=\"http://www.w3.org/2006/12/owl11-xml#\" " +
516 "URI=\"" + getURI() + "/different_individuals/" + stateID + "\">\n" +
517 "\t<DifferentIndividuals>\n";
518 for (OntologyElement oe : getOntologyElements()) {
519 if (oe instanceof Individual) {
520 String word = ((Individual) oe).getWord();
521 if (word.startsWith("the ")) word = word.substring(4);
522 owlString += "\t\t<Individual URI=\"" + ((Individual) oe).getURI() + "\" />\n";
523 }
524 }
525 owlString +=
526 "\t</DifferentIndividuals>\n" +
527 "</Ontology>";
528
529 try {
530 differentIndividualsAxiom = readOWLOntology(owlString);
531 loadOntology(differentIndividualsAxiom);
532 } catch (OWLOntologyCreationException ex) {
533 log("unexpected error");
534 ex.printStackTrace();
535 }
536 }
537
538 /**
539 * Returns all concepts the given individual belongs to. The reasoner is used for this.
540 *
541 * @param ind The individual.
542 * @return A list of all concepts of the individual.
543 * @see Individual#getConcepts()
544 */
545 public synchronized List<Concept> getConcepts(Individual ind) {
546 OWLIndividual owlIndividual = (new OWLDataFactoryImpl()).getOWLIndividual(ind.getURI());
547 ArrayList<Concept> concepts = new ArrayList<Concept>();
548 try {
549 Set<Set<OWLClass>> owlClasses = reasoner.getTypes(owlIndividual, false);
550 for (Set<OWLClass> s : owlClasses) {
551 for (OWLClass oc : s) {
552 if (oc.isOWLThing() || oc.isOWLNothing()) continue;
553 String conceptURI = oc.getURI().toASCIIString();
554 String conceptName = conceptURI.substring(conceptURI.indexOf("#") + 1);
555 concepts.add((Concept) get(conceptName));
556 }
557 }
558 } catch (OWLReasonerException ex) {
559 ex.printStackTrace();
560 }
561 return concepts;
562 }
563
564 /**
565 * Returns all individuals that belong to the given concept. The reasoner is used for this.
566 *
567 * @param concept The concept.
568 * @return A list of all individuals of the concept.
569 * @see Concept#getIndividuals()
570 */
571 public synchronized List<Individual> getIndividuals(Concept concept) {
572 OWLClass owlClass = new OWLClassImpl(new OWLDataFactoryImpl(), concept.getURI());
573 ArrayList<Individual> individuals = new ArrayList<Individual>();
574 try {
575 Set<OWLIndividual> owlIndividuals = reasoner.getIndividuals(owlClass, false);
576 for (OWLIndividual oi : owlIndividuals) {
577 String indURI = oi.getURI().toASCIIString();
578 String indName = indURI.substring(indURI.indexOf("#") + 1);
579 if (!indName.matches("I[0-9]+")) {
580 individuals.add((Individual) get(indName));
581 }
582 }
583 } catch (OWLReasonerException ex) {
584 ex.printStackTrace();
585 }
586 return individuals;
587 }
588
589 /**
590 * Returns all super-concepts of the given concept. The reasoner is used for this.
591 *
592 * @param concept The concept for which all super-concepts should be returned.
593 * @return A list of all super-concepts.
594 * @see Concept#getSuperConcepts()
595 */
596 public synchronized List<Concept> getSuperConcepts(Concept concept) {
597 OWLClass owlClass = new OWLClassImpl(new OWLDataFactoryImpl(), concept.getURI());
598 ArrayList<Concept> concepts = new ArrayList<Concept>();
599 try {
600 Set<Set<OWLClass>> owlClasses = reasoner.getAncestorClasses(owlClass);
601 for (Set<OWLClass> s : owlClasses) {
602 for (OWLClass oc : s) {
603 if (oc.isOWLThing() || oc.isOWLNothing()) continue;
604 String conceptURI = oc.getURI().toASCIIString();
605 String conceptName = conceptURI.substring(conceptURI.indexOf("#") + 1);
606 concepts.add((Concept) get(conceptName));
607 }
608 }
609 } catch (OWLReasonerException ex) {
610 ex.printStackTrace();
611 }
612 return concepts;
613 }
614
615 /**
616 * Returns all the sub-concepts of the given concept. The reasoner is used for this.
617 *
618 * @param concept The concept for which all sub-concepts should be returned.
619 * @return A list of all sub-concepts.
620 * @see Concept#getSubConcepts()
621 */
622 public synchronized List<Concept> getSubConcepts(Concept concept) {
623 OWLClass owlClass = new OWLClassImpl(new OWLDataFactoryImpl(), concept.getURI());
624 ArrayList<Concept> concepts = new ArrayList<Concept>();
625 try {
626 Set<Set<OWLClass>> owlClasses = reasoner.getDescendantClasses(owlClass);
627 for (Set<OWLClass> s : owlClasses) {
628 for (OWLClass oc : s) {
629 if (oc.isOWLThing() || oc.isOWLNothing()) continue;
630 String conceptURI = oc.getURI().toASCIIString();
631 String conceptName = conceptURI.substring(conceptURI.indexOf("#") + 1);
632 concepts.add((Concept) get(conceptName));
633 }
634 }
635 } catch (OWLReasonerException ex) {
636 ex.printStackTrace();
637 }
638 return concepts;
639 }
640
641 /**
642 * Returns all individuals that answer the given question. The reasoner is used for this.
643 * Questions in AceWiki are "DL Queries". They describe a concept and the answer consists
644 * of all individuals that belong to this concept. The null value is returned if the
645 * sentence is not a question.
646 *
647 * @param questionSentence The question sentence that should be answered.
648 * @return A list of individuals that are the answer for the question.
649 * @see Sentence#getAnswer()
650 */
651 public synchronized List<Individual> getAnswer(Sentence questionSentence) {
652 if (!questionSentence.isQuestion()) return null;
653
654 ArrayList<Individual> individuals = new ArrayList<Individual>();
655 OWLOntology o = questionSentence.getOWLOntology();
656 if (o == null || o.isEmpty()) return null;
657 try {
658 OWLSubClassAxiom answerOWLAxiom = (OWLSubClassAxiom) o.getAxioms().iterator().next();
659
660 Set<OWLIndividual> owlIndividuals = reasoner.getIndividuals(answerOWLAxiom.getSubClass(), false);
661 for (OWLIndividual oi : owlIndividuals) {
662 String indURI = oi.getURI().toASCIIString();
663 String indName = indURI.substring(indURI.indexOf("#") + 1);
664 if (!indName.matches("I[0-9]+")) {
665 individuals.add((Individual) get(indName));
666 }
667 }
668 } catch (Exception ex) {
669 ex.printStackTrace();
670 }
671 return individuals;
672 }
673
674 /**
675 * Returns true if the ontology is consistent. If nothing goes wrong, this should always return true.
676 * The reasoner is used for this.
677 *
678 * @return true if the ontology is consistent.
679 */
680 public synchronized boolean isConsistent() {
681 boolean isConsistent = true;
682 try {
683 isConsistent = reasoner.isSatisfiable((new OWLDataFactoryImpl()).getOWLThing());
684 } catch (OWLReasonerException ex) {
685 ex.printStackTrace();
686 }
687 return isConsistent;
688 }
689
690 /**
691 * Checks if the given concept is satisfiable. The reasoner is used for this.
692 *
693 * @param concept The concept.
694 * @return true if the concept is satisfiable.
695 */
696 public synchronized boolean isSatisfiable(Concept concept) {
697 OWLClass owlClass = new OWLClassImpl(new OWLDataFactoryImpl(), concept.getURI());
698 boolean isSatisfiable = false;
699 try {
700 isSatisfiable = (!reasoner.isDefined(owlClass) || reasoner.isSatisfiable(owlClass));
701 } catch (OWLReasonerException ex) {
702 ex.printStackTrace();
703 }
704 return isSatisfiable;
705 }
706
707 private void loadOntology(OWLOntology ontology) {
708 if (ontology == null) return;
709
710 HashSet<OWLOntology> ontologies = new HashSet<OWLOntology>();
711 ontologies.add(ontology);
712 try {
713 reasoner.loadOntologies(ontologies);
714 } catch (OWLReasonerException ex) {
715 ex.printStackTrace();
716 }
717 }
718
719 private void unloadOntology(OWLOntology ontology) {
720 if (ontology == null) return;
721
722 HashSet<OWLOntology> ontologies = new HashSet<OWLOntology>();
723 ontologies.add(ontology);
724 try {
725 reasoner.unloadOntologies(ontologies);
726 } catch (OWLReasonerException ex) {
727 ex.printStackTrace();
728 }
729 }
730
731 private void clearOntologies() {
732 try {
733 reasoner.clearOntologies();
734 } catch (OWLReasonerException ex) {
735 ex.printStackTrace();
736 }
737 }
738
739 private long nextId() {
740 return ++idCount;
741 }
742
743 /**
744 * Returns the state id of the ontology. This id increases each time the ontology changes (more precisely:
745 * each time the part of the ontology that participates in reasoning changes). This id is used to find out
746 * whether cached information is still valid or has to be recalculated.
747 *
748 * @return The state id of the ontology.
749 */
750 long getStateID() {
751 return stateID;
752 }
753
754 }