Use Spring for Stardog in a Spring Boot Application

Posted on May 11, 2017 (last modified May 7, 2021)

Recently I completed a little study incorporating Spring for Stardog into a Spring Boot web app, with successful results. Here’s how.

Introduction

Stardog is a Java based RDF repository server (a.k.a. triple-store and more), which supports the RDF graph data model; SPARQL query language; property graph model and Gremlin graph traversal language; HTTP and SNARL protocols for remote access and control; OWL 2 and user-defined rules for inference and data analytics; virtual graphs; geospatial query answering; and programmatic interaction via several languages and network interfaces. At this point, I don’t have a lot of experience with Stardog, but I’ve been experimenting with it to see what I can learn. As part of my study, I recently incorporated Stardog Spring into a Spring Boot web app – taking notes along the way. Here’s my notes on how I got it setup and working successfully.

Download and install Stardog

For my local development environment on Mac OS, I installed Stardog 5 BETA (Community Edition).

You can download Stardog at www.stardog.com. Once you’ve downloaded it, unzip the archive to a destination directory. I’m put mine in /Users/cburleson/stardog

Next you need to set the STARDOG_HOME environment variable. You can do this by adding an export line to your .bash_profile.

cd ~ sudo nano .bash_profile

Add the following line to .bash_profile:

export STARDOG_HOME=/Users/cburleson/stardog

Save changes made to .bash_profile by hitting Control+o (that’s an o as in otter), ENTER, then exit out of nano by hitting Control+X.

Note that changes made .bash_profile will require the shell to be restarted or a new shell to spawn.

Copy stardog-license-key.bin into the STARDOG_HOME location. Then you can start the Stardog server to test your installation.

Start the Stardog server

/Users/cburleson/stardog/bin/stardog-admin server start

If everything is working properly, you should get the following response.

Stardog server is listening on all network interfaces. HTTP server available at http://localhost:5820. STARDOG_HOME=/Users/cburleson/stardog

the server is running and can be accessed in a web browser at http://localhost:5820/

Login with:

Usernameadmin
Passwordadmin

You can also check the server status with the following command:

/Users/cburleson/stardog/bin/stardog-admin server status

Now, that you’ve tested the installation, you can stop the server with the following command.

/Users/cburleson/stardog/bin/stardog-admin server stop

Add the Stardog Maven Repo to pom.xml

In order to get the required dependencies, you need to add the Stardog public maven repository to your repositories defined in the Maven POM (pom.xml). Here’s how that section looks in my file:

<repositories> <repository> <id>spring-releases</id> <url>https://repo.spring.io/libs-release</url> </repository> <repository> <id>stardog-public</id> <url>http://maven.stardog.com</url> </repository> </repositories>

Add Stardog dependencies to pom.xml

Now, we can add the required dependencies. Notice that even though I installed Stardog 5 BETA, I’m using a different version number for various dependencies (still, it works).

<dependency> <groupId>com.complexible.stardog</groupId> <artifactId>client-snarl</artifactId> <version>4.2.4</version> <type>pom</type> </dependency> <dependency> <groupId>com.complexible.stardog</groupId> <artifactId>client-http</artifactId> <version>4.2.4</version> <type>pom</type> </dependency> <dependency> <groupId>com.complexible.stardog</groupId> <artifactId>server</artifactId> <version>4.2.4</version> <type>pom</type> </dependency> <!-- <dependency> <groupId>com.complexible.stardog.sesame</groupId> <artifactId>stardog-sesame-core</artifactId> <version>4.2.4</version> <type>jar</type> </dependency> --> <!-- <dependency> <groupId>com.complexible.stardog.jena</groupId> <artifactId>stardog-jena</artifactId> <version>4.2.4</version> <type>jar</type> </dependency> --> <!-- <dependency> <groupId>com.complexible.stardog.gremlin</groupId> <artifactId>stardog-gremlin</artifactId> <version>4.2.4</version> <type>jar</type> </dependency> --> <dependency> <groupId>com.complexible.stardog</groupId> <artifactId>stardog-spring</artifactId> <version>2.1.3</version> <type>jar</type> </dependency> <!-- <dependency> <groupId>com.complexible.stardog</groupId> <artifactId>stardog-spring-batch</artifactId> <version>2.1.3</version> <type>jar</type> </dependency> --> <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>6.5.1</version> </dependency>

Notice that I’ve got stardog-spring-batch commented in the file, but commented out. I put it in the file incase I decide to use it in the future, but for now, I don’t need it.

Create or edit Spring application context file

I prefer using pure Java only configuration for Spring, but I had trouble with this one, so opted to use the XML configuration. I created the following file inside of src/main/resources...

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="embeddedProvider" class="com.base22.rdfx.config.EmbeddedProvider"></bean> <bean name="dataSource" class="com.complexible.stardog.ext.spring.DataSourceFactoryBean"> <property name="to" value="testdb"/> <property name="provider" ref="embeddedProvider"/> <property name="username" value="admin"/> <property name="password" value="admin"/> </bean> <bean name="template" class="com.complexible.stardog.ext.spring.SnarlTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean name="importer" class="com.complexible.stardog.ext.spring.DataImporter"> <property name="snarlTemplate" ref="template"/> <property name="format" value="N3"/> <property name="inputFiles"> <list> <value>classpath:data/sp2b_10k.n3</value> </list> </property> </bean> </beans>

Notice that the data importer bean is going to look for an RDF file in the classpath, which should exist in src/main/resources/data.

I got that file from the source project for stardog-spring, which you can find on GitHub at: https://github.com/stardog-union/stardog-spring

You could use any RDF file that you want to have auto-loaded into the Stardog repository.

Make the applicationContext.xml available to your Spring Boot app

In order for your Spring Boot app to recognize and load the applicationContext.xml, you’ll need to add an annotation to the main application class (the one with a Java main() method)…

The annotation you’ll need to add is:

@ImportResource("classpath:applicationContext.xml")

My main application class looks like this:

package com.base22.rdfx; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ImportResource; @SpringBootApplication @ImportResource("classpath:applicationContext.xml") public class Platform { public static void main(String[] args) throws Exception { SpringApplication.run(Platform.class, args); } }

Create an EmbeddedProvider Java class

The applicationContext.xml file references an EmbeddedProvider class. There is no EmbeddedProvider exposed by the stardog-spring library, but I found one in the stardog-spring source code at src/main/test/java/com/complexible/stardog/ext/spring.

You’ll need to create this class in your project and make sure that you reference the package and class properly for the embeddedProvider bean in your applicationContext.xml file.

EmbeddedProvider.java

package com.base22.rdfx.config; import com.complexible.common.protocols.server.ServerException; import com.complexible.stardog.Stardog; import com.complexible.stardog.StardogException; import com.complexible.stardog.api.admin.AdminConnection; import com.complexible.stardog.api.admin.AdminConnectionConfiguration; import com.complexible.stardog.ext.spring.Provider; import com.complexible.stardog.protocols.snarl.SNARLProtocolConstants; public class EmbeddedProvider implements Provider { @Override public void execute(String to, String url, String user, String pass) { try { Stardog.builder() .create() .newServer() .bind(SNARLProtocolConstants.EMBEDDED_ADDRESS) .start(); AdminConnection dbms = AdminConnectionConfiguration.toEmbeddedServer().credentials(user, pass).connect(); if (dbms.list().contains(to)) { dbms.drop(to); dbms.createMemory(to); } else { dbms.createMemory(to); } dbms.close(); } catch (StardogException e) { } catch (ServerException e) { } finally { } } }

Use the Spring for Stardog SnarlTemplate in a controller

For a quick acid test, I created a simple Spring Controller that gets executed when you hit the path /test in a web browser.

Here’s the simple test controller I created, which logs output from a SPARQL query to the console.

TestController.java

package com.base22.rdfx.controllers; import com.complexible.stardog.ext.spring.SnarlTemplate; import com.complexible.stardog.ext.spring.mapper.SimpleRowMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @RestController public class TestController { private static final Logger log = LoggerFactory.getLogger( TestController.class); @Autowired private SnarlTemplate template; //private static final String template = "Hello, %s!"; //private final AtomicLong counter = new AtomicLong(); @RequestMapping("/test") public void test(@RequestParam(value="name", defaultValue="World") String name) { log.trace(">> test()"); String sparql = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 5"; List<Map<String,String>> results = template.query(sparql, new SimpleRowMapper()); for ( Map<String, String> result : results ) { log.trace( "-- test() > --------------------------"); Set keys = result.keySet(); for ( Iterator i = keys.iterator(); i.hasNext(); ) { String key = (String) i.next(); String value = result.get(key); log.trace("-- test() > " + key + " | " + value); } } } }

How to use the SnarlTemplate

The Spring Programming section of the documentation on the Stardog website provides some good information. However, if you want to see some actual code examples, you might want to refer to the TestDataSourceFactory.java class on GitHub. That’s where I learned how to execute the query shown in my TestController using a SimpleRowMapper.

Test the app

Now you should be able to run your Spring Boot application and hit the TestController (/test in your browser). When you hit the URL, you should see the following output logged to the console, which shows that you’ve successfully configured and used Spring for Stardog. As you can see, five triples were returned from the given LIMIT 5 SPARQL query…

14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > -------------------------- 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > p | http://www.w3.org/2000/01/rdf-schema#subClassOf 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > s | http://localhost/vocabulary/bench/Journal 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > o | http://xmlns.com/foaf/0.1/Document 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > -------------------------- 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > p | http://www.w3.org/2000/01/rdf-schema#subClassOf 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > s | http://localhost/vocabulary/bench/Proceedings 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > o | http://xmlns.com/foaf/0.1/Document 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > -------------------------- 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > p | http://www.w3.org/2000/01/rdf-schema#subClassOf 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > s | http://localhost/vocabulary/bench/Inproceedings 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > o | http://xmlns.com/foaf/0.1/Document 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > -------------------------- 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > p | http://www.w3.org/2000/01/rdf-schema#subClassOf 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > s | http://localhost/vocabulary/bench/Article 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > o | http://xmlns.com/foaf/0.1/Document 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > -------------------------- 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > p | http://www.w3.org/2000/01/rdf-schema#subClassOf 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > s | http://localhost/vocabulary/bench/Www 14:40:36.903 [http-nio-8080-exec-1] TRACE com.base22.rdfx.controllers.TestController - -- test() > o | http://xmlns.com/foaf/0.1/Document

Conclusion

In this post, I showed how I used Spring for Stardog in a Spring Boot web app. With some minor variation, these instructions could probably be useful for any Spring app and not just a Spring Boot web app.

There is also some useful information in the QUICKSTART.txt file on GitHub that you might find useful, so be sure to check it out.