blob: a99e120820329ecd72308037ed51980d2bbf634e [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Apache Jena - Event handling in Jena</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-icons.css" rel="stylesheet" media="screen"><link rel="stylesheet" type="text/css" href="https://jena.apache.org/sass/jena.1b17c39a117e22b46db4c66f6395dc27c134a60377d87d2d5745b8600eb69722.css" integrity="sha256-GxfDmhF&#43;IrRttMZvY5XcJ8E0pgN32H0tV0W4YA62lyI=">
<link rel="shortcut icon" href="/images/favicon.ico" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" role="navigation">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/index.html">
<img class="logo-menu" src="/images/jena-logo/jena-logo-notext-small.png" alt="jena logo">Apache Jena</a>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li id="homepage" class="nav-item"><a class="nav-link" href="/index.html"><span class="bi-house"></span> Home</a></li>
<li id="download" class="nav-item"><a class="nav-link" href="/download/index.cgi"><span class="bi-download"></span> Download</a></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal"></span> Learn <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Tutorials</li>
<li><a class="dropdown-item" href="/tutorials/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/fuseki2/index.html">Fuseki Triplestore</a></li>
<li><a class="dropdown-item" href="/documentation/notes/index.html">How-To's</a></li>
<li><a class="dropdown-item" href="/documentation/query/manipulating_sparql_using_arq.html">Manipulating SPARQL using ARQ</a></li>
<li><a class="dropdown-item" href="/tutorials/rdf_api.html">RDF core API tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/sparql.html">SPARQL tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/using_jena_with_eclipse.html">Using Jena with Eclipse</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">References</li>
<li><a class="dropdown-item" href="/documentation/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/query/index.html">ARQ (SPARQL)</a></li>
<li><a class="dropdown-item" href="/documentation/io/">RDF I/O</a></li>
<li><a class="dropdown-item" href="/documentation/assembler/index.html">Assembler</a></li>
<li><a class="dropdown-item" href="/documentation/tools/index.html">Command-line tools</a></li>
<li><a class="dropdown-item" href="/documentation/rdfs/">Data with RDFS Inferencing</a></li>
<li><a class="dropdown-item" href="/documentation/geosparql/index.html">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/inference/index.html">Inference API</a></li>
<li><a class="dropdown-item" href="/documentation/ontology/">Ontology API</a></li>
<li><a class="dropdown-item" href="/documentation/permissions/index.html">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/extras/querybuilder/index.html">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/rdf/index.html">RDF API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfconnection/">RDF Connection - SPARQL API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfstar/index.html">RDF-star</a></li>
<li><a class="dropdown-item" href="/documentation/shacl/index.html">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/shex/index.html">ShEx</a></li>
<li><a class="dropdown-item" href="/documentation/tdb/index.html">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/tdb2/index.html">TDB2</a></li>
<li><a class="dropdown-item" href="/documentation/query/text-query.html">Text Search</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal-code"></span> Javadoc <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/documentation/javadoc.html">All Javadoc</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/arq/">ARQ</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/fuseki2/">Fuseki</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/geosparql/">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/jena/">Jena Core</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/permissions/">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/extras/querybuilder/">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/shacl/">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/tdb/">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/text/">Text Search</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search" action="/search" method="GET">
<div class="input-group">
<input class="form-control border-end-0 border m-0" type="search" name="q" id="search-query" placeholder="Search...." aria-label="Search" style="width: 10rem;">
<button class="btn btn-outline-secondary border-start-0 border" type="submit">
<i class="bi-search"></i>
</button>
</div>
</form>
<ul class="navbar-nav">
<li id="ask" class="nav-item"><a class="nav-link" href="/help_and_support/index.html" title="Ask"><span class="bi-patch-question"></span><span class="text-body d-none d-xxl-inline"> Ask</span></a></li>
<li class="nav-item dropdown">
<a href="#" title="Get involved" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-megaphone"></span><span class="text-body d-none d-xxl-inline"> Get involved </span><b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/getting_involved/index.html">Contribute</a></li>
<li><a class="dropdown-item" href="/help_and_support/bugs_and_suggestions.html">Report a bug</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Project</li>
<li><a class="dropdown-item" href="/about_jena/about.html">About Jena</a></li>
<li><a class="dropdown-item" href="/about_jena/architecture.html">Architecture</a></li>
<li><a class="dropdown-item" href="/about_jena/citing.html">Citing</a></li>
<li><a class="dropdown-item" href="/about_jena/team.html">Project team</a></li>
<li><a class="dropdown-item" href="/about_jena/contributions.html">Related projects</a></li>
<li><a class="dropdown-item" href="/about_jena/roadmap.html">Roadmap</a></li>
<li><a class="dropdown-item" href="/about_jena/security-advisories.html">Security Advisories</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">ASF</li>
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Software Foundation</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/LICENSE-2.0">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
</ul>
</li>
<li class="nav-item" id="edit"><a class="nav-link" href="https://github.com/apache/jena-site/edit/main/source/documentation/notes/event-handler-howto.md" title="Edit this page on GitHub"><span class="bi-pencil-square"></span><span class="text-body d-none d-xxl-inline"> Edit this page</span></a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="breadcrumbs">
<ol class="breadcrumb mt-4 p-2 bg-body-tertiary">
<li class="breadcrumb-item"><a href='/documentation'>DOCUMENTATION</a></li>
<li class="breadcrumb-item"><a href='/documentation/notes'>NOTES</a></li>
<li class="breadcrumb-item active">EVENT HANDLER HOWTO</li>
</ol>
</div>
<h1 class="title">Event handling in Jena</h1>
<main class="d-flex flex-xl-row flex-column">
<aside class="text-muted align-self-start mb-3 p-0 d-xl-none d-block">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#modelchangedlistener">ModelChangedListener</a></li>
<li><a href="#utility-classes">Utility classes</a></li>
<li><a href="#when-listeners-are-called">When listeners are called</a></li>
<li><a href="#registering-and-unregistering">Registering and unregistering</a></li>
<li><a href="#transactions-and-databases">Transactions and databases</a></li>
</ul>
</nav>
</aside>
<article class="flex-column me-lg-4">
<h2 id="modelchangedlistener">ModelChangedListener</h2>
<p>In Jena it is possible to monitor a <code>Model</code> for changes, so that
code can be run after changes are applied without the coding for
that Model having to do anything special. We call these changes
&ldquo;events&rdquo;. This first
design and implementation is open for user comment and we may
refine or reduce the implementation as more experience is gained with
it.</p>
<p>To monitor a Model, you must <em>register</em> a <em>ModelChangedListener</em>
with that Model:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>Model m <span style="color:#666">=</span> ModelFactory<span style="color:#666">.</span><span style="color:#b44">createDefaultModel</span><span style="color:#666">();</span>
</span></span><span style="display:flex;"><span>ModelChangedListener L <span style="color:#666">=</span> <span style="color:#a2f;font-weight:bold">new</span> MyListener<span style="color:#666">();</span>
</span></span><span style="display:flex;"><span>m<span style="color:#666">.</span><span style="color:#b44">register</span><span style="color:#666">(</span> L <span style="color:#666">);</span>
</span></span></code></pre></div><p><em>MyListener</em> must be an implementation of <em>ModelChangedListener</em>,
for example:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">class</span> <span style="color:#00f">MyListener</span> <span style="color:#a2f;font-weight:bold">implements</span> ModelChangedListener
</span></span><span style="display:flex;"><span><span style="color:#666">{</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">addedStatement</span><span style="color:#666">(</span> Statement s <span style="color:#666">)</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">{</span> System<span style="color:#666">.</span><span style="color:#b44">out</span><span style="color:#666">.</span><span style="color:#b44">println</span><span style="color:#666">(</span> <span style="color:#b44">&#34;&gt;&gt; added statement &#34;</span> <span style="color:#666">+</span> s <span style="color:#666">);</span> <span style="color:#666">}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">addedStatements</span><span style="color:#666">(</span> Statement <span style="color:#666">[]</span> statements <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">addedStatements</span><span style="color:#666">(</span> List statements <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">addedStatements</span><span style="color:#666">(</span> StmtIterator statements <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">addedStatements</span><span style="color:#666">(</span> Model m <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">removedStatement</span><span style="color:#666">(</span> Statement s <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">removedStatements</span><span style="color:#666">(</span> Statement <span style="color:#666">[]</span> statements <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">removedStatements</span><span style="color:#666">(</span> List statements <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">removedStatements</span><span style="color:#666">(</span> StmtIterator statements <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">public</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">removedStatements</span><span style="color:#666">(</span> Model m <span style="color:#666">)</span> <span style="color:#666">{}</span>
</span></span><span style="display:flex;"><span><span style="color:#666">}</span>
</span></span></code></pre></div><p>This listener ignores everything except the addition of single
statements to <em>m</em>; those it prints out. The listener has a method
for each of the ways that statements can be added to a Model:</p>
<ul>
<li>as a single statement, <code>Model::add(Statement)</code></li>
<li>as an element of an array of statements,
<code>Model::add(Statement[])</code></li>
<li>as an element of a list of statements, <code>Model::add(List)</code></li>
<li>as an iterator over statements, <code>Model::add(StmtIterator)</code></li>
<li>as part of another Model, <code>Model::add(Model)</code></li>
</ul>
<p>(Similarly for <em>delete</em>.)</p>
<p>The listener method is called when the statement(s) have been added
to the Model, if no exceptions have been thrown. It does not matter
if the statement was <em>already</em> in the Model or not; it is the act
of adding it that fires the listener.</p>
<p>There is no guarantee that the statement, array, list, or model
that is added or removed is the same one that is passed to the
appropriate listener method, and the <em>StmtIterator</em> will never be
the same one. However, in the current design:</p>
<ul>
<li>a single Statement will be .equals to the original Statement</li>
<li>a List will be .equals to the original List</li>
<li>a Statement[] will be the same length and have .equal elements
in the same order</li>
<li>a StmtIterator will deliver .equal elements in the same order</li>
<li>a Model will contain the same statements</li>
</ul>
<p>We advise not relying on these ordering properties; instead assume
that for any bulk update operation on the model, the listener will
be told the method of update and the statements added or removed,
but that the order may be different and duplicate statements may
have been removed.
Note in particular that a Model with any Listeners will have to
record the complete contents of any <em>StmtIterator</em> that is added or
removed to the model, so that the Model and the Listener can both
see all the statements.</p>
<p>Finally, there is no guarantee that <em>only</em> Statements etc added
through the Model API will be presented to the listener; any
Triples added to its underlying Graph will also be presented to the
listener as statements.</p>
<h2 id="utility-classes">Utility classes</h2>
<p>The full Listener API is rather chunky and it can be inconvenient
to use, especially for the creation of inline classes. There are
four utility classes in <em>org.apache.jena.rdf.listeners:</em></p>
<ul>
<li><em>NullListener</em>. This class&rsquo;s methods do nothing. This is useful
when you want to subclass and intercept only specific ways of
updating a Model.</li>
<li><em>ChangedListener</em>. This class only records whether some change
has been made, but not what it is. The method <em>hasChanged()</em>
returns <em>true</em> if some change has been made since the last call of
<em>hasChanged()</em> [or since the listener was created].</li>
<li><em>StatementListener</em>. This class translates all bulk update
calls (ie the ones other than <em>addedStatement()</em> and
<em>removedStatement()</em>) into calls to
<em>addedStatement()/removedStatement()</em> for each Statement in the
collection. This allows statements to be tracked whether they are
added one at a time or in bulk.</li>
<li><em>ObjectListener</em>. This class translates all the listener calls
into <em>added(Object)</em> or <em>removed(Object)</em> as appropriate; it is
left to the user code to distinguish among the types of argument.</li>
</ul>
<h2 id="when-listeners-are-called">When listeners are called</h2>
<p>In the current implementation, listener methods are called
immediately the additions or removals are made, in the same thread
as the one making the update. If a model has multiple listeners
registered, the order in which they are informed about an update is
unspecified and may change from update to update. If any listener
throws an exception, that exception is thrown through the update
call, and other listeners may not be informed of the update.
Hence listener code should be brief and exception-free if at all
possible.</p>
<h2 id="registering-and-unregistering">Registering and unregistering</h2>
<p>A listener may be registered with the same model multiple times. If
so, it will be invoked as many times as it is registered for each
update event on the model.</p>
<p>A listener <em>L</em> may be <em>unregistered</em> from a Model using the method
<code>unregister(L)</code>. If <em>L</em> is not registered with the model, nothing
happens.</p>
<p>If a listener is registered multiple times with the same model,
each <code>unregister()</code> for that listener will remove just one of the
registrations.</p>
<h2 id="transactions-and-databases">Transactions and databases</h2>
<p>In the current design, listeners are not informed of transaction
boundaries, and all events are fed to listeners as soon as they
happen.</p>
</article>
<aside class="text-muted align-self-start mb-3 mb-xl-5 p-0 d-none d-xl-flex flex-column sticky-top">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#modelchangedlistener">ModelChangedListener</a></li>
<li><a href="#utility-classes">Utility classes</a></li>
<li><a href="#when-listeners-are-called">When listeners are called</a></li>
<li><a href="#registering-and-unregistering">Registering and unregistering</a></li>
<li><a href="#transactions-and-databases">Transactions and databases</a></li>
</ul>
</nav>
</aside>
</main>
</div>
</div>
</div>
<footer class="bd-footer py-4 py-md-5 mt-4 mt-lg-5 bg-body-tertiary">
<div class="container" style="font-size:80%" >
<p>
Copyright &copy; 2011&ndash;2024 The Apache Software Foundation, Licensed under the
<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</p>
<p>
Apache Jena, Jena, the Apache Jena project logo, Apache and the Apache feather logos are trademarks of
The Apache Software Foundation.
<br/>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html"
>Apache Software Foundation Privacy Policy</a>.
</p>
</div>
</footer>
<script src="/js/popper.min.js.js" type="text/javascript"></script>
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/js/improve.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
'use strict'
const links = document.querySelectorAll(`a[href="${window.location.pathname}"]`)
if (links !== undefined && links !== null) {
for (const link of links) {
link.classList.add('active')
let parentElement = link.parentElement
let count = 0
const levelsLimit = 4
while (['UL', 'LI'].includes(parentElement.tagName) && count <= levelsLimit) {
if (parentElement.tagName === 'LI') {
parentElement.querySelector('a:first-child').classList.add('active')
}
parentElement = parentElement.parentElement
count++
}
}
}
})()
</script>
</body>
</html>