Fuseki : Embedded Server

Fuseki can be run within a larger JVM application as an embedded triplestore.

The application can safely access and modify the data published by the server if it does so inside a transaction using an appropriate storage choice. DatasetFactory.createTxnMem() is a good choice for in-memory use; TDB is a good choice for a persistent database.

To build and start the server:

Dataset ds = ...
FusekiServer server = FusekiServer.create()
  .add("/rdf", ds)
  .build() ;
server.start() ;

then the application can modify the dataset:

// Add some data while live.
// Write transaction.
Txn.execWrite(dsg, ()->RDFDataMgr.read(dsg, "D.trig")) ;

or read the dataset and see any updates made by remote systems:

// Query data while live
// Read transaction.
Txn.execRead(dsg, ()->{
Dataset ds = DatasetFactory.wrap(dsg) ;
try (QueryExecution qExec = QueryExecution.create("SELECT * { ?s  ?o}", ds) ) {
    ResultSet rs = qExec.execSelect() ;
    ResultSetFormatter.out(rs) ;
  }
}) ;

The full Jena API can be used provided operations (read and write) are inside a transaction.

Dependencies and Setup

To include an embedded Fuseki server in the application:

<dependency>
  <groupId>org.apache.jena</groupId>
  <artifactId>jena-fuseki-main</artifactId>
  <version>3.x.y</version> <!-- Set the version -->
</dependency>

This brings in enough dependencies to run Fuseki. Application writers are strongly encouraged to use a dependency manager because the number of Jetty and other dependencies is quite large and difficult to set manually.

This dependency does not include a logging setting. Fuseki uses slf4j.

If the application wishes to use a dataset with a text-index then the application will also need to include jena-text in its dependencies.

Logging

The application must set the logging provided for slf4j. Apache Jena provides helpers Apache Log4j v2.

For Apache Log4j2, call:

FusekiLogging.setLogging();

and dependency:

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-slf4j-impl</artifactId>
  <version>2.13.1</version> <!-- Many versions work -->  
</dependency>

See Fuseki Logging.

To silence logging from Java, try:

LogCtl.setLevel(Fuseki.serverLogName,  "WARN");
LogCtl.setLevel(Fuseki.actionLogName,  "WARN");
LogCtl.setLevel(Fuseki.requestLogName, "WARN");
LogCtl.setLevel(Fuseki.adminLogName,   "WARN");
LogCtl.setLevel("org.eclipse.jetty",   "WARN");

Building a server

A FusekiServer is built by creating a configuration, building the server, then running it. The application needs to start the server.

The default port for a Fuseki embedded server is 3330. This is different for the default port for Fuseki running as a standalone server or as a webapp application.

Examples of embedded use

Example 1

Create a server on port 3330, that provides the default set of endpoints for an RDF dataset that can be updated via HTTP.

Dataset ds = DatasetFactory.createTxnMem() ;
FusekiServer server = FusekiServer.create()
    .add("/ds", ds)
    .build() ;
server.start() ;
...
server.stop() ;

The services are avilable on a named endpoint and also on the dataset URL itself.

URLs:

Service Endpoint1 Endpoint2
SPARQL Query http://host:3330/ds/query http://host:3330/ds
SPARQL Query http://host:3330/ds/sparql http://host:3330/ds
SPARQL Update http://host:3330/ds/update http://host:3330/ds
GSP read-write http://host:3330/ds/data http://host:3330/ds

“GSP” = SPARQL Graph Store Protocol

Example 2

Create a server on port 3332, that provides the default set of endpoints for a data set that is read-only over HTTP. The application can still update the dataset.

Dataset ds = ... ;
FusekiServer server = FusekiServer.create()
    .port(3332)
    .add("/ds", ds, false)
    .build() ;
server.start() ;
Service Endpoint Endpoint2
SPARQL Query http://host:3332/ds/query http://host:3332/ds
SPARQL Query http://host:3332/ds/sparql http://host:3332/ds
GSP read-only http://host:3332/ds/data http://host:3332/ds

Example 3

Different combinations of services and endpoint names can be given using a DataService.

DatasetGraph dsg = ... ;
DataService dataService = new DataService(dsg) ;
dataService.addEndpoint(OperationName.GSP_RW, "");
dataService.addEndpoint(OperationName.Query, "");
dataService.addEndpoint(OperationName.Update, "");

FusekiServer server = FusekiServer.create()
   .port(3332)
   .add("/data", dataService)
   .build() ;
server.start() ;

This setup puts all the operation on the dataset URL. The Content-type and any query string is used to determine the operation.

Service Endpoint
SPARQL Query http://host:3332/ds
SPARQL Update http://host:3332/ds
GSP read-write http://host:3332/ds

Example 4

Multiple datasets can be served by one server.

Dataset ds1 = ...
Dataset ds2 = ...
FusekiServer server = FusekiServer.create()
    .add("/data1", ds1)
    .add("/data1-readonly", ds1, true)
    .add("/data2", ds2)
    .build() ;
server.start() ;