This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 63e3ae9179 GH-2487: ontapi -- add PersistentGraphRepository,
GraphMaker; changes in OntModelFactory
63e3ae9179 is described below
commit 63e3ae9179c9de9768a7e9da20e5b2f477a05c6b
Author: sszuev <[email protected]>
AuthorDate: Sun May 26 14:04:54 2024 +0300
GH-2487: ontapi -- add PersistentGraphRepository, GraphMaker; changes in
OntModelFactory
---
.../java/org/apache/jena/ontapi/GraphMaker.java | 110 ++++++++++++++++++
.../org/apache/jena/ontapi/GraphRepository.java | 18 ++-
.../org/apache/jena/ontapi/OntModelFactory.java | 71 ++++++++----
.../impl/repositories/OntUnionGraphRepository.java | 17 ++-
.../repositories/PersistentGraphRepository.java | 124 +++++++++++++++++++++
.../jena/ontapi/OntUnionGraphRepositoryTest.java | 80 ++++++++++++-
.../jena/ontapi/PersistentGraphRepositoryTest.java | 88 +++++++++++++++
.../org/apache/jena/ontapi/TestMemGraphMaker.java | 81 ++++++++++++++
8 files changed, 556 insertions(+), 33 deletions(-)
diff --git a/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphMaker.java
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphMaker.java
new file mode 100644
index 0000000000..0bfcfef9c4
--- /dev/null
+++ b/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphMaker.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.ontapi;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.shared.AlreadyExistsException;
+import org.apache.jena.shared.DoesNotExistException;
+
+import java.util.stream.Stream;
+
+/**
+ * A factory for providing instances of named graphs with appropriate storage
models.
+ * It represents a directory, or a database, or a mapping: names map to graphs
for the
+ * lifetime of the GraphMaker. Names can be "arbitrary" character sequences.
+ */
+public interface GraphMaker {
+
+ /**
+ * Create a new graph associated with the given name.
+ * If there is no such association, create one and return it.
+ * Otherwise, throw an AlreadyExistsException.
+ *
+ * @param name graph identifier, not {@code null}
+ * @return {@link Graph}, not {@code null}
+ * @throws AlreadyExistsException if graph already exists in the
underlying storage
+ */
+ Graph createGraph(String name) throws AlreadyExistsException;
+
+ /**
+ * Finds an existing graph that this factory knows about under the given
name.
+ * If such a graph exists, return it.
+ * Otherwise, throw a DoesNotExistException.
+ *
+ * @param name graph identifier, not {@code null}
+ * @return {@link Graph}, not {@code null}
+ * @throws DoesNotExistException if there is no such graph in the
underlying storage
+ */
+ Graph openGraph(String name) throws DoesNotExistException;
+
+ /**
+ * Removes the association between the name and the graph.
+ * The method {@link #createGraph(String)} will now be able to create a
graph with that name,
+ * and {@link #openGraph(String)} will no longer be able to find it.
+ * The graph itself is not touched.
+ *
+ * @param name graph identifier, not {@code null}
+ * @throws DoesNotExistException if there is no such graph in the
underlying storage
+ */
+ void removeGraph(String name) throws DoesNotExistException;
+
+ /**
+ * Returns true iff the factory has a graph with the given name
+ *
+ * @param name graph identifier, not {@code null}
+ * @return {@code boolean}
+ */
+ boolean hasGraph(String name);
+
+ /**
+ * Answers a {@code Stream} where each element is the name of a graph in
+ * the maker, and the complete sequence exhausts the set of names.
+ * No particular order is expected from the list.
+ *
+ * @return {@code Stream} of graph's identifiers
+ */
+ Stream<String> names();
+
+ /**
+ * Closes the factory - no more requests will be executed, and any cleanup
can be performed.
+ */
+ void close();
+
+ /**
+ * Returns the existing graph or null if it does not exist.
+ *
+ * @param name graph identifier, not {@code null}
+ * @return {@link Graph}, or {@code null}
+ */
+ default Graph getGraphOrNull(String name) {
+ try {
+ return openGraph(name);
+ } catch (DoesNotExistException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Lists all graphs.
+ * @return {@code Stream} of {@link Graph}s
+ */
+ default Stream<Graph> graphs() {
+ return names().map(this::openGraph);
+ }
+}
diff --git
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphRepository.java
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphRepository.java
index caf8af9f23..56085f4944 100644
--- a/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphRepository.java
+++ b/jena-ontapi/src/main/java/org/apache/jena/ontapi/GraphRepository.java
@@ -18,9 +18,10 @@
package org.apache.jena.ontapi;
-import org.apache.jena.ontapi.impl.repositories.DocumentGraphRepository;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.GraphMemFactory;
+import org.apache.jena.ontapi.impl.repositories.DocumentGraphRepository;
+import org.apache.jena.ontapi.impl.repositories.PersistentGraphRepository;
import org.apache.jena.ontapi.model.OntID;
import java.util.Objects;
@@ -40,6 +41,8 @@ public interface GraphRepository {
* A factory method to creates {@link GraphRepository} instance
* that loads graphs on demand from the location to memory.
* The location is specified by the method {@link
DocumentGraphRepository#addMapping(String, String)}.
+ * If there is no mapping specified,
+ * graph id (see {@link GraphRepository#get(String)}) will be used as a
source URL or file path.
*
* @return {@link DocumentGraphRepository}
*/
@@ -51,6 +54,8 @@ public interface GraphRepository {
* A factory method to creates {@link GraphRepository} instance
* that loads graphs on demand from the location.
* The location is specified by the method {@link
DocumentGraphRepository#addMapping(String, String)}.
+ * If there is no mapping specified,
+ * graph id (see {@link GraphRepository#get(String)}) will be used as a
source URL or file path.
*
* @param factory {@link Supplier} to produce new {@link Graph}, {@code
null} for default
* @return {@link DocumentGraphRepository}
@@ -59,10 +64,19 @@ public interface GraphRepository {
return new DocumentGraphRepository(Objects.requireNonNull(factory,
"Null graph factory"));
}
+ /**
+ * A factory method for creating persistent {@link GraphRepository};
persistence is ensured by the {@code maker}.
+ * @param maker {@link GraphMaker} a factory to create/fetch/remove {@link
Graph}s
+ * @return {@link PersistentGraphRepository}
+ */
+ static PersistentGraphRepository
createPersistentGraphRepository(GraphMaker maker) {
+ return new PersistentGraphRepository(Objects.requireNonNull(maker));
+ }
+
/**
* Gets Graph by ID.
*
- * @param id {@code String} Graph's identifier
+ * @param id {@code String} Graph's identifier, usually it is ontology ID
or source URL or file path
* @return {@link Graph}
*/
Graph get(String id);
diff --git
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/OntModelFactory.java
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/OntModelFactory.java
index 18e7081d99..7e3f0e6582 100644
--- a/jena-ontapi/src/main/java/org/apache/jena/ontapi/OntModelFactory.java
+++ b/jena-ontapi/src/main/java/org/apache/jena/ontapi/OntModelFactory.java
@@ -28,6 +28,7 @@ import org.apache.jena.ontapi.common.OntPersonality;
import org.apache.jena.ontapi.impl.OntGraphModelImpl;
import org.apache.jena.ontapi.impl.UnionGraphImpl;
import org.apache.jena.ontapi.impl.repositories.OntUnionGraphRepository;
+import org.apache.jena.ontapi.impl.repositories.PersistentGraphRepository;
import org.apache.jena.ontapi.model.OntID;
import org.apache.jena.ontapi.model.OntModel;
import org.apache.jena.ontapi.utils.Graphs;
@@ -162,17 +163,17 @@ public class OntModelFactory {
/**
* Creates an Ontology Model according to the specified specification.
*
- * @param data {@link Graph} (base graph)
- * @param spec {@link OntSpecification}
+ * @param graph {@link Graph} (base graph)
+ * @param spec {@link OntSpecification}
* @return {@link OntModel}
*/
- public static OntModel createModel(Graph data, OntSpecification spec) {
- Objects.requireNonNull(data);
+ public static OntModel createModel(Graph graph, OntSpecification spec) {
+ Objects.requireNonNull(graph);
ReasonerFactory reasonerFactory =
Objects.requireNonNull(spec).getReasonerFactory();
if (reasonerFactory == null) {
- return new OntGraphModelImpl(Graphs.makeOntUnionFrom(data,
OntModelFactory::createUnionGraph), spec.getPersonality());
+ return new OntGraphModelImpl(Graphs.makeOntUnionFrom(graph,
OntModelFactory::createUnionGraph), spec.getPersonality());
}
- return createModel(data, spec.getPersonality(),
reasonerFactory.create(null));
+ return createModel(graph, spec.getPersonality(),
reasonerFactory.create(null));
}
/**
@@ -198,34 +199,36 @@ public class OntModelFactory {
}
/**
- * Creates an Ontology Model associated with {@link
OntSpecification#OWL2_DL_MEM_BUILTIN_INF} spec.
+ * Creates Ontology Model associated with {@link
OntSpecification#OWL2_DL_MEM_BUILTIN_INF} spec.
* The {@code repository} manages all the dependencies.
* See {@link #createModel(Graph, OntSpecification, GraphRepository)}.
*
- * @param uri String, subject of {@code uri rdf:type owl:Ontology}
statement.
+ * @param uri String, subject of {@code uri rdf:type owl:Ontology}
statement,
+ * can be {@code null} for anonymous ontology
* @param repository {@link GraphRepository}
* @return {@link OntModel}
*/
public static OntModel createModel(String uri, GraphRepository repository)
{
- Objects.requireNonNull(uri);
return createModel(
- createDefaultModel().createResource(uri,
OWL2.Ontology).getModel().getGraph(),
+ createOntGraph(uri != null ? NodeFactory.createURI(uri) :
NodeFactory.createBlankNode(), repository),
OntSpecification.OWL2_DL_MEM_BUILTIN_INF,
repository
).setNsPrefixes(STANDARD);
}
/**
- * Creates an Ontology Model according to the specified specification.
+ * Creates an anonymous Ontology Model according to the specified
specification.
* The {@code repository} manages all the dependencies.
- * See {@link #createModel(Graph, OntSpecification, GraphRepository)}.
+ * Note that if {@code repository} is {@link PersistentGraphRepository},
+ * encapsulated {@link GraphMaker} will be used to create graphs.
+ * See also {@link #createModel(Graph, OntSpecification, GraphRepository)}.
*
* @param spec {@link OntSpecification}
* @param repository {@link GraphRepository}
* @return {@link OntModel}
*/
public static OntModel createModel(OntSpecification spec, GraphRepository
repository) {
- return createModel(createDefaultGraph(), spec,
repository).setNsPrefixes(STANDARD);
+ return createModel(null, spec, repository).setNsPrefixes(STANDARD);
}
/**
@@ -253,22 +256,30 @@ public class OntModelFactory {
* it returns a new instance of {@link OntModel} wrapping the existing
{@link UnionGraph}
* if it is present in the {@code repository}.
*
- * @param graph {@link Graph}
+ * @param graph {@link Graph} or {@code null} to create anonymous
Graph automatically;
+ * the instance (new or provided) will be wrapped as
+ * {@link UnionGraph} (if it is not already {@link
UnionGraph})
* @param spec {@link OntSpecification}
- * @param repository {@link GraphRepository}
+ * @param repository {@link GraphRepository}; will contain {@link
UnionGraph}s
* @return {@link OntModel}
+ * @see org.apache.jena.ontapi.impl.repositories.DocumentGraphRepository
DocumentGraphRepository
+ * @see PersistentGraphRepository
*/
- public static OntModel createModel(Graph graph, OntSpecification spec,
GraphRepository repository) {
+ public static OntModel createModel(Graph graph,
+ OntSpecification spec,
+ GraphRepository repository) {
Objects.requireNonNull(spec);
Objects.requireNonNull(repository);
- Objects.requireNonNull(graph);
if (Graphs.dataGraphs(graph).anyMatch(it -> it instanceof InfGraph)) {
throw new IllegalArgumentException("InfGraph in the hierarchy
detected");
}
+ if (graph == null) {
+ graph = createOntGraph(NodeFactory.createBlankNode(), repository);
+ }
OntUnionGraphRepository ontUnionGraphRepository = new
OntUnionGraphRepository(
repository,
OntModelFactory::createUnionGraph,
- OntModelFactory::createDefaultGraph,
+ n -> createOntGraph(n, repository),
/*ignoreUnresolvedImports*/ true);
UnionGraph union;
if (graph instanceof UnionGraph) {
@@ -301,7 +312,8 @@ public class OntModelFactory {
*
* @param uri ontology name:
* object from the statement {@code <ont> owl:versionIri
<name>} or
- * subject from the statement {@code <name> rdf:type
owl:Ontology}
+ * subject from the statement {@code <name> rdf:type
owl:Ontology};
+ * not {@code null}
* @param spec {@link OntSpecification}
* @param repository {@link GraphRepository}
* @return {@link OntModel} or {@code null} if there is no such ontology
@@ -330,7 +342,7 @@ public class OntModelFactory {
OntUnionGraphRepository ontUnionGraphRepository = new
OntUnionGraphRepository(
repository,
OntModelFactory::createUnionGraph,
- OntModelFactory::createDefaultGraph,
+ n -> createOntGraph(n, repository),
/*ignoreUnresolvedImports*/ true);
if (!ontUnionGraphRepository.contains(name)) {
return null;
@@ -342,7 +354,26 @@ public class OntModelFactory {
}
InfGraph inf = reasonerFactory.create(null).bind(union);
return new OntGraphModelImpl(inf, spec.getPersonality());
+ }
+ /**
+ * Creates ontology graph.
+ *
+ * @param name {@link Node}, not {@code null} - ontology header.
+ * @param repository {@link GraphRepository}, not {@code null}
+ * @return {@link Graph}
+ */
+ public static Graph createOntGraph(Node name, GraphRepository repository) {
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(repository);
+ Graph res;
+ if (repository instanceof PersistentGraphRepository) {
+ res = ((PersistentGraphRepository)
repository).getGraphMaker().createGraph(name.toString());
+ } else {
+ res = createDefaultGraph();
+ }
+ res.add(name, RDF.type.asNode(), OWL2.Ontology.asNode());
+ return res;
}
}
diff --git
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/OntUnionGraphRepository.java
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/OntUnionGraphRepository.java
index f9c30b9a86..ecdf126c60 100644
---
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/OntUnionGraphRepository.java
+++
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/OntUnionGraphRepository.java
@@ -37,7 +37,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
@@ -46,12 +45,12 @@ import java.util.stream.Collectors;
public class OntUnionGraphRepository {
private final GraphRepository repository;
private final Function<Graph, UnionGraph> unionGraphFactory;
- private final Supplier<Graph> baseGraphFactory;
+ private final Function<Node, Graph> baseGraphFactory;
private final boolean ignoreUnresolvedImports;
public OntUnionGraphRepository(GraphRepository repository,
Function<Graph, UnionGraph>
unionGraphFactory,
- Supplier<Graph> baseGraphFactory,
+ Function<Node, Graph> baseGraphFactory,
boolean ignoreUnresolvedImports) {
this.repository = repository;
this.unionGraphFactory = unionGraphFactory;
@@ -283,12 +282,6 @@ public class OntUnionGraphRepository {
}
}
- private Graph newGraph(Node name) {
- Graph res = baseGraphFactory.get();
- res.add(name, RDF.type.asNode(), OWL2.Ontology.asNode());
- return res;
- }
-
private Graph repositoryGerOrNull(String name) {
try {
return repository.get(name);
@@ -297,6 +290,12 @@ public class OntUnionGraphRepository {
}
}
+ private Graph newGraph(Node name) {
+ Graph res = baseGraphFactory.apply(name);
+ res.add(name, RDF.type.asNode(), OWL2.Ontology.asNode());
+ return res;
+ }
+
protected void attachListener(UnionGraph res) {
UnionGraph.EventManager manager = res.getEventManager();
if (manager.listeners(OntUnionGraphListener.class).noneMatch(it ->
isSameRepository(it.ontGraphRepository))) {
diff --git
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/PersistentGraphRepository.java
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/PersistentGraphRepository.java
new file mode 100644
index 0000000000..d6a797f8db
--- /dev/null
+++
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/repositories/PersistentGraphRepository.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.ontapi.impl.repositories;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.ontapi.GraphMaker;
+import org.apache.jena.ontapi.GraphRepository;
+import org.apache.jena.ontapi.UnionGraph;
+import org.apache.jena.ontapi.utils.Graphs;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A {@code GraphRepository} implementation that supports persistence via
{@link GraphMaker}.
+ * Note that this repository does not permit modification of underlying
storage ({@code source}).
+ * Removing graph from the {@code source} is not reflected by this repository,
+ * so it will still contain reference to the graph, even the graph is no
longer available via {@link GraphMaker}.
+ * This repository does not permit modification of underlying storage ({@code
source}).
+ */
+public class PersistentGraphRepository implements GraphRepository {
+ protected final GraphMaker source;
+ protected final Map<String, Graph> graphs;
+
+ public PersistentGraphRepository(GraphMaker source) {
+ this.source = Objects.requireNonNull(source);
+ this.graphs = loadGraphs(source);
+ }
+
+ protected static Map<String, Graph> loadGraphs(GraphMaker source) {
+ var res = new HashMap<String, Graph>();
+ source.names().forEach(id -> {
+ var g = source.openGraph(id);
+ var name =
Graphs.findOntologyNameNode(g).map(Node::toString).orElse(id);
+ res.put(name, g);
+ });
+ return res;
+ }
+
+ /**
+ * Provides access to the underlying storage.
+ * @return {@link GraphMaker}
+ */
+ public GraphMaker getGraphMaker() {
+ return source;
+ }
+
+ @Override
+ public Graph get(String id) {
+ return graphs.computeIfAbsent(id, source::openGraph);
+ }
+
+ @Override
+ public Graph put(String id, Graph graph) {
+ Set<Graph> graphs = source.graphs().collect(Collectors.toSet());
+ if (graph instanceof UnionGraph) {
+ if (Graphs.dataGraphs(graph).anyMatch(it -> !graphs.contains(it)))
{
+ throw new IllegalArgumentException(
+ "Operation 'put' is not supported for the given
UnionGraph (id = " + id + "):" +
+ "it contains subgraphs that do not managed by
the underlying storage");
+ }
+ } else if (!graphs.contains(graph)) {
+ throw new IllegalArgumentException(
+ "Operation 'put' is not supported for the given Graph (id
= " + id + "):" +
+ "it does not managed by the underlying storage");
+ }
+ var prev = this.graphs.entrySet().stream()
+ .filter(it -> graph.equals(it.getValue()))
+ .findFirst();
+ prev.map(Map.Entry::getKey).ifPresent(this.graphs::remove);
+ this.graphs.put(id, graph);
+ return prev.map(Map.Entry::getValue).orElse(null);
+ }
+
+ @Override
+ public Graph remove(String id) {
+ // do not remove from the storage,
+ // otherwise remapping will not be possible
+ return graphs.remove(id);
+ }
+
+ @Override
+ public void clear() {
+ // do not clear the storage
+ graphs.clear();
+ }
+
+ @Override
+ public Stream<String> ids() {
+ return graphs.keySet().stream();
+ }
+
+ @Override
+ public Stream<Graph> graphs() {
+ return graphs.values().stream();
+ }
+
+ @Override
+ public boolean contains(String id) {
+ return graphs.containsKey(id) || source.hasGraph(id);
+ }
+
+}
diff --git
a/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntUnionGraphRepositoryTest.java
b/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntUnionGraphRepositoryTest.java
index 24421a4c14..0b65709d05 100644
---
a/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntUnionGraphRepositoryTest.java
+++
b/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntUnionGraphRepositoryTest.java
@@ -231,7 +231,7 @@ public class OntUnionGraphRepositoryTest {
GraphRepository repository =
GraphRepository.createGraphDocumentRepositoryMem();
- OntModel inRepo = OntModelFactory.createModel(a.getGraph(),
OntSpecification.OWL2_DL_MEM_BUILTIN_INF, repository);
+ OntModelFactory.createModel(a.getGraph(),
OntSpecification.OWL2_DL_MEM_BUILTIN_INF, repository);
Assertions.assertEquals(5, repository.count());
Assertions.assertEquals(
@@ -261,7 +261,7 @@ public class OntUnionGraphRepositoryTest {
GraphRepository repository =
GraphRepository.createGraphDocumentRepositoryMem();
- OntModel inRepo = OntModelFactory.createModel(c.getGraph(),
OntSpecification.OWL2_DL_MEM_BUILTIN_INF, repository);
+ OntModelFactory.createModel(c.getGraph(),
OntSpecification.OWL2_DL_MEM_BUILTIN_INF, repository);
Assertions.assertEquals(5, repository.count());
Assertions.assertEquals(
@@ -598,4 +598,80 @@ public class OntUnionGraphRepositoryTest {
Assertions.assertNotNull(OntModelFactory.getModelOrNull(NodeFactory.createURI("B"),
OntSpecification.OWL2_DL_MEM_RDFS_INF, repository));
}
+ @Test
+ public void testCreatePersistentModel1() {
+ var maker = new TestMemGraphMaker();
+ var graph = maker.createGraph("x");
+ var repo = GraphRepository.createPersistentGraphRepository(maker);
+ var model = OntModelFactory.createModel(graph,
+ OntSpecification.OWL2_DL_MEM,
+ repo
+ );
+
+ model.getID().addImport("b");
+ model.setID("a");
+
+ Assertions.assertEquals(Set.of("a", "b"),
repo.ids().collect(Collectors.toSet()));
+ Assertions.assertEquals(
+ Stream.concat(Stream.of(model), model.imports())
+ .map(ModelGraphInterface::getGraph)
+ .collect(Collectors.toSet()),
+ repo.graphs().collect(Collectors.toSet()));
+
+ Assertions.assertEquals(
+ Stream.concat(Stream.of(model), model.imports())
+ .map(OntModel::getBaseGraph)
+ .collect(Collectors.toSet()),
+ maker.graphs().collect(Collectors.toSet()));
+
+ Assertions.assertEquals(Set.of("x", "b"),
maker.names().collect(Collectors.toSet()));
+ }
+
+ @Test
+ public void testCreatePersistentModel2() {
+ var repo = GraphRepository.createPersistentGraphRepository(new
TestMemGraphMaker());
+
+ var model1 = OntModelFactory.createModel(null,
+ OntSpecification.OWL2_DL_MEM,
+ repo
+ ).setID("a").getModel();
+
+ var model2 = OntModelFactory.createModel(null,
+ OntSpecification.OWL2_DL_MEM,
+ repo
+ ).setID("b").addImport("a").getModel();
+
+ Assertions.assertEquals(Set.of("a", "b"),
repo.ids().collect(Collectors.toSet()));
+ Assertions.assertEquals(
+ Stream.of(model1, model2)
+ .map(ModelGraphInterface::getGraph)
+ .collect(Collectors.toSet()),
+ repo.graphs().collect(Collectors.toSet()));
+ }
+
+ @Test
+ public void testCreatePersistentModel3() {
+ var maker = new TestMemGraphMaker();
+
+ var repo1 = GraphRepository.createPersistentGraphRepository(maker);
+ var model1 = OntModelFactory.createModel("a", repo1);
+
+ var repo2 = GraphRepository.createPersistentGraphRepository(maker);
+ var model2 = OntModelFactory.createModel("b",
repo2).getID().addImport("a").getModel();
+
+ Assertions.assertEquals(Set.of("a", "b"),
repo2.ids().collect(Collectors.toSet()));
+ Assertions.assertEquals(
+ Stream.of(model1, model2)
+ .map(OntModel::getBaseGraph)
+ .collect(Collectors.toSet()),
+ maker.graphs().collect(Collectors.toSet()));
+
+ var model3 = OntModelFactory.getModelOrNull("b",
OntSpecification.OWL2_DL_MEM, repo2);
+ Assertions.assertEquals(
+ Stream.concat(Stream.of(model3), model3.imports())
+ .map(ModelGraphInterface::getGraph)
+ .collect(Collectors.toSet()),
+ repo2.graphs().collect(Collectors.toSet()));
+ }
+
}
diff --git
a/jena-ontapi/src/test/java/org/apache/jena/ontapi/PersistentGraphRepositoryTest.java
b/jena-ontapi/src/test/java/org/apache/jena/ontapi/PersistentGraphRepositoryTest.java
new file mode 100644
index 0000000000..0c6df0fd24
--- /dev/null
+++
b/jena-ontapi/src/test/java/org/apache/jena/ontapi/PersistentGraphRepositoryTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.ontapi;
+
+import org.apache.jena.graph.GraphMemFactory;
+import org.apache.jena.ontapi.impl.repositories.PersistentGraphRepository;
+import org.apache.jena.ontapi.utils.Graphs;
+import org.apache.jena.shared.DoesNotExistException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class PersistentGraphRepositoryTest {
+
+ @Test
+ public void testGetIdsRemove() {
+ var maker = new TestMemGraphMaker();
+ var repo = new PersistentGraphRepository(maker);
+ Assertions.assertThrows(DoesNotExistException.class, () ->
repo.get("/graph"));
+ var graph = maker.createGraph("/graph");
+ Assertions.assertSame(graph, repo.get("/graph"));
+ Assertions.assertEquals(List.of("/graph"), repo.ids().toList());
+
+ Assertions.assertSame(graph, repo.remove("/graph"));
+ Assertions.assertEquals(List.of(), repo.ids().toList());
+
+ // restore graph
+ Assertions.assertSame(graph, repo.get("/graph"));
+ Assertions.assertEquals(List.of("/graph"), repo.ids().toList());
+
+ maker.removeGraph("/graph");
+ repo.remove("/graph");
+ Assertions.assertThrows(DoesNotExistException.class, () ->
repo.get("/graph"));
+ }
+
+ @Test
+ public void testPutIdsGet() {
+ var maker = new TestMemGraphMaker();
+ var repo = new PersistentGraphRepository(maker);
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
+ repo.put("/graph", GraphMemFactory.createDefaultGraph())
+ );
+ Assertions.assertNull(repo.put("/graph", maker.createGraph("/graph")));
+ Assertions.assertNotNull(repo.put("/graph",
maker.openGraph("/graph")));
+ Assertions.assertEquals(List.of("/graph"), repo.ids().toList());
+
+ var u =
(UnionGraph)OntModelFactory.createModel(maker.getGraphOrNull("/graph")).getGraph();
+ repo.put("/graph", u);
+ Assertions.assertSame(u, repo.get("/graph"));
+ Assertions.assertEquals(List.of("/graph"), repo.ids().toList());
+ }
+
+ @Test
+ public void testLoadAll() {
+ var maker = new TestMemGraphMaker();
+ maker.createGraph("g1");
+ maker.createGraph("g2");
+ var repo1 = new PersistentGraphRepository(maker);
+ Assertions.assertEquals(Set.of("g1", "g2"),
repo1.ids().collect(Collectors.toSet()));
+
+ var repo2 = new PersistentGraphRepository(maker);
+ Assertions.assertEquals(Set.of("g1", "g2"),
repo2.ids().collect(Collectors.toSet()));
+
+ // remap
+ Graphs.createOntologyHeaderNode(maker.openGraph("g2"), "g3");
+ var repo3 = new PersistentGraphRepository(maker);
+ Assertions.assertEquals(Set.of("g1", "g3"),
repo3.ids().collect(Collectors.toSet()));
+ }
+}
diff --git
a/jena-ontapi/src/test/java/org/apache/jena/ontapi/TestMemGraphMaker.java
b/jena-ontapi/src/test/java/org/apache/jena/ontapi/TestMemGraphMaker.java
new file mode 100644
index 0000000000..54d0e51baf
--- /dev/null
+++ b/jena-ontapi/src/test/java/org/apache/jena/ontapi/TestMemGraphMaker.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.ontapi;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphMemFactory;
+import org.apache.jena.shared.AlreadyExistsException;
+import org.apache.jena.shared.DoesNotExistException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+public class TestMemGraphMaker implements GraphMaker {
+ private boolean isOpen = true;
+ private final Map<String, Graph> storage = new HashMap<>();
+
+ @Override
+ public Graph createGraph(String name) throws AlreadyExistsException {
+ checkOpen();
+ if (storage.containsKey(name)) {
+ throw new AlreadyExistsException("Already contains graph " + name);
+ }
+ var graph = GraphMemFactory.createDefaultGraph();
+ storage.put(name, graph);
+ return graph;
+ }
+
+ @Override
+ public Graph openGraph(String name) throws DoesNotExistException {
+ var res = storage.get(name);
+ if (res == null) {
+ throw new DoesNotExistException("Can't find graph " + name);
+ }
+ return res;
+ }
+
+ @Override
+ public void removeGraph(String name) throws DoesNotExistException {
+ if (storage.remove(name) == null) {
+ throw new DoesNotExistException("Can't find graph " + name);
+ }
+ }
+
+ @Override
+ public boolean hasGraph(String name) {
+ return storage.containsKey(name);
+ }
+
+ @Override
+ public Stream<String> names() {
+ return storage.keySet().stream();
+ }
+
+ @Override
+ public void close() {
+ isOpen = false;
+ }
+
+ private void checkOpen() {
+ if (!isOpen) {
+ throw new IllegalStateException("GraphMaker is closed");
+ }
+ }
+}