1
votes

Context

Despite the number of questions/answers on the subject, I'm stil having trouble to configure Apache Jena Fuseki...

I'm trying to configure an Apache Jena Fuseki instance with TDB and OWL reasoner activated, for testing my application. I need to create a dataset, execute my tests, and delete the dataset programatically.

Setup

I use stain/jena-fuseki docker image to run Apache Jena Fuseki.

I run Jena Fuseki in version 3.10.0.

bash-4.3# ./fuseki-server -version
Jena:       VERSION: 3.10.0
Jena:       BUILD_DATE: 2018-12-30T15:45:57+0000
TDB:        VERSION: 3.10.0
TDB:        BUILD_DATE: 2018-12-30T15:45:57+0000
Fuseki:     VERSION: 3.10.0
Fuseki:     BUILD_DATE: 2018-12-30T15:45:57+0000

Base Configuration

I use folowing shiro.ini file. I allow full access for everyone this is only a test instance.

bash-4.3# cat /fuseki/shiro.ini 

[main]
# Development
ssl.enabled = false
plainMatcher=org.apache.shiro.authc.credential.SimpleCredentialsMatcher
iniRealm.credentialsMatcher = $plainMatcher

[users]
admin=mysupersecurepassword

[roles]

[urls]
## Control functions open to anyone
/$/status = anon
/$/ping   = anon

# Everything else
/**=anon

I use the default config.ttl file:

bash-4.3# cat /fuseki/config.ttl 
# Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
## Fuseki Server configuration file.

@prefix :        <#> .
@prefix fuseki:  <http://jena.apache.org/fuseki#> .
@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ja:      <http://jena.hpl.hp.com/2005/11/Assembler#> .

[] rdf:type fuseki:Server ;
   .

What I'm tring to do ?

For testing my application I'm trying to create a dataset, execute tests, and delete the dataset programatically. For this purpose I use Fuseki HTTP Administration Protocol.

I follow these steps:

  • POST /$/datasets to create dataset.
  • POST /dataset_name/data to upload data files.
  • (Execute my application tests)
  • POST /dataset_name?update=DROP+ALL to remove data.
  • DELETE /$/datasets/dataset_name to delete dataset.

Step 1:

Using curl :

curl -F 'files[][email protected]' http://localhost:3030/$/datasets

I use following dataset.ttl file:

@prefix fuseki: <http://jena.apache.org/fuseki#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
@prefix : <#> .


# Custom code
tdb:GraphTDB rdfs:subClassOf ja:Model .

# Setup service
:service rdf:type fuseki:Service ;
    rdfs:label                          "TDB dataset_name" ;
    fuseki:name                         "dataset_name" ;
    fuseki:dataset                      :dataset ;
    fuseki:serviceQuery                 "query", "sparql" ;
    fuseki:serviceUpdate                "update" ;
    fuseki:serviceUpload                "upload" ;
    fuseki:serviceReadWriteGraphStore   "data" ;
    fuseki:serviceReadGraphStore        "get" ;
.

# Setup Assembler model with reasoner
:dataset rdf:type ja:RDFDataset;
    ja:defaultGraph :modelInf ;
.
:modelInf rdf:type ja:InfModel;
    ja:baseModel :tdbGraph ;
    ja:reasoner [ 
        ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner> 
    ] ;
.

# TDB dataset used for RDF storage
:tdbGraph rdf:type tdb:GraphTDB;
    tdb:location "/fuseki/databases/dataset_name" ;
.

Jena Fuseki logs

[2019-10-23 14:41:00] Admin      INFO  [6] POST http://localhost:3030/$/datasets
[2019-10-23 14:41:00] Admin      INFO  [6] Filename: dataset.ttl, Content-Type=application/octet-stream, Charset=null => Turtle : Count=19 Triples=19 Quads=0
[2019-10-23 14:41:00] Admin      INFO  [6] Create database : name = /dataset_name
[2019-10-23 14:41:02] Admin      INFO  [6] 200 OK (1.894 s)

Everything is OK :P


Step 2:

Using curl :

curl -F 'files[][email protected]' http://localhost:3030/dataset_name/data
{ 
  "count" : 1524 ,
  "tripleCount" : 1524 ,
  "quadCount" : 0
}

Jena Fuseki logs

[2019-10-23 14:44:52] Fuseki     INFO  [7] POST http://localhost:3030/dataset_name/data
[2019-10-23 14:44:53] Fuseki     INFO  [7] Filename: data.rdf, Content-Type=application/octet-stream, Charset=null => RDF/XML : Count=1524 Triples=1524 Quads=0
[2019-10-23 14:44:54] Fuseki     INFO  [7] 200 OK (1.858 s)

Everything is OK :P


Step 3 :

Testing my application (useless here)


Step 4:

Using curl :

curl -d "update=DROP+ALL" -X POST http://localhost:3030/dataset_name/update
...
Update succeeded
...

Jena Fuseki logs

[2019-10-23 15:04:13] Fuseki     INFO  [67] POST http://localhost:3030/dataset_name/update
[2019-10-23 15:04:14] Fuseki     INFO  [67] 200 OK (268 ms)

Everything is OK :P


Step 5:

Using curl :

curl -X DELETE http://localhost:3030/$/datasets/dataset_name

Jena Fuseki logs

[2019-10-23 15:10:17] Admin      INFO  [92] DELETE http://localhost:3030/$/datasets/dataset_name
[2019-10-23 15:10:17] Admin      INFO  [92] DELETE ds=/dataset_name
[2019-10-23 15:10:17] Server     INFO  Shutting down data service for [, data, upload, query, get, update, sparql]
[2019-10-23 15:10:17] Admin      WARN  [92] RC = 500 : Not in a transaction
org.apache.jena.tdb.transaction.TDBTransactionException: Not in a transaction
        at org.apache.jena.tdb.transaction.DatasetGraphTransaction.get(DatasetGraphTransaction.java:140)
        at org.apache.jena.tdb.transaction.DatasetGraphTransaction.getDatasetGraphToQuery(DatasetGraphTransaction.java:86)
        at org.apache.jena.tdb.store.GraphTxnTDB.getDatasetGraphTDB(GraphTxnTDB.java:51)
        at org.apache.jena.tdb.store.GraphTDB.sync(GraphTDB.java:128)
        at org.apache.jena.tdb.store.GraphTDB.close(GraphTDB.java:133)
        at org.apache.jena.reasoner.BaseInfGraph.close(BaseInfGraph.java:445)
        at org.apache.jena.reasoner.rulesys.BasicForwardRuleInfGraph.close(BasicForwardRuleInfGraph.java:360)
        at org.apache.jena.reasoner.rulesys.FBRuleInfGraph.close(FBRuleInfGraph.java:710)
        at org.apache.jena.sparql.core.DatasetGraphMapLink.close(DatasetGraphMapLink.java:199)
        at org.apache.jena.fuseki.server.DataService.expel(DataService.java:223)
        at org.apache.jena.fuseki.server.DataService.shutdown(DataService.java:199)
        at org.apache.jena.fuseki.mgt.ActionDatasets.execDeleteItem(ActionDatasets.java:360)
        at org.apache.jena.fuseki.ctl.ActionContainerItem.execDelete(ActionContainerItem.java:105)
        at org.apache.jena.fuseki.ctl.ActionContainerItem.perform(ActionContainerItem.java:64)
        at org.apache.jena.fuseki.ctl.ActionCtl.executeLifecycle(ActionCtl.java:68)
        at org.apache.jena.fuseki.ctl.ActionCtl.executeAction(ActionCtl.java:62)
        at org.apache.jena.fuseki.ctl.ActionCtl.execCommonWorker(ActionCtl.java:53)
        at org.apache.jena.fuseki.servlets.ActionBase.doCommon(ActionBase.java:74)
        at org.apache.jena.fuseki.ctl.ActionContainerItem.doDelete(ActionContainerItem.java:52)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1655)
        at org.apache.jena.fuseki.servlets.FusekiFilter.doFilter(FusekiFilter.java:101)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
        at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
        at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
        at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
        at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
        at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
        at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
        at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
        at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
        at org.apache.jena.fuseki.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:285)
        at org.apache.jena.fuseki.servlets.CrossOriginFilter.doFilter(CrossOriginFilter.java:248)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1634)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
        at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:690)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.Server.handle(Server.java:503)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
        at java.lang.Thread.run(Thread.java:745)
[2019-10-23 15:10:17] Admin      INFO  [92] 500 Not in a transaction (65 ms)

Here is the problem. Anyone can help solving this ?

Thoughts / Tries

I try same procedure with the default dataset configuration file and get no error. So I asume this come from the dataset configuration file.

Here what I called default dataset configuration file:

@prefix :      <http://base/#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix tdb2:  <http://jena.apache.org/2016/tdb#> .
@prefix ja:    <http://jena.hpl.hp.com/2005/11/Assembler#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix fuseki: <http://jena.apache.org/fuseki#> .

:service_tdb_all        a                   fuseki:Service ;
        rdfs:label                          "TDB2 dataset_name" ;
        fuseki:dataset                      :tdb_dataset_readwrite ;
        fuseki:name                         "dataset_name" ;
        fuseki:serviceQuery                 "query" , "sparql" ;
        fuseki:serviceReadGraphStore        "get" ;
        fuseki:serviceReadWriteGraphStore   "data" ;
        fuseki:serviceUpdate                "update" ;
        fuseki:serviceUpload                "upload" .

:tdb_dataset_readwrite  a                   tdb2:DatasetTDB2 ;
        tdb2:location                       "/fuseki/databases/dataset_name" .

I don't find any clear enought for me documentation on how to properly configure Jena Fuseki. Lots of exemples can be found but dated from some years, don't know if they are still uptodate. And no explanation on how they really works so it is hard to addapt to a specific case.

If any docs / tutorial to explain what are "ja:RDFDataset", "ja:InfModel" and other "ja:things" and how they works would be much appreciated.

I'm still starting with ontology/triplestores/linked data and thoses docs are not the easiest to read :


I tried different configuration examples and always get errors either on steps 1 or 5.

Example

Config:

@prefix : <#> .
@prefix fuseki: <http://jena.apache.org/fuseki#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .

[] rdf:type fuseki:Server ;
    fuseki:services (
        <#service>
    ) .

## ---------------------------------------------------------------
## Service with only SPARQL query on an inference model.
## Inference model base data in TDB.

<#service> rdf:type fuseki:Service ;
    fuseki:name "dataset_name" ;
    fuseki:serviceQuery "query" , "sparql" ;
    fuseki:serviceUpdate "update" ;
    fuseki:serviceUpload "upload" ;
    fuseki:serviceReadWriteGraphStore "data" ;
    fuseki:serviceReadGraphStore "get" ;
    fuseki:dataset <#dataset>  ;
    .

<#dataset> rdf:type ja:RDFDataset ;
    ja:defaultGraph <#model> ;
    . 

<#model> rdf:type ja:InfModel ;
    ja:baseModel <#tdbGraph> ;
    ja:reasoner [
        ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner> ;
    ] ;
    .

<#tdbGraph> rdf:type tdb:GraphTDB ;
    tdb:dataset <#tdbDataset> ;
    .

<#tdbDataset> rdf:type tdb:DatasetTDB ;
    tdb:location "/fuseki/databases/dataset_name" ;
    .

Error on step 1.

Fuseki log:

[2019-10-23 15:20:51] Admin      INFO  [93] POST http://localhost:3030/$/datasets
[2019-10-23 15:20:51] Admin      INFO  [93] Filename: dataset.ttl, Content-Type=text/turtle, Charset=null => Turtle : Count=23 Triples=23 Quads=0
[2019-10-23 15:20:51] Admin      INFO  [93] Create database : name = /dataset_name
[2019-10-23 15:20:51] Admin      WARN  [93] RC = 500 : cannot find a most specific type for :tdbGraph, which has as possibilities: ja:Model tdb:GraphTDB.
org.apache.jena.assembler.exceptions.AmbiguousSpecificTypeException: cannot find a most specific type for :tdbGraph, which has as possibilities: ja:Model tdb:GraphTDB.
1

1 Answers

1
votes

The full server provides delete for databases created through the UI or protocol using one of the templates. Arbitrary configuration files pushed the server can't be deleted this way; even if they can be unlinked from the server, there might be stuff left around (they are arbitrary assmbler files) which isn't good for testing.

For testing, there is a simpler way. Spin up a server for each test, either scripted or from Java (JUnit etc).. The "Fuseki main" version of the server starts and stops quite quickly. So start a server with the configuration required - and you can use an in-memory TDB database (location is "--mem--") for the data if the data is reasonably small.

This will complete clearup when the server exits, making the tests cleanly isolated.