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 d165bc5284 GH-2868: [ontapi] override register\unregister 
ModelChangedListener functionality: use only UnionGraph (not InfGraph) to hold 
graph-listeners
d165bc5284 is described below

commit d165bc5284d5a1b95476dbe1b8cd05841b7c9caa
Author: sszuev <[email protected]>
AuthorDate: Thu Dec 12 23:24:51 2024 +0300

    GH-2868: [ontapi] override register\unregister ModelChangedListener 
functionality: use only UnionGraph (not InfGraph) to hold graph-listeners
---
 .../apache/jena/ontapi/impl/OntGraphModelImpl.java |  20 ++++
 .../apache/jena/ontapi/impl/UnionGraphImpl.java    |   9 +-
 .../ontapi/impl/objects/OntSimpleClassImpl.java    |  11 ++-
 .../org/apache/jena/ontapi/model/MutableModel.java |  33 +++++++
 .../org/apache/jena/ontapi/OntModelMiscTest.java   | 102 +++++++++++++++++++++
 5 files changed, 166 insertions(+), 9 deletions(-)

diff --git 
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/OntGraphModelImpl.java 
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/OntGraphModelImpl.java
index ad7bae3c94..c6747bfe92 100644
--- 
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/OntGraphModelImpl.java
+++ 
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/OntGraphModelImpl.java
@@ -68,6 +68,7 @@ import org.apache.jena.ontapi.utils.StdModels;
 import org.apache.jena.rdf.model.InfModel;
 import org.apache.jena.rdf.model.Literal;
 import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelChangedListener;
 import org.apache.jena.rdf.model.Property;
 import org.apache.jena.rdf.model.RDFList;
 import org.apache.jena.rdf.model.RDFNode;
@@ -355,6 +356,25 @@ public class OntGraphModelImpl extends ModelCom implements 
OntModel, OntEnhGraph
         return new ModelCom(getBaseGraph());
     }
 
+    @Override
+    public OntGraphModelImpl register(ModelChangedListener listener) {
+        getUnionGraph().getEventManager().register(adapt(listener));
+        return this;
+    }
+
+    @Override
+    public OntGraphModelImpl unregister(ModelChangedListener listener) {
+        getUnionGraph().getEventManager().unregister(adapt(listener));
+        return this;
+    }
+
+    @Override
+    public OntGraphModelImpl notifyEvent(Object event) {
+        var ug = getUnionGraph();
+        ug.getEventManager().notifyEvent(ug, event);
+        return this;
+    }
+
     @Override
     public OntID getID() {
         checkType(OntID.class);
diff --git 
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/UnionGraphImpl.java 
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/UnionGraphImpl.java
index 6565221138..f73d964347 100644
--- a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/UnionGraphImpl.java
+++ b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/UnionGraphImpl.java
@@ -18,17 +18,18 @@
 
 package org.apache.jena.ontapi.impl;
 
-import org.apache.jena.ontapi.UnionGraph;
-import org.apache.jena.ontapi.utils.Graphs;
-import org.apache.jena.ontapi.utils.Iterators;
 import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.GraphEventManager;
 import org.apache.jena.graph.GraphEvents;
 import org.apache.jena.graph.GraphListener;
+import org.apache.jena.graph.GraphUtil;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.Triple;
 import org.apache.jena.graph.compose.CompositionBase;
 import org.apache.jena.graph.impl.SimpleEventManager;
+import org.apache.jena.ontapi.UnionGraph;
+import org.apache.jena.ontapi.utils.Graphs;
+import org.apache.jena.ontapi.utils.Iterators;
 import org.apache.jena.shared.PrefixMapping;
 import org.apache.jena.util.iterator.ExtendedIterator;
 
@@ -223,7 +224,7 @@ public class UnionGraphImpl extends CompositionBase 
implements UnionGraph {
         Triple t = Triple.createMatch(s, p, o);
         UnionGraph.EventManager em = getEventManager();
         em.onDeleteTriple(this, t);
-        super.remove(s, p, o);
+        GraphUtil.remove(this, s, p, o);
         em.notifyEvent(this, GraphEvents.remove(s, p, o));
     }
 
diff --git 
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/objects/OntSimpleClassImpl.java
 
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/objects/OntSimpleClassImpl.java
index cef800397b..e39cc0869d 100644
--- 
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/objects/OntSimpleClassImpl.java
+++ 
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/impl/objects/OntSimpleClassImpl.java
@@ -22,6 +22,7 @@ import org.apache.jena.enhanced.EnhGraph;
 import org.apache.jena.graph.Node;
 import org.apache.jena.ontapi.OntJenaException;
 import org.apache.jena.ontapi.OntModelControls;
+import org.apache.jena.ontapi.common.OntPersonalities;
 import org.apache.jena.ontapi.impl.OntGraphModelImpl;
 import org.apache.jena.ontapi.model.OntClass;
 import org.apache.jena.ontapi.model.OntDataProperty;
@@ -34,6 +35,7 @@ import org.apache.jena.ontapi.model.OntRelationalProperty;
 import org.apache.jena.ontapi.model.OntStatement;
 import org.apache.jena.rdf.model.Resource;
 import org.apache.jena.vocabulary.OWL2;
+import org.apache.jena.vocabulary.RDFS;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -42,10 +44,9 @@ import java.util.Optional;
 import java.util.stream.Stream;
 
 /**
- * {@code owl:Class} Implementation.
- * Instance of this class as a class with unknown nature is only available in 
a spec with corresponding permissions
- * ({@link OntModelControls}).
- * Specialized classes have their own implementations ({@link NamedImpl} or 
{@link OntClassImpl}).
+ * Simple Ontology Class implementation.
+ * Represents RDFS OntClass or OWL OntClass with unknown nature.
+ * Specialized OWL classes have their own implementations ({@link NamedImpl} 
or {@link OntClassImpl}).
  */
 @SuppressWarnings("WeakerAccess")
 public class OntSimpleClassImpl extends OntObjectImpl implements OntClass {
@@ -56,7 +57,7 @@ public class OntSimpleClassImpl extends OntObjectImpl 
implements OntClass {
 
     @Override
     public Optional<OntStatement> findRootStatement() {
-        return getOptionalRootStatement(this, OWL2.Class);
+        return getOptionalRootStatement(this, 
OntPersonalities.isRDFS(getModel().getOntPersonality()) ? RDFS.Class : 
OWL2.Class);
     }
 
     @Override
diff --git 
a/jena-ontapi/src/main/java/org/apache/jena/ontapi/model/MutableModel.java 
b/jena-ontapi/src/main/java/org/apache/jena/ontapi/model/MutableModel.java
index 996d9fb8f2..92d04d229f 100644
--- a/jena-ontapi/src/main/java/org/apache/jena/ontapi/model/MutableModel.java
+++ b/jena-ontapi/src/main/java/org/apache/jena/ontapi/model/MutableModel.java
@@ -21,6 +21,7 @@ package org.apache.jena.ontapi.model;
 import org.apache.jena.datatypes.RDFDatatype;
 import org.apache.jena.rdf.model.Literal;
 import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelChangedListener;
 import org.apache.jena.rdf.model.ModelCon;
 import org.apache.jena.rdf.model.Property;
 import org.apache.jena.rdf.model.RDFNode;
@@ -109,4 +110,36 @@ interface MutableModel<R extends Model> extends Model {
 
     @Override
     R add(Resource s, Property p, String lex, String lang);
+
+    /**
+     * Registers a listener for model-changed events on this model.
+     * The methods on the listener will be called when API add/remove calls on 
the model succeed
+     * [in whole or in part].
+     * The same listener may be registered many times;
+     * if so, its methods will be called as many times as it's registered for 
each event.
+     *
+     * @param listener {@link ModelChangedListener}, not null
+     * @return this model, for cascading
+     */
+    R register(ModelChangedListener listener);
+
+    /**
+     * Unregisters a listener from model-changed events on this model.
+     * The listener is detached from the model.
+     * The model is returned to permit cascading.
+     * If the listener is not attached to the model, then nothing happens.
+     *
+     * @param listener {@link ModelChangedListener}, not null
+     */
+    R unregister(ModelChangedListener listener);
+
+    /**
+     * Notifies any listeners that the {@code event} has occurred.
+     *
+     * @param event the event, which has occurred, e.g. {@code 
GraphEvents#startRead}
+     * @return this model, for cascading
+     * @see ModelChangedListener
+     * @see org.apache.jena.graph.GraphEvents
+     */
+    R notifyEvent(Object event);
 }
diff --git 
a/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntModelMiscTest.java 
b/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntModelMiscTest.java
index 72cb0acf88..263a537acc 100644
--- a/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntModelMiscTest.java
+++ b/jena-ontapi/src/test/java/org/apache/jena/ontapi/OntModelMiscTest.java
@@ -25,15 +25,19 @@ import org.apache.jena.ontapi.model.OntClass;
 import org.apache.jena.ontapi.model.OntDisjoint;
 import org.apache.jena.ontapi.model.OntModel;
 import org.apache.jena.ontapi.utils.OntModels;
+import org.apache.jena.rdf.listeners.StatementListener;
 import org.apache.jena.rdf.model.Model;
 import org.apache.jena.rdf.model.ModelFactory;
 import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.rdf.model.Statement;
 import org.apache.jena.shared.PrefixMapping;
 import org.apache.jena.vocabulary.OWL;
 import org.apache.jena.vocabulary.OWL2;
 import org.apache.jena.vocabulary.RDF;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -154,4 +158,102 @@ public class OntModelMiscTest {
 
         Assertions.assertThrows(IllegalArgumentException.class, 
ont::createDifferentIndividuals);
     }
+
+    @ParameterizedTest
+    @EnumSource(names = {
+            "OWL2_DL_MEM_RDFS_BUILTIN_INF",
+            "OWL2_DL_MEM",
+            "OWL2_DL_MEM_RDFS_INF",
+            "OWL2_DL_MEM_TRANS_INF",
+            "OWL2_DL_MEM_RULES_INF",
+            "OWL2_MEM",
+            "OWL2_MEM_RDFS_INF",
+            "OWL2_MEM_TRANS_INF",
+            "OWL2_MEM_RULES_INF",
+            "OWL2_MEM_MINI_RULES_INF",
+            "OWL2_MEM_MICRO_RULES_INF",
+            "OWL2_EL_MEM",
+            "OWL2_EL_MEM_RDFS_INF",
+            "OWL2_EL_MEM_TRANS_INF",
+            "OWL2_EL_MEM_RULES_INF",
+            "OWL2_QL_MEM",
+            "OWL2_QL_MEM_RDFS_INF",
+            "OWL2_QL_MEM_TRANS_INF",
+            "OWL2_QL_MEM_RULES_INF",
+            "OWL2_RL_MEM",
+            "OWL2_RL_MEM_RDFS_INF",
+            "OWL2_RL_MEM_TRANS_INF",
+            "OWL2_RL_MEM_RULES_INF",
+            "OWL1_DL_MEM",
+            "OWL1_DL_MEM_RDFS_INF",
+            "OWL1_DL_MEM_TRANS_INF",
+            "OWL1_DL_MEM_RULES_INF",
+            "OWL1_MEM",
+            "OWL1_MEM_RDFS_INF",
+            "OWL1_MEM_TRANS_INF",
+            "OWL1_MEM_RULES_INF",
+            "OWL1_MEM_MINI_RULES_INF",
+            "OWL1_MEM_MICRO_RULES_INF",
+            "OWL1_LITE_MEM",
+            "OWL1_LITE_MEM_RDFS_INF",
+            "OWL1_LITE_MEM_TRANS_INF",
+            "OWL1_LITE_MEM_RULES_INF",
+            "RDFS_MEM",
+            "RDFS_MEM_RDFS_INF",
+            "RDFS_MEM_TRANS_INF",
+    })
+    public void testModelChangeListenerGH2868(TestSpec spec) {
+        var listener = new TestModelChangedListener();
+        var m = OntModelFactory.createModel(spec.inst).register(listener);
+
+        var type1 = m.createOntClass("http://x1";);
+        type1.removeProperties();
+        Assertions.assertEquals(1, listener.addedStatements.size());
+        Assertions.assertEquals(1, listener.removedStatements.size());
+        Assertions.assertEquals(1, listener.events.size());
+
+        listener.clear();
+
+        var type2 = m.createOntClass("http://x2";);
+        m.remove(type2.getMainStatement());
+        Assertions.assertEquals(1, listener.addedStatements.size());
+        Assertions.assertEquals(1, listener.removedStatements.size());
+        Assertions.assertEquals(0, listener.events.size());
+
+        listener.clear();
+
+        m.createOntClass("http://x3";);
+        m.createOntClass("http://x4";);
+        m.removeAll(null, RDF.type, null);
+        Assertions.assertEquals(2, listener.addedStatements.size());
+        Assertions.assertEquals(2, listener.removedStatements.size());
+        Assertions.assertEquals(1, listener.events.size());
+    }
+
+    private static class TestModelChangedListener extends StatementListener {
+        private final List<Statement> addedStatements = new ArrayList<>();
+        private final List<Statement> removedStatements = new ArrayList<>();
+        private final List<Object> events = new ArrayList<>();
+
+        @Override
+        public void addedStatement(Statement x) {
+            addedStatements.add(x);
+        }
+
+        @Override
+        public void removedStatement(Statement x) {
+            removedStatements.add(x);
+        }
+
+        @Override
+        public void notifyEvent(Model m, Object event) {
+            events.add(event);
+        }
+
+        private void clear() {
+            addedStatements.clear();
+            removedStatements.clear();
+            events.clear();
+        }
+    }
 }

Reply via email to