Skip to content

Method: executeWrite(Consumer)

1: /**
2: * Copyright (C) 2016 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.ConfigParam;
17: import cz.cvut.kbss.ontodriver.config.Configuration;
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.model.parameters.OntologyCopy;
27: import org.semanticweb.owlapi.reasoner.OWLReasoner;
28: import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
29: import org.slf4j.Logger;
30: import org.slf4j.LoggerFactory;
31:
32: import java.io.FileNotFoundException;
33: import java.util.List;
34: import java.util.concurrent.locks.Lock;
35: import java.util.concurrent.locks.ReentrantReadWriteLock;
36: import java.util.function.Consumer;
37: import java.util.function.Function;
38:
39: /**
40: * Default file-based storage connector.
41: * <p>
42: * Each call to {@link #getOntologySnapshot()} returns a new snapshot of the current state of the ontology. The changes
43: * are the applied to a shared ontology, which represents the current state of the underlying storage.
44: * <p>
45: * Note: This connector currently does not handle concurrent updates.
46: */
47: public class BasicStorageConnector extends AbstractConnector {
48:
49: private static final Logger LOG = LoggerFactory.getLogger(BasicStorageConnector.class);
50:
51: private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
52: private static Lock READ = LOCK.readLock();
53: private static Lock WRITE = LOCK.writeLock();
54:
55: private OWLOntologyManager ontologyManager;
56: private OWLOntology ontology;
57: private OWLReasoner reasoner;
58: private OWLReasonerFactory reasonerFactory;
59:
60: public BasicStorageConnector(Configuration configuration) throws OwlapiDriverException {
61: super(configuration);
62: }
63:
64: @Override
65: protected void initializeConnector() throws OwlapiDriverException {
66: if (isOpen()) {
67: return;
68: }
69: final OntologyStorageProperties storageProperties = configuration.getStorageProperties();
70: LOG.debug("Loading ontology {} from {}.", storageProperties.getOntologyURI(),
71: storageProperties.getPhysicalURI());
72: this.ontologyManager = OWLManager.createOWLOntologyManager();
73: setIriMapper();
74: try {
75: this.ontology = ontologyManager.loadOntologyFromOntologyDocument(
76: IRI.create(storageProperties.getPhysicalURI()));
77: if (!ontology.getOntologyID().getOntologyIRI().isPresent() ||
78: !ontology.getOntologyID().getOntologyIRI().get().equals(
79: IRI.create(storageProperties.getOntologyURI()))) {
80: throw new InvalidOntologyIriException(
81: "Expected ontology with IRI " + storageProperties.getOntologyURI() +
82: " but the loaded ontology has IRI " + ontology.getOntologyID().getOntologyIRI());
83: }
84: } catch (OWLOntologyCreationException e) {
85: if (e.getCause() instanceof FileNotFoundException) {
86: LOG.trace("Ontology file {} does not exist.", storageProperties.getPhysicalURI());
87: } else {
88: LOG.trace("Unable to load ontology from document.", e);
89: }
90: tryCreatingOntology();
91: }
92: initializeReasonerFactory();
93: this.reasoner = getReasoner(ontology);
94: }
95:
96: private void setIriMapper() {
97: if (configuration.isSet(OwlapiConfigParam.MAPPING_FILE_LOCATION)) {
98: ontologyManager.getIRIMappers().add(new DefaultOntologyIriMapper(new MappingFileParser(configuration)));
99: }
100: }
101:
102: private void tryCreatingOntology() throws OwlapiDriverException {
103: LOG.trace("Creating new ontology in {}.", configuration.getStorageProperties().getPhysicalURI());
104: try {
105: this.ontology = ontologyManager
106: .createOntology(IRI.create(configuration.getStorageProperties().getOntologyURI()));
107: ontology.saveOntology(IRI.create(configuration.getStorageProperties().getPhysicalURI()));
108: } catch (OWLOntologyCreationException | OWLOntologyStorageException e) {
109: throw new OwlapiDriverException(
110: "Unable to create ontology in " + configuration.getStorageProperties().getPhysicalURI(), e);
111: }
112: }
113:
114: private void initializeReasonerFactory() {
115: final String reasonerFactoryClass = configuration.getProperty(ConfigParam.REASONER_FACTORY_CLASS);
116: if (reasonerFactoryClass == null) {
117: LOG.warn("Reasoner factory class not found. Reasoner won't be available.");
118: return;
119: }
120: try {
121: this.reasonerFactory = (OWLReasonerFactory) Class.forName(reasonerFactoryClass).newInstance();
122: } catch (InstantiationException | IllegalAccessException e) {
123: final String msg = "Unable to instantiate reasoner factory class " + reasonerFactoryClass;
124: LOG.error(msg);
125: throw new ReasonerNotAvailableException(msg, e);
126: } catch (ClassNotFoundException e) {
127: final String msg = "Reasoner factory class " + reasonerFactoryClass + " not found!";
128: LOG.error(msg);
129: throw new ReasonerNotAvailableException(msg, e);
130: }
131: }
132:
133: @Override
134: public OntologySnapshot getOntologySnapshot() {
135: ensureOpen();
136: READ.lock();
137: try {
138: final OWLOntologyManager m = OWLManager.createOWLOntologyManager();
139: final OWLOntology snapshot = m.copyOntology(ontology, OntologyCopy.DEEP);
140: return new OntologySnapshot(snapshot, m, m.getOWLDataFactory(), getReasoner(snapshot));
141: } catch (OWLOntologyCreationException e) {
142: throw new OntologySnapshotException("Unable to create ontology snapshot.", e);
143: } finally {
144: READ.unlock();
145: }
146: }
147:
148: private OntologySnapshot getLiveOntology() {
149: ensureOpen();
150: return new OntologySnapshot(ontology, ontologyManager, ontologyManager.getOWLDataFactory(), reasoner);
151: }
152:
153: @Override
154: public <R> R executeRead(Function<OntologySnapshot, R> function) {
155: ensureOpen();
156: READ.lock();
157: try {
158: return function.apply(getLiveOntology());
159: } finally {
160: READ.unlock();
161: }
162: }
163:
164: @Override
165: public void executeWrite(Consumer<OntologySnapshot> function) {
166: ensureOpen();
167: WRITE.lock();
168: try {
169: function.accept(getLiveOntology());
170: } finally {
171: WRITE.unlock();
172: }
173: }
174:
175: private OWLReasoner getReasoner(OWLOntology ontology) {
176: if (reasonerFactory == null) {
177: LOG.warn(
178: "Creating ontology snapshot without reasoner, because reasoner factory class was not specified.");
179: return null;
180: }
181: return reasonerFactory.createReasoner(ontology);
182: }
183:
184: @Override
185: public void applyChanges(List<OWLOntologyChange> changes) {
186: ensureOpen();
187: assert changes != null;
188: WRITE.lock();
189: try {
190: changes.stream().filter(ch -> ch instanceof MutableAxiomChange)
191: .forEach(ch -> ((MutableAxiomChange) ch).setOntology(ontology));
192: ontologyManager.applyChanges(changes);
193: try {
194: writeToFile();
195: } catch (OntologyStorageException e) {
196: LOG.error("Unable to write out ontology." + e);
197: }
198: } finally {
199: WRITE.unlock();
200: }
201: }
202:
203: @Override
204: public void close() throws OntoDriverException {
205: if (!isOpen()) {
206: return;
207: }
208: WRITE.lock();
209: try {
210: writeToFile();
211: super.close();
212: } finally {
213: WRITE.unlock();
214: }
215: }
216:
217: private void writeToFile() throws OntologyStorageException {
218: try {
219: ontologyManager.saveOntology(ontology, IRI.create(configuration.getStorageProperties().getPhysicalURI()));
220: } catch (OWLOntologyStorageException e) {
221: throw new OntologyStorageException(
222: "Error when saving ontology to " + configuration.getStorageProperties().getPhysicalURI(), e);
223: }
224: }
225: }