Skip to content

Method: lambda$applyChanges$1(OWLOntologyChange)

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