Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cc69523
Add support for java protobuf generation and port java files from pro…
nk2IsHere Apr 14, 2025
a8d6951
Port java part of core to java module
nk2IsHere Apr 15, 2025
f43448a
Port most of scala parts to java module
nk2IsHere Apr 16, 2025
82723e4
Port some of tests
nk2IsHere Apr 19, 2025
bec285b
Split out Rdf
nk2IsHere Apr 19, 2025
bfe41e4
var -> final var
nk2IsHere Apr 19, 2025
8ddb579
Comments pt 1
nk2IsHere Apr 19, 2025
fc0ad1d
Refactor proto encoder decoder to use handlers for decoding
nk2IsHere Apr 19, 2025
2f7df9f
Finish all tests to compilable state
nk2IsHere Apr 20, 2025
bd2126a
Reformat
nk2IsHere Apr 20, 2025
5c7f99f
Update tests to not fail pt 1
nk2IsHere Apr 20, 2025
c1891d5
Update tests to not fail pt 2
nk2IsHere Apr 20, 2025
8a194d0
All tests pass
nk2IsHere Apr 20, 2025
a3ae706
Fix compilation of java core
nk2IsHere Apr 21, 2025
42f4aba
Restore documentation
nk2IsHere Apr 21, 2025
c188aa5
Add factories
nk2IsHere Apr 21, 2025
5530fb0
Move to eu.neverblink
nk2IsHere Apr 21, 2025
9cf0c90
Update docs for ProtoHandler
nk2IsHere Apr 22, 2025
6462ff7
Remove sinces
nk2IsHere Apr 22, 2025
70e381c
Force jelly transcoder to be non-overridable
nk2IsHere Apr 22, 2025
671dd49
Refactor to remove triples, graphs and quads as nodes
nk2IsHere Apr 22, 2025
c277a32
Generify proto encoder
nk2IsHere Apr 22, 2025
eca4893
Add triple or quad statement handler
nk2IsHere Apr 22, 2025
15e354e
Comments
nk2IsHere Apr 22, 2025
0cbfa27
Comments 2
nk2IsHere Apr 23, 2025
eb66018
Comments 3
nk2IsHere Apr 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 80 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ lazy val commonSettings = Seq(
"-unchecked",
),
javacOptions ++= Seq(
"-Werror",
"-source", "17",
// Currently, impossible to enable this without breaking the build due to warnings in protobuf generated code.
// "-Werror",
// TODO: enable more warnings
"-Xlint:unchecked",
),
Expand All @@ -83,6 +85,59 @@ lazy val rdfProtos = (project in file("rdf-protos"))
publishArtifact := false,
)

lazy val generateProtos = taskKey[Seq[File]]("Copies and modifies proto files before compilation")

// Intermediate project that generates the Scala code from the protobuf files
lazy val rdfProtosJava = (project in file("rdf-protos-java"))
.enablePlugins(ProtobufPlugin)
.settings(
name := "jelly-protos-java",
organization := "eu.neverblink.jelly",
libraryDependencies ++= Seq(
"com.google.protobuf" % "protobuf-java" % protobufV,
),
generateProtos := {
val inputDir = (baseDirectory.value / ".." / "submodules" / "protobuf" / "proto").getAbsoluteFile
val outputDir = (baseDirectory.value / "src" / "main" / "protobuf").getAbsoluteFile

// Make output dir if not exists
IO.createDirectory(outputDir)

// Clean the output directory
IO.delete(IO.listFiles(outputDir))

val protoFiles = (inputDir ** "*.proto").get
protoFiles
.map { file =>
// Copy the file to the output directory
val outputFile = outputDir / file.relativeTo(inputDir).get.getPath
IO.copyFile(file, outputFile)
outputFile
}
.map { file =>
// Append java options to the file
val content = IO.read(file)
val newContent = content +
"""
|option java_multiple_files = true;
|option java_package = "eu.neverblink.jelly.core.proto.v1";
|option optimize_for = SPEED;
|""".stripMargin
IO.write(file, newContent)
file
}

// Return the list of generated files
protoFiles.map { file =>
val outputFile = outputDir / file.relativeTo(inputDir).get.getPath
outputFile
}
},
Compile / compile := (Compile / compile).dependsOn(generateProtos).value,
ProtobufConfig / protobufExcludeFilters := Seq(Glob(baseDirectory.value.toPath) / "**" / "grpc.proto"),
publishArtifact := false,
)

lazy val core = (project in file("core"))
.settings(
name := "jelly-core",
Expand All @@ -103,9 +158,33 @@ lazy val core = (project in file("core"))
commonSettings,
)

lazy val coreJava = (project in file("core-java"))
.settings(
name := "jelly-core-java",
description := "Core code for serializing and deserializing RDF data in the Jelly format. Java edition.",
libraryDependencies ++= Seq(
"com.google.protobuf" % "protobuf-java" % protobufV,
),
Compile / sourceGenerators += Def.task {
// Copy from the managed source directory to the output directory
val inputDir = (rdfProtosJava / target).value / ("scala-" + scalaVersion.value) / "src_managed" / "main"
val outputDir = sourceManaged.value / "main" / "protobuf"
val javaFiles = (inputDir ** "*.java").get
javaFiles.map { file =>
val outputFile = outputDir / file.relativeTo(inputDir).get.getPath
IO.copyFile(file, outputFile)
outputFile
}

}.dependsOn(rdfProtosJava / Compile / compile),
Compile / sourceManaged := sourceManaged.value / "main",
commonSettings,
)

lazy val corePatch = (project in file("core-patch"))
.settings(
name := "jelly-core-patch",
organization := "eu.neverblink.jelly",
description := "Core code for the RDF Patch Jelly extension.",
// Add the generated proto classes after transforming them with Scalameta
Compile / sourceGenerators += Def.task {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package eu.neverblink.jelly.core;

public class JellyConstants {

private JellyConstants() {}

public static final String JELLY_NAME = "Jelly";
public static final String JELLY_FILE_EXTENSION = "jelly";
public static final String JELLY_CONTENT_TYPE = "application/x-jelly-rdf";

public static final int PROTO_VERSION_1_0_X = 1;
public static final int PROTO_VERSION_1_1_X = 2;
public static final int PROTO_VERSION = PROTO_VERSION_1_1_X;

public static final String PROTO_SEMANTIC_VERSION_1_0_0 = "1.0.0"; // First protocol version
public static final String PROTO_SEMANTIC_VERSION_1_1_0 = "1.1.0"; // Protocol version with namespace declarations
public static final String PROTO_SEMANTIC_VERSION_1_1_1 = "1.1.1"; // Protocol version with metadata in RdfStreamFrame
public static final String PROTO_SEMANTIC_VERSION = PROTO_SEMANTIC_VERSION_1_1_1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package eu.neverblink.jelly.core;

import eu.neverblink.jelly.core.internal.ProtoDecoderImpl;
import eu.neverblink.jelly.core.internal.ProtoEncoderImpl;
import eu.neverblink.jelly.core.proto.v1.RdfStreamOptions;

/**
* "Main" interface to be implemented by RDF conversion modules (e.g., for Jena and RDF4J).
* Exposes factory methods for building protobuf encoders and decoders.
* <p>
* This should typically be implemented as an object. You should also provide a package-scoped given for your
* implementation so that users can easily make use of the connector in the stream package.
*
* @param <TNode> Type of RDF nodes in the RDF library
* @param <TDatatype> Type of RDF datatypes in the RDF library
* @param <TEncoderConverter> Implementation of ProtoEncoderConverter for a given RDF library.
* @param <TDecoderConverter> Implementation of ProtoDecoderConverter for a given RDF library.
*/
public abstract class JellyConverterFactory<
TNode,
TDatatype,
TEncoderConverter extends ProtoEncoderConverter<TNode>,
TDecoderConverter extends ProtoDecoderConverter<TNode, TDatatype>
> {

/**
* To be implemented by subclasses. Returns an instance of ProtoEncoderConverter for the RDF library.
*/
protected abstract TEncoderConverter encoderConverter();

/**
* To be implemented by subclasses. Returns an instance of ProtoDecoderConverter for the RDF library.
*/
protected abstract TDecoderConverter decoderConverter();

/**
* Create a new ProtoEncoder.
* @param params Parameters for the encoder.
* @return encoder
*/
public final ProtoEncoder<TNode> encoder(ProtoEncoder.Params params) {
return new ProtoEncoderImpl<>(encoderConverter(), params);
}

/**
* Create a new TriplesDecoder.
* @param supportedOptions maximum supported options for the decoder. If not provided, this.defaultSupportedOptions
* will be used. If you want to modify this (e.g., to specify an expected logical stream
* type), you should always use this.defaultSupportedOptions.withXxx.
* namespace prefix (without a colon), the second is the IRI node.
* @param tripleProtoHandler the handler to use for decoding triples
* @return decoder
*/
public final ProtoDecoder<TNode, TDatatype> triplesDecoder(
RdfHandler.TripleHandler<TNode> tripleProtoHandler,
RdfStreamOptions supportedOptions
) {
return new ProtoDecoderImpl.TriplesDecoder<>(decoderConverter(), tripleProtoHandler, supportedOptions);
}

/**
* Create a new QuadsDecoder.
* @param supportedOptions maximum supported options for the decoder. If not provided, this.defaultSupportedOptions
* will be used. If you want to modify this (e.g., to specify an expected logical stream
* type), you should always use this.defaultSupportedOptions.withXxx.
* @param quadProtoHandler the handler to use for decoding quads
* @return decoder
*/
public final ProtoDecoder<TNode, TDatatype> quadsDecoder(
RdfHandler.QuadHandler<TNode> quadProtoHandler,
RdfStreamOptions supportedOptions
) {
return new ProtoDecoderImpl.QuadsDecoder<>(decoderConverter(), quadProtoHandler, supportedOptions);
}

/**
* Create a new GraphsAsQuadsDecoder.
* @param supportedOptions maximum supported options for the decoder. If not provided, this.defaultSupportedOptions
* will be used. If you want to modify this (e.g., to specify an expected logical stream
* type), you should always use this.defaultSupportedOptions.withXxx.
* @param graphProtoHandler the handler to use for decoding graphs
* @return decoder
*/
public final ProtoDecoder<TNode, TDatatype> graphsAsQuadsDecoder(
RdfHandler.QuadHandler<TNode> graphProtoHandler,
RdfStreamOptions supportedOptions
) {
return new ProtoDecoderImpl.GraphsAsQuadsDecoder<>(decoderConverter(), graphProtoHandler, supportedOptions);
}

/**
* Create a new GraphsDecoder.
* @param supportedOptions maximum supported options for the decoder. If not provided, this.defaultSupportedOptions
* will be used. If you want to modify this (e.g., to specify an expected logical stream
* type), you should always use this.defaultSupportedOptions.withXxx.
* @param graphProtoHandler the handler to use for decoding graphs
* @return decoder
*/
public final ProtoDecoder<TNode, TDatatype> graphsDecoder(
RdfHandler.GraphHandler<TNode> graphProtoHandler,
RdfStreamOptions supportedOptions
) {
return new ProtoDecoderImpl.GraphsDecoder<>(decoderConverter(), graphProtoHandler, supportedOptions);
}

/**
* Create a new AnyStatementDecoder.
* @param supportedOptions maximum supported options for the decoder. If not provided, this.defaultSupportedOptions
* will be used. If you want to modify this (e.g., to specify an expected logical stream
* type), you should always use this.defaultSupportedOptions.withXxx.
* @param anyProtoHandler the handler to use for decoding any statements
* @return decoder
*/
public final ProtoDecoder<TNode, TDatatype> anyDecoder(
RdfHandler.AnyRdfHandler<TNode> anyProtoHandler,
RdfStreamOptions supportedOptions
) {
return new ProtoDecoderImpl.AnyStatementDecoder<>(decoderConverter(), anyProtoHandler, supportedOptions);
}
}
Loading