Useful utilities
This guide presents some useful utilities in the jelly-core
and jelly-stream
modules.
Jelly options presets
Every Jelly stream begins with a header that specifies the serialization options used to encode the stream – see the details in the specification. So, whenever you serialize some RDF with Jelly (e.g., using Apache Jena RIOT, RDF4J Rio, or the jelly-stream
module), you need to specify these options.
The eu.ostrzyciel.jelly.core.JellyOptions
object provides a few common presets for Jelly serialization options. They return an instance of eu.ostrzyciel.jelly.core.proto.v1.RdfStreamOptions
that you can further customize. For example:
import eu.ostrzyciel.jelly.core.JellyOptions
val options = JellyOptions.smallStrict
val optionsWithRdfStarSupport = JellyOptions.smallRdfStar
val bigWithCustomDictionarySize = JellyOptions.bigStrict
.withMaxNameTableSize(2000)
Warning
These presets do not specify the physical or logical stream type. In most cases, the Jelly library will take care of this for you and set these types automatically later. However, if you use the low-level API, you need to set the stream types manually. For example:
Checking supported options
There is also the eu.ostrzyciel.jelly.core.JellyOptions.defaultSupportedOptions
method which specifies the maximum set of options supported by default in Jelly-JVM, when parsing a stream. By default, Jelly-JVM will refuse to parse any stream that uses options that are beyond what is specified in this method. This is important for security reasons, as it prevents the library from, for example, allocating a 10 GB dictionary (potential Denial of Service attack).
The supported options check is carried out automatically by the decoder when parsing a stream. You cannot disable the check, but you can customize the supported options by constructing a new RdfStreamOptions
object from eu.ostrzyciel.jelly.core.JellyOptions.defaultSupportedOptions
, customizing it, and passing it to the decoder.
If you want to do this kind of check in some other context (e.g., in a gRPC service to check if you can support the options requested by the client), you can use the eu.ostrzyciel.jelly.core.JellyOptions.checkCompatibility
method. It will throw an exception if the options are not supported.
Useful constants
The eu.ostrzyciel.jelly.core.Constants
object defines some useful constants, such as the file extension for Jelly, its content type, and the version of the Jelly protocol.
RDF Stream Taxonomy (RDF-STaX) stream type utilities
Jelly uses RDF-STaX to define the logical stream types (more details here). Jelly-JVM defines each of these types as a case object in eu.ostrzyciel.jelly.core.proto.v1.LogicalStreamType
.
These objects have a few useful methods for working with the RDF-STaX ontology:
import eu.ostrzyciel.jelly.core.*
import eu.ostrzyciel.jelly.core.proto.v1.LogicalStreamType
// Get the RDF-STaX IRI of a stream type
// returns "https://w3id.org/stax/ontology#flatTripleStream"
LogicalStreamType.TRIPLES.getRdfStaxType
You can also obtain a full RDF-STaX annotation for your stream if you also import an RDF library interop module (e.g., jelly-jena
or jelly-rdf4j
):
// Here we import `jena.given` to get the necessary implicit conversions.
// You can do the same with `rdf4j.given` if you are using RDF4J.
import eu.ostrzyciel.jelly.convert.jena.given
import eu.ostrzyciel.jelly.core.*
import eu.ostrzyciel.jelly.core.proto.v1.LogicalStreamType
import org.apache.jena.graph.NodeFactory
val subjectNode: Node = NodeFactory.createURI("http://example.org/subject")
val triples: Seq[Triple] = LogicalStreamType.QUADS.getRdfStaxAnnotation
// Returns a Seq of three triples that would look like this in Turtle:
// <http://example.org/subject> stax:hasStreamTypeUsage [
// a stax:RdfStreamTypeUsage ;
// stax:hasStreamType stax:flatQuadStream
// ] .
You can then take this annotation and expose as semantic metadata of your stream.
You can also do the opposite and construct an instance of LogicalStreamType
from an RDF-STaX IRI:
import eu.ostrzyciel.jelly.core.LogicalStreamTypeFactory
val iri = "https://w3id.org/stax/ontology#flatQuadStream"
// returns LogicalStreamType.QUADS
val streamType = LogicalStreamTypeFactory.fromOntologyIri(iri)
Finally, there are also stream type checking and manipulation utilities:
import eu.ostrzyciel.jelly.core.*
import eu.ostrzyciel.jelly.core.proto.v1.LogicalStreamType
// Check if this type is equal or a subtype of another type.
// This is useful for performing compatibility checks.
// Returns false
LogicalStreamType.TRIPLES.isEqualOrSubtypeOf(LogicalStreamType.DATASETS)
// Returns true
LogicalStreamType.NAMED_GRAPHS.isEqualOrSubtypeOf(LogicalStreamType.DATASETS)
// Get the "base" type of a stream type. Base types are concrete stream types
// that have no parent types.
// There are only 4 base types: GRAPHS, DATASETS, TRIPLES, QUADS.
// Returns LogicalStreamType.TRIPLES
LogicalStreamType.TRIPLES.toBaseType
// Returns LogicalStreamType.DATASETS
LogicalStreamType.NAMED_GRAPHS.toBaseType
// Returns LogicalStreamType.DATASETS
LogicalStreamType.TIMESTAMPED_NAMED_GRAPHS.toBaseType
Jelly configuration from Typesafe config
The jelly-stream
module also implements a utility for configuring Jelly serialization options using the Typesafe config library, which is commonly used in Apache Pekko applications.
The utility is provided by the eu.ostrzyciel.jelly.stream.JellyOptionsFromTypesafe
object. For example:
import com.typesafe.config.ConfigFactory
import eu.ostrzyciel.jelly.stream.JellyOptionsFromTypesafe
val config = ConfigFactory.parseString("""
|jelly.physical-type = QUADS
|jelly.name-table-size = 1024
|jelly.prefix-table-size = 64
|""".stripMargin)
val options = JellyOptionsFromTypesafe.fromConfig(config.getConfig("jelly"))
options.physicalType // returns PhysicalStreamType.QUADS
options.maxNameTableSize // returns 1024
options.maxPrefixTableSize // returns 64
options.maxDatatypeTableSize // returns 16 (the default)
See the source code of this class for more details.