Skip to content

Method: tryCreatingOntology(IRI)

1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.ontodriver.owlapi.connector;
19:
20: import cz.cvut.kbss.ontodriver.OntologyStorageProperties;
21: import cz.cvut.kbss.ontodriver.config.DriverConfigParam;
22: import cz.cvut.kbss.ontodriver.config.DriverConfiguration;
23: import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
24: import cz.cvut.kbss.ontodriver.owlapi.change.TransactionalChange;
25: import cz.cvut.kbss.ontodriver.owlapi.config.OwlapiConfigParam;
26: import cz.cvut.kbss.ontodriver.owlapi.exception.InvalidOntologyIriException;
27: import cz.cvut.kbss.ontodriver.owlapi.exception.OntologySnapshotException;
28: import cz.cvut.kbss.ontodriver.owlapi.exception.OntologyStorageException;
29: import cz.cvut.kbss.ontodriver.owlapi.exception.OwlapiDriverException;
30: import cz.cvut.kbss.ontodriver.owlapi.exception.ReasonerNotAvailableException;
31: import cz.cvut.kbss.ontodriver.owlapi.util.DefaultOntologyIriMapper;
32: import cz.cvut.kbss.ontodriver.owlapi.util.MappingFileParser;
33: import org.semanticweb.owlapi.apibinding.OWLManager;
34: import org.semanticweb.owlapi.model.AddImport;
35: import org.semanticweb.owlapi.model.IRI;
36: import org.semanticweb.owlapi.model.OWLOntology;
37: import org.semanticweb.owlapi.model.OWLOntologyChange;
38: import org.semanticweb.owlapi.model.OWLOntologyCreationException;
39: import org.semanticweb.owlapi.model.OWLOntologyIRIMapper;
40: import org.semanticweb.owlapi.model.OWLOntologyManager;
41: import org.semanticweb.owlapi.model.OWLOntologyStorageException;
42: import org.semanticweb.owlapi.reasoner.OWLReasoner;
43: import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
44: import org.slf4j.Logger;
45: import org.slf4j.LoggerFactory;
46:
47: import java.io.FileNotFoundException;
48: import java.lang.reflect.InvocationTargetException;
49: import java.net.URI;
50: import java.util.List;
51: import java.util.Optional;
52: import java.util.concurrent.locks.Lock;
53: import java.util.concurrent.locks.ReentrantReadWriteLock;
54: import java.util.function.Consumer;
55: import java.util.function.Function;
56: import java.util.stream.Collectors;
57:
58: /**
59: * Default file-based storage connector.
60: * <p>
61: * Each call to {@link #getOntologySnapshot()} returns a new snapshot of the current state of the ontology. The changes
62: * are the applied to a shared ontology, which represents the current state of the underlying storage.
63: * <p>
64: * Note: This connector currently does not handle concurrent updates.
65: */
66: public class BasicStorageConnector extends AbstractConnector {
67:
68: private static final Logger LOG = LoggerFactory.getLogger(BasicStorageConnector.class);
69:
70: private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
71: private static final Lock READ = LOCK.readLock();
72: private static final Lock WRITE = LOCK.writeLock();
73:
74: private OWLOntologyManager ontologyManager;
75: private OWLOntology ontology;
76: private OWLReasoner reasoner;
77: private OWLReasonerFactory reasonerFactory;
78:
79: private OWLOntologyIRIMapper iriMapper;
80:
81: BasicStorageConnector(DriverConfiguration configuration) throws OwlapiDriverException {
82: super(configuration);
83: }
84:
85: @Override
86: protected void initializeConnector() throws OwlapiDriverException {
87: if (isOpen()) {
88: return;
89: }
90: final OntologyStorageProperties storageProperties = configuration.getStorageProperties();
91: LOG.debug("Loading ontology {} from {}.", storageProperties.getOntologyURI(),
92: storageProperties.getPhysicalURI());
93: resolveIriMapper();
94: this.ontologyManager = OWLManager.createOWLOntologyManager();
95: setIriMapper(ontologyManager);
96: loadOntology(storageProperties);
97: initializeReasonerFactory();
98: this.reasoner = getReasoner(ontology);
99: }
100:
101: private void resolveIriMapper() {
102: if (configuration.isSet(OwlapiConfigParam.MAPPING_FILE_LOCATION)) {
103: this.iriMapper = new DefaultOntologyIriMapper(new MappingFileParser(configuration));
104: }
105: }
106:
107: private void setIriMapper(OWLOntologyManager manager) {
108: if (iriMapper != null) {
109: manager.getIRIMappers().add(new DefaultOntologyIriMapper(new MappingFileParser(configuration)));
110: }
111: }
112:
113: private void loadOntology(OntologyStorageProperties storageProperties) throws OwlapiDriverException {
114: final Optional<IRI> ontologyIri = storageProperties.getOntologyURI().map(IRI::create);
115: try {
116: this.ontology =
117: ontologyManager.loadOntologyFromOntologyDocument(IRI.create(storageProperties.getPhysicalURI()));
118: if (!ontology.getOntologyID().getOntologyIRI().equals(ontologyIri)) {
119: throw new InvalidOntologyIriException(
120: "Expected ontology with IRI " + storageProperties.getOntologyURI() +
121: " but the loaded ontology has IRI " + ontology.getOntologyID().getOntologyIRI());
122: }
123: } catch (OWLOntologyCreationException e) {
124: if (e.getCause() instanceof FileNotFoundException) {
125: LOG.trace("Ontology file {} does not exist.", storageProperties.getPhysicalURI());
126: } else {
127: LOG.trace("Unable to load ontology from document.", e);
128: }
129: tryCreatingOntology(ontologyIri.orElse(null));
130: }
131: }
132:
133: private void tryCreatingOntology(IRI ontologyIri) throws OwlapiDriverException {
134: LOG.trace("Creating new ontology in {}.", configuration.getStorageProperties().getPhysicalURI());
135: try {
136: this.ontology = ontologyManager.createOntology(ontologyIri);
137: ontology.saveOntology(IRI.create(configuration.getStorageProperties().getPhysicalURI()));
138: } catch (OWLOntologyCreationException | OWLOntologyStorageException e) {
139: throw new OwlapiDriverException(
140: "Unable to create ontology in " + configuration.getStorageProperties().getPhysicalURI(), e);
141: }
142: }
143:
144: private void initializeReasonerFactory() {
145: final String reasonerFactoryClass = configuration.getProperty(DriverConfigParam.REASONER_FACTORY_CLASS);
146: if (reasonerFactoryClass == null) {
147: LOG.warn("Reasoner factory class not found. Reasoner won't be available.");
148: return;
149: }
150: try {
151: this.reasonerFactory = (OWLReasonerFactory) Class.forName(reasonerFactoryClass).getDeclaredConstructor()
152: .newInstance();
153: } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
154: final String msg = "Unable to instantiate reasoner factory class " + reasonerFactoryClass;
155: LOG.error(msg);
156: throw new ReasonerNotAvailableException(msg, e);
157: } catch (NoSuchMethodException e) {
158: final String msg = "Reasoner factory class " + reasonerFactoryClass + " does not have a public no-arg constructor.";
159: LOG.error(msg);
160: throw new ReasonerNotAvailableException(msg, e);
161: } catch (ClassNotFoundException e) {
162: final String msg = "Reasoner factory class " + reasonerFactoryClass + " not found!";
163: LOG.error(msg);
164: throw new ReasonerNotAvailableException(msg, e);
165: }
166: }
167:
168: @Override
169: public URI getOntologyUri() {
170: assert ontology.getOntologyID().getOntologyIRI().isPresent();
171:
172: return ontology.getOntologyID().getOntologyIRI().get().toURI();
173: }
174:
175: @Override
176: public OntologySnapshot getOntologySnapshot() {
177: ensureOpen();
178: READ.lock();
179: try {
180: final OWLOntology snapshot = ontologyManager.createOntology();
181: cloneOntologyContent(snapshot);
182: return new OntologySnapshot(snapshot, ontologyManager, ontologyManager.getOWLDataFactory(),
183: getReasoner(snapshot));
184: } catch (OWLOntologyCreationException e) {
185: throw new OntologySnapshotException("Unable to create ontology snapshot.", e);
186: } finally {
187: READ.unlock();
188: }
189: }
190:
191: private void cloneOntologyContent(OWLOntology target) {
192: ontologyManager.addAxioms(target, ontology.axioms());
193: ontologyManager.applyChanges(
194: ontology.importsDeclarations().map(i -> new AddImport(target, i)).collect(Collectors.toList()));
195: }
196:
197: private OntologySnapshot getLiveOntology() {
198: ensureOpen();
199: return new OntologySnapshot(ontology, ontologyManager, ontologyManager.getOWLDataFactory(), reasoner);
200: }
201:
202: @Override
203: public <R> R executeRead(Function<OntologySnapshot, R> function) {
204: ensureOpen();
205: READ.lock();
206: try {
207: return function.apply(getLiveOntology());
208: } finally {
209: READ.unlock();
210: }
211: }
212:
213: @Override
214: public void executeWrite(Consumer<OntologySnapshot> function) {
215: ensureOpen();
216: WRITE.lock();
217: try {
218: function.accept(getLiveOntology());
219: } finally {
220: WRITE.unlock();
221: }
222: }
223:
224: private OWLReasoner getReasoner(OWLOntology ontology) {
225: if (reasonerFactory == null) {
226: LOG.warn("Creating ontology snapshot without reasoner, because reasoner factory class was not specified.");
227: return null;
228: }
229: return reasonerFactory.createReasoner(ontology);
230: }
231:
232: @Override
233: public void applyChanges(List<TransactionalChange> changes) {
234: ensureOpen();
235: assert changes != null;
236: WRITE.lock();
237: try {
238: final List<OWLOntologyChange> toApply = changes.stream()
239: .flatMap(o -> o.toOwlChanges(ontology).stream())
240: .collect(Collectors.toList());
241: ontologyManager.applyChanges(toApply);
242: try {
243: writeToFile();
244: } catch (OntologyStorageException e) {
245: LOG.error("Unable to write out ontology." + e);
246: }
247: } finally {
248: WRITE.unlock();
249: }
250: }
251:
252: @Override
253: public void closeSnapshot(OntologySnapshot snapshot) {
254: ensureOpen();
255: assert snapshot != null;
256: ontologyManager.removeOntology(snapshot.getOntology());
257: }
258:
259: @Override
260: void reloadData() throws OwlapiDriverException {
261: WRITE.lock();
262: try {
263: ontologyManager.clearOntologies();
264: loadOntology(configuration.getStorageProperties());
265: this.reasoner = getReasoner(ontology);
266: } finally {
267: WRITE.unlock();
268: }
269: }
270:
271: @Override
272: public void close() throws OntoDriverException {
273: if (!isOpen()) {
274: return;
275: }
276: WRITE.lock();
277: try {
278: writeToFile();
279: super.close();
280: } finally {
281: WRITE.unlock();
282: }
283: }
284:
285: private void writeToFile() throws OntologyStorageException {
286: try {
287: ontologyManager.saveOntology(ontology, IRI.create(configuration.getStorageProperties().getPhysicalURI()));
288: } catch (OWLOntologyStorageException e) {
289: throw new OntologyStorageException(
290: "Error when saving ontology to " + configuration.getStorageProperties().getPhysicalURI(), e);
291: }
292: }
293: }