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");
+        }
+    }
+}


Reply via email to