Skip to content

Method: cloneOntologyContent(OWLOntology)

1: /**
2: * Copyright (C) 2020 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
172: .applyChanges(
173: ontology.importsDeclarations().map(i -> new AddImport(target, i)).collect(
174: Collectors.toList()));
175: }
176:
177: private OntologySnapshot getLiveOntology() {
178: ensureOpen();
179: return new OntologySnapshot(ontology, ontologyManager, ontologyManager.getOWLDataFactory(), reasoner);
180: }
181:
182: @Override
183: public <R> R executeRead(Function<OntologySnapshot, R> function) {
184: ensureOpen();
185: READ.lock();
186: try {
187: return function.apply(getLiveOntology());
188: } finally {
189: READ.unlock();
190: }
191: }
192:
193: @Override
194: public void executeWrite(Consumer<OntologySnapshot> function) {
195: ensureOpen();
196: WRITE.lock();
197: try {
198: function.accept(getLiveOntology());
199: } finally {
200: WRITE.unlock();
201: }
202: }
203:
204: private OWLReasoner getReasoner(OWLOntology ontology) {
205: if (reasonerFactory == null) {
206: LOG.warn(
207: "Creating ontology snapshot without reasoner, because reasoner factory class was not specified.");
208: return null;
209: }
210: return reasonerFactory.createReasoner(ontology);
211: }
212:
213: @Override
214: public void applyChanges(List<OWLOntologyChange> changes) {
215: ensureOpen();
216: assert changes != null;
217: WRITE.lock();
218: try {
219: changes.stream().filter(ch -> ch instanceof MutableAxiomChange)
220: .forEach(ch -> ((MutableAxiomChange) ch).setOntology(ontology));
221: ontologyManager.applyChanges(changes);
222: try {
223: writeToFile();
224: } catch (OntologyStorageException e) {
225: LOG.error("Unable to write out ontology." + e);
226: }
227: } finally {
228: WRITE.unlock();
229: }
230: }
231:
232: @Override
233: public void closeSnapshot(OntologySnapshot snapshot) {
234: ensureOpen();
235: assert snapshot != null;
236: ontologyManager.removeOntology(snapshot.getOntology());
237: }
238:
239: @Override
240: void reloadData() throws OwlapiDriverException {
241: WRITE.lock();
242: try {
243: ontologyManager.clearOntologies();
244: loadOntology(configuration.getStorageProperties());
245: this.reasoner = getReasoner(ontology);
246: } finally {
247: WRITE.unlock();
248: }
249: }
250:
251: @Override
252: public void close() throws OntoDriverException {
253: if (!isOpen()) {
254: return;
255: }
256: WRITE.lock();
257: try {
258: writeToFile();
259: super.close();
260: } finally {
261: WRITE.unlock();
262: }
263: }
264:
265: private void writeToFile() throws OntologyStorageException {
266: try {
267: ontologyManager.saveOntology(ontology, IRI.create(configuration.getStorageProperties().getPhysicalURI()));
268: } catch (OWLOntologyStorageException e) {
269: throw new OntologyStorageException(
270: "Error when saving ontology to " + configuration.getStorageProperties().getPhysicalURI(), e);
271: }
272: }
273: }