Let's walk through a complete example from start to finish. We're still talking about bikes, but this version is a bit more complex than the minimal example in the main readme.
To get started, build the inkblot tool and the runtime jar using gradle:
./gradlew assemble
./gradlew runtimeJar
mv build/libs/inkblot-1.0-SNAPSHOT-all.jar inkblot.jar
mv build/libs/inkblot-runtime.jar .Gather all your queries in a file, one line per query. In this example we'll generate the classes Bike, Wheel and Bell from the following queries in queries.txt:
PREFIX bk: <http://rec0de.net/ns/bike#> SELECT ?bike ?mfg ?fw ?bw ?bells { ?bike a bk:bike; bk:hasFrame [bk:frontWheel ?fw; bk:backWheel ?bw] OPTIONAL { ?bike bk:mfgYear ?mfg } OPTIONAL { ?bike bk:hasFrame [bk:hasBell ?bells] } }
PREFIX bk: <http://rec0de.net/ns/bike#> SELECT ?wheel ?diameter { ?wheel a bk:wheel; bk:diameter ?diameter. }
PREFIX bk: <http://rec0de.net/ns/bike#> SELECT ?bell ?color WHERE { ?bell a bk:bell; bk:color ?color }While we can always write our configuration files by hand, it's usually faster to generate a template. Note that this assumes the first SPARQL variable in each query to be the anchor.
java -jar inkblot.jar configure example/queries.txt example/config.jsonFill in the type and cardinality details in the generated config.json file to your liking. For a completed example config, see bike-example.json. Refer to the readme for details on how to fill in the necessary details.
With the configuration completed, we can generate the actual library code. A minimal command to assemble the library in the gen folder looks like this:
java -jar inkblot.jar generate example/config.json example/genTo add wrappers for the generated classes and be more explicit about things, we can use this more verbose command:
java -jar inkblot.jar generate --wrappers --namespace "http://rec0de.net/ns/bike#" --package "gen" example/config.json example/genThe second command should produce the same files you can find in the reference folder, possibly with minor changes if you made different decisions in filling in the configuration template.
Add the previously generated inkblot-runtime.jar as a library to your target project. Also add Jena as a dependency, for example by adding this to your build.gradle.kts:
dependencies {
implementation("org.apache.jena:jena-core:4.4.0")
implementation("org.apache.jena:apache-jena-libs:4.4.0")
}Now you can add the generated sources to your project source tree and you should be able to use them just like regular objects. Have a look at the one of the wrappers for a good idea of how to interact with the generated classes.
Remember to set your SPARQL endpoint on startup and commit whenever you want to persist changes:
Inkblot.endpoint = "http://example.com/your/sparql/endpoint"
...
Inkblot.commit()You can find a full usage example in apiUsage.kt. The example retrieves all bike instances from the data store and prints some information about them. It then creates a new bike from a mix of old and new components and finally commits the changes to the data store. The relevant parts of the code are shown below:
Inkblot.endpoint = "http://localhost:3030/inkblot" // your SPARQL endpoint here
println("Loading bike inventory")
val bikes = BikeFactory.commitAndLoadAll()
bikes.forEach { bk ->
println("${bk.uri}: mfg ${bk.mfgYear}")
println("-> Number of bells: ${bk.bells.size}")
if(bk.bells.isNotEmpty())
println("-> Bell colors: ${bk.bells.joinToString(", ") { bell -> bell.color }}")
if(bk.frontWheel.diameter != bk.backWheel.diameter)
println("-> Warning: Mismatched wheel diameters (${bk.frontWheel.diameter} vs ${bk.backWheel.diameter})")
}
println("Creating a bike")
val newFrontWheel = WheelFactory.create(20.0, 2023, listOf("AluWheel"))
val newBackWheel = WheelFactory.create(22.0, 2021, emptyList())
val newBell = BellFactory.create("blood red")
BikeFactory.create(newFrontWheel, newBackWheel, listOf(newBell), 2023)
Inkblot.commit()To try this for yourself, you can create test data using inkblot by adapting the usage example. Or, for a quick start, import sampleBikes.ttl into your data store before executing the example. If you'd like to avoid creating a new project and importing the required dependencies, you can also just add your generated sources and the example script into the inkblot source tree.
On first execution, this script should produce the following output when used with the sample dataset:
Loading bike inventory
http://rec0de.net/ns/bike#bike-5v7m7ti-f27kqvqf: mfg 1989
-> Number of bells: 0
-> Warning: Mismatched wheel diameters (12.0 vs 13.0)
http://rec0de.net/ns/bike#bike-5v7m7ti-hvxtklzj: mfg 2022
-> Number of bells: 1
-> Bell colors: froggy green
http://rec0de.net/ns/bike#bike-5v7m7ti-njlxloa7: mfg 2022
-> Number of bells: 2
-> Bell colors: shiny chrome, light-leak orange
On subsequent executions, the additional, newly created bike(s) should be present in the listing as well.