Skip to content

Commit

Permalink
GH-2868: [ontapi] override register\unregister ModelChangedListener f…
Browse files Browse the repository at this point in the history
…unctionality: use only UnionGraph (not InfGraph) to hold graph-listeners
  • Loading branch information
sszuev committed Dec 12, 2024
1 parent d6e124a commit 07d3b29
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
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;
Expand Down Expand Up @@ -355,6 +356,25 @@ public Model getBaseModel() {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -223,7 +224,7 @@ public void remove(Node s, Node p, Node o) {
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));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
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;
Expand All @@ -34,6 +35,7 @@
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;
Expand All @@ -42,10 +44,9 @@
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 {
Expand All @@ -56,7 +57,7 @@ public OntSimpleClassImpl(Node n, EnhGraph eg) {

@Override
public Optional<OntStatement> findRootStatement() {
return getOptionalRootStatement(this, OWL2.Class);
return getOptionalRootStatement(this, OntPersonalities.isRDFS(getModel().getOntPersonality()) ? RDFS.Class : OWL2.Class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;
Expand Down Expand Up @@ -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);
}
102 changes: 102 additions & 0 deletions jena-ontapi/src/test/java/org/apache/jena/ontapi/OntModelMiscTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@
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;
Expand Down Expand Up @@ -154,4 +158,102 @@ public void testOntDisjointIndividuals() {

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();
}
}
}

0 comments on commit 07d3b29

Please sign in to comment.