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