diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c85e92ec20..e54b1db265 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,7 +24,7 @@ jobs:
distribution: zulu
java-version: ${{ matrix.java }}
- name: Cache Maven packages
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
~/.m2/repository
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 8dc3602146..3de9762eea 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -62,7 +62,7 @@ jobs:
# Cache downloaded Maven dependencies
- name: Cache Maven packages
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: |
~/.m2/repository
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dbfda3be02..7acdd7090f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,18 +2,38 @@
## [Unreleased](https://github.com/aklivity/zilla/tree/HEAD)
-[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.65...HEAD)
+[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.66...HEAD)
+
+**Implemented enhancements:**
+
+- Use `model` and `view` when describing the message type [\#750](https://github.com/aklivity/zilla/issues/750)
+- Support obtaining `protobuf` schemas from `schema registry` for `grpc` services [\#697](https://github.com/aklivity/zilla/issues/697)
+- Support idempotent `mqtt` `qos 2` publish to `kafka` [\#677](https://github.com/aklivity/zilla/issues/677)
+- Detect and inspect invalid messages received [\#676](https://github.com/aklivity/zilla/issues/676)
+- Support incremental validation of fragmented messages sent by client [\#671](https://github.com/aklivity/zilla/issues/671)
**Fixed bugs:**
-- Schema validation fails before the `${{env.*}}` parameters have been removed [\#583](https://github.com/aklivity/zilla/issues/583)
+- TLSv1.3 client handshake stall [\#791](https://github.com/aklivity/zilla/issues/791)
+- Zilla crashes when it tries to send flush on retain stream [\#770](https://github.com/aklivity/zilla/issues/770)
+- Running emqtt\_bench triggers exception in connection pool [\#716](https://github.com/aklivity/zilla/issues/716)
+- `mqtt-kafka` does not limit client sharding to `mqtt v5` [\#708](https://github.com/aklivity/zilla/issues/708)
+- `tls binding` should handle `null` key returned from `vault` [\#395](https://github.com/aklivity/zilla/issues/395)
-**Closed issues:**
+## [0.9.66](https://github.com/aklivity/zilla/tree/0.9.66) (2024-01-24)
+
+[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.65...0.9.66)
+
+**Implemented enhancements:**
- Support `openapi` `http` response validation [\#684](https://github.com/aklivity/zilla/issues/684)
- Support `protobuf` conversion to and from `json` for `kafka` messages [\#682](https://github.com/aklivity/zilla/issues/682)
- Support incubator features preview in zilla release docker image [\#670](https://github.com/aklivity/zilla/issues/670)
+**Fixed bugs:**
+
+- Schema validation fails before the `${{env.*}}` parameters have been removed [\#583](https://github.com/aklivity/zilla/issues/583)
+
**Merged pull requests:**
- update license exclude path to include both zpmw files [\#759](https://github.com/aklivity/zilla/pull/759) ([vordimous](https://github.com/vordimous))
@@ -29,6 +49,10 @@
**Implemented enhancements:**
+- Support `avro` conversion to and from `json` for `kafka` messages [\#681](https://github.com/aklivity/zilla/issues/681)
+- Support observability of zilla engine internal streams [\#678](https://github.com/aklivity/zilla/issues/678)
+- Simplify configuration of multiple protocols on different tcp ports [\#669](https://github.com/aklivity/zilla/issues/669)
+- Simplify kafka client bootstrap server names and ports config [\#619](https://github.com/aklivity/zilla/issues/619)
- MQTT publish QoS 2 as Kafka produce with acks in\_sync\_replicas and idempotent `producerId` [\#605](https://github.com/aklivity/zilla/issues/605)
- Add the option to route by `port` in the `tls` binding [\#564](https://github.com/aklivity/zilla/issues/564)
- Support outbound message transformation from `protobuf` to `json` [\#458](https://github.com/aklivity/zilla/issues/458)
@@ -59,10 +83,6 @@
**Closed issues:**
- Prototype composite binding support with nested namespaces [\#685](https://github.com/aklivity/zilla/issues/685)
-- Support `avro` conversion to and from `json` for `kafka` messages [\#681](https://github.com/aklivity/zilla/issues/681)
-- Support observability of zilla engine internal streams [\#678](https://github.com/aklivity/zilla/issues/678)
-- Simplify configuration of multiple protocols on different tcp ports [\#669](https://github.com/aklivity/zilla/issues/669)
-- Simplify kafka client bootstrap server names and ports config [\#619](https://github.com/aklivity/zilla/issues/619)
- Build has been failed in local [\#229](https://github.com/aklivity/zilla/issues/229)
**Merged pull requests:**
diff --git a/build/flyweight-maven-plugin/pom.xml b/build/flyweight-maven-plugin/pom.xml
index 0debf12a8f..f1e3f15dba 100644
--- a/build/flyweight-maven-plugin/pom.xml
+++ b/build/flyweight-maven-plugin/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
build
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/build/pom.xml b/build/pom.xml
index fe55a455ae..154048bda5 100644
--- a/build/pom.xml
+++ b/build/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/cloud/docker-image/pom.xml b/cloud/docker-image/pom.xml
index 25f346b970..f9ed5c8295 100644
--- a/cloud/docker-image/pom.xml
+++ b/cloud/docker-image/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
cloud
- 0.9.66
+ 0.9.67
../pom.xml
@@ -249,19 +249,25 @@
${project.groupId}
- validator-avro
+ model-avro
${project.version}
runtime
${project.groupId}
- validator-core
+ model-core
${project.version}
runtime
${project.groupId}
- validator-json
+ model-json
+ ${project.version}
+ runtime
+
+
+ ${project.groupId}
+ model-protobuf
${project.version}
runtime
diff --git a/cloud/docker-image/src/main/docker/Dockerfile b/cloud/docker-image/src/main/docker/Dockerfile
index 32d8f73f8b..876a1c77af 100644
--- a/cloud/docker-image/src/main/docker/Dockerfile
+++ b/cloud/docker-image/src/main/docker/Dockerfile
@@ -15,14 +15,12 @@
FROM eclipse-temurin:21-jdk AS build
-RUN apt update && apt install -y gettext
-
COPY maven /root/.m2/repository
COPY zpmw zpmw
COPY zpm.json.template zpm.json.template
-RUN cat zpm.json.template | env VERSION=${project.version} envsubst > zpm.json
+RUN cat zpm.json.template | sed "s/\${VERSION}/${project.version}/g" | tee zpm.json
RUN ./zpmw install --debug --exclude-remote-repositories
RUN ./zpmw clean --keep-image
diff --git a/cloud/docker-image/src/main/docker/assembly.xml b/cloud/docker-image/src/main/docker/assembly.xml
index c67d7d02c0..ca3954717b 100644
--- a/cloud/docker-image/src/main/docker/assembly.xml
+++ b/cloud/docker-image/src/main/docker/assembly.xml
@@ -32,8 +32,8 @@
io/aklivity/zilla/exporter-*/**
io/aklivity/zilla/guard-*/**
io/aklivity/zilla/metrics-*/**
+ io/aklivity/zilla/model-*/**
io/aklivity/zilla/resolver-*/**
- io/aklivity/zilla/validator-*/**
io/aklivity/zilla/vault-*/**
io/aklivity/zilla/command/**
io/aklivity/zilla/command-*/**
@@ -63,6 +63,8 @@
com/fasterxml/jackson/**
org/yaml/snakeyaml/**
org/junit/**
+ com/google/**
+ org/checkerframework/**
diff --git a/cloud/docker-image/src/main/docker/zpm.json.template b/cloud/docker-image/src/main/docker/zpm.json.template
index 0abc7656a5..427e9b3f99 100644
--- a/cloud/docker-image/src/main/docker/zpm.json.template
+++ b/cloud/docker-image/src/main/docker/zpm.json.template
@@ -49,10 +49,11 @@
"io.aklivity.zilla:metrics-stream",
"io.aklivity.zilla:metrics-http",
"io.aklivity.zilla:metrics-grpc",
+ "io.aklivity.zilla:model-avro",
+ "io.aklivity.zilla:model-core",
+ "io.aklivity.zilla:model-json",
+ "io.aklivity.zilla:model-protobuf",
"io.aklivity.zilla:resolver-env",
- "io.aklivity.zilla:validator-avro",
- "io.aklivity.zilla:validator-core",
- "io.aklivity.zilla:validator-json",
"io.aklivity.zilla:vault-filesystem",
"org.slf4j:slf4j-simple",
"org.antlr:antlr4-runtime"
diff --git a/cloud/helm-chart/pom.xml b/cloud/helm-chart/pom.xml
index 8bbbbfdca1..e29d415610 100644
--- a/cloud/helm-chart/pom.xml
+++ b/cloud/helm-chart/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
cloud
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/cloud/pom.xml b/cloud/pom.xml
index 27a2230114..f36e49a984 100644
--- a/cloud/pom.xml
+++ b/cloud/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/conf/pom.xml b/conf/pom.xml
index 434285c312..1395067ed1 100644
--- a/conf/pom.xml
+++ b/conf/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/binding-amqp.spec/pom.xml b/incubator/binding-amqp.spec/pom.xml
index d1d14e2647..7193406bd7 100644
--- a/incubator/binding-amqp.spec/pom.xml
+++ b/incubator/binding-amqp.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/binding-amqp/pom.xml b/incubator/binding-amqp/pom.xml
index 7f5ccd71c7..e0e8777ebf 100644
--- a/incubator/binding-amqp/pom.xml
+++ b/incubator/binding-amqp/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/catalog-inline.spec/pom.xml b/incubator/catalog-inline.spec/pom.xml
index b8538b226d..8c578ec4f3 100644
--- a/incubator/catalog-inline.spec/pom.xml
+++ b/incubator/catalog-inline.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/catalog-inline/pom.xml b/incubator/catalog-inline/pom.xml
index 2748b9e4c2..d51dab34c6 100644
--- a/incubator/catalog-inline/pom.xml
+++ b/incubator/catalog-inline/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/catalog-inline/src/test/java/io/aklivity/zilla/runtime/catalog/inline/internal/InlineIT.java b/incubator/catalog-inline/src/test/java/io/aklivity/zilla/runtime/catalog/inline/internal/InlineIT.java
index c7d02a0577..b979d6281b 100644
--- a/incubator/catalog-inline/src/test/java/io/aklivity/zilla/runtime/catalog/inline/internal/InlineIT.java
+++ b/incubator/catalog-inline/src/test/java/io/aklivity/zilla/runtime/catalog/inline/internal/InlineIT.java
@@ -20,11 +20,15 @@
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
import org.junit.Before;
import org.junit.Test;
import io.aklivity.zilla.runtime.catalog.inline.config.InlineOptionsConfig;
import io.aklivity.zilla.runtime.catalog.inline.config.InlineSchemaConfig;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
public class InlineIT
{
@@ -55,4 +59,39 @@ public void shouldResolveSchemaViaSchemaId()
assertThat(schema, not(nullValue()));
assertEquals(expected, schema);
}
+
+ @Test
+ public void shouldResolveSchemaIdAndProcessData()
+ {
+ InlineCatalogHandler catalog = new InlineCatalogHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "{" +
+ "\"id\": \"123\"," +
+ "\"status\": \"OK\"" +
+ "}";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ int valLength = catalog.decode(data, 0, data.capacity(), ValueConsumer.NOP, CatalogHandler.Decoder.IDENTITY);
+
+ assertEquals(data.capacity(), valLength);
+ }
+
+ @Test
+ public void shouldVerifyEncodedData()
+ {
+ InlineCatalogHandler catalog = new InlineCatalogHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+
+ assertEquals(13, catalog.encode(1, data, 0, data.capacity(),
+ ValueConsumer.NOP, CatalogHandler.Encoder.IDENTITY));
+ }
}
diff --git a/incubator/catalog-schema-registry.spec/pom.xml b/incubator/catalog-schema-registry.spec/pom.xml
index 15425da0e6..cc854fcc9e 100644
--- a/incubator/catalog-schema-registry.spec/pom.xml
+++ b/incubator/catalog-schema-registry.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/catalog.yaml b/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/catalog.yaml
index c39f8ae0f4..1ed998e6f0 100644
--- a/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/catalog.yaml
+++ b/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/config/catalog.yaml
@@ -21,3 +21,4 @@ catalogs:
options:
url: http://localhost:8081
context: default
+ max-age: 30
diff --git a/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json b/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json
index 085fa92996..2864109bc7 100644
--- a/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json
+++ b/incubator/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json
@@ -39,6 +39,12 @@
{
"type": "string",
"default": "default"
+ },
+ "max-age":
+ {
+ "title": "Max Age",
+ "type": "number",
+ "default": 300
}
},
"additionalProperties": false
diff --git a/incubator/catalog-schema-registry/pom.xml b/incubator/catalog-schema-registry/pom.xml
index d932582ca8..bf3457a44f 100644
--- a/incubator/catalog-schema-registry/pom.xml
+++ b/incubator/catalog-schema-registry/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
@@ -75,6 +75,22 @@
com.mycila
license-maven-plugin
+
+ ${project.groupId}
+ flyweight-maven-plugin
+ ${project.version}
+
+ internal
+ io.aklivity.zilla.runtime.catalog.schema.registry.internal.types
+
+
+
+
+ generate
+
+
+
+
maven-checkstyle-plugin
@@ -125,6 +141,9 @@
org.jacoco
jacoco-maven-plugin
+
+ io/aklivity/zilla/runtime/catalog/schema/registry/internal/types/**/*.class
+
BUNDLE
diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/CachedSchemaId.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/CachedSchemaId.java
new file mode 100644
index 0000000000..82ce19d4b6
--- /dev/null
+++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/CachedSchemaId.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.catalog.schema.registry.internal;
+
+public class CachedSchemaId
+{
+ public long timestamp;
+ public int id;
+
+ public CachedSchemaId(
+ long timestamp,
+ int id)
+ {
+ this.timestamp = timestamp;
+ this.id = id;
+ }
+}
diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogHandler.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogHandler.java
index 28376e90a2..c8bc750709 100644
--- a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogHandler.java
+++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogHandler.java
@@ -18,27 +18,39 @@
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
+import java.nio.ByteOrder;
import java.text.MessageFormat;
import java.util.zip.CRC32C;
+import org.agrona.BitUtil;
+import org.agrona.DirectBuffer;
import org.agrona.collections.Int2ObjectCache;
+import org.agrona.concurrent.UnsafeBuffer;
import io.aklivity.zilla.runtime.catalog.schema.registry.internal.config.SchemaRegistryOptionsConfig;
import io.aklivity.zilla.runtime.catalog.schema.registry.internal.serializer.RegisterSchemaRequest;
+import io.aklivity.zilla.runtime.catalog.schema.registry.internal.types.SchemaRegistryPrefixFW;
import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
public class SchemaRegistryCatalogHandler implements CatalogHandler
{
private static final String SUBJECT_VERSION_PATH = "/subjects/{0}/versions/{1}";
private static final String SCHEMA_PATH = "/schemas/ids/{0}";
private static final String REGISTER_SCHEMA_PATH = "/subjects/{0}/versions";
+ private static final int MAX_PADDING_LENGTH = 5;
+ private static final byte MAGIC_BYTE = 0x0;
+
+ private final SchemaRegistryPrefixFW.Builder prefixRW = new SchemaRegistryPrefixFW.Builder()
+ .wrap(new UnsafeBuffer(new byte[5]), 0, 5);
private final HttpClient client;
private final String baseUrl;
private final RegisterSchemaRequest request;
private final CRC32C crc32c;
- private final Int2ObjectCache cache;
- private final Int2ObjectCache schemaIdCache;
+ private final Int2ObjectCache schemas;
+ private final Int2ObjectCache schemaIds;
+ private final long maxAgeMillis;
public SchemaRegistryCatalogHandler(
SchemaRegistryOptionsConfig config)
@@ -47,8 +59,9 @@ public SchemaRegistryCatalogHandler(
this.client = HttpClient.newHttpClient();
this.request = new RegisterSchemaRequest();
this.crc32c = new CRC32C();
- this.cache = new Int2ObjectCache<>(1, 1024, i -> {});
- this.schemaIdCache = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.schemas = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.schemaIds = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.maxAgeMillis = config.maxAge.toMillis();
}
@Override
@@ -69,7 +82,7 @@ public int register(
schemaId = response.statusCode() == 200 ? request.resolveResponse(response.body()) : NO_SCHEMA_ID;
if (schemaId != NO_SCHEMA_ID)
{
- cache.put(schemaId, schema);
+ schemas.put(schemaId, schema);
}
}
catch (Exception ex)
@@ -84,9 +97,9 @@ public String resolve(
int schemaId)
{
String schema;
- if (cache.containsKey(schemaId))
+ if (schemas.containsKey(schemaId))
{
- schema = cache.get(schemaId);
+ schema = schemas.get(schemaId);
}
else
{
@@ -94,7 +107,7 @@ public String resolve(
schema = response != null ? request.resolveSchemaResponse(response) : null;
if (schema != null)
{
- cache.put(schemaId, schema);
+ schemas.put(schemaId, schema);
}
}
return schema;
@@ -108,9 +121,10 @@ public int resolve(
int schemaId;
int checkSum = generateCRC32C(subject, version);
- if (schemaIdCache.containsKey(checkSum))
+ if (schemaIds.containsKey(checkSum) &&
+ (System.currentTimeMillis() - schemaIds.get(checkSum).timestamp) < maxAgeMillis)
{
- schemaId = Integer.parseInt(schemaIdCache.get(checkSum));
+ schemaId = schemaIds.get(checkSum).id;
}
else
{
@@ -118,12 +132,72 @@ public int resolve(
schemaId = response != null ? request.resolveResponse(response) : NO_SCHEMA_ID;
if (schemaId != NO_SCHEMA_ID)
{
- schemaIdCache.put(checkSum, String.valueOf(schemaId));
+ schemaIds.put(checkSum, new CachedSchemaId(System.currentTimeMillis(), schemaId));
}
}
return schemaId;
}
+ @Override
+ public int resolve(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ int schemaId = NO_SCHEMA_ID;
+ if (data.getByte(index) == MAGIC_BYTE)
+ {
+ schemaId = data.getInt(index + BitUtil.SIZE_OF_BYTE, ByteOrder.BIG_ENDIAN);
+ }
+ return schemaId;
+ }
+
+ @Override
+ public int decode(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next,
+ Decoder decoder)
+ {
+ int schemaId = NO_SCHEMA_ID;
+ int progress = 0;
+ int valLength = -1;
+ if (data.getByte(index) == MAGIC_BYTE)
+ {
+ progress += BitUtil.SIZE_OF_BYTE;
+ schemaId = data.getInt(index + progress, ByteOrder.BIG_ENDIAN);
+ progress += BitUtil.SIZE_OF_INT;
+ }
+
+ if (schemaId > NO_SCHEMA_ID)
+ {
+ valLength = decoder.accept(schemaId, data, index + progress, length - progress, next);
+ }
+ return valLength;
+ }
+
+ @Override
+ public int encode(
+ int schemaId,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next,
+ Encoder encoder)
+ {
+ SchemaRegistryPrefixFW prefix = prefixRW.rewrap().schemaId(schemaId).build();
+ next.accept(prefix.buffer(), prefix.offset(), prefix.sizeof());
+ int valLength = encoder.accept(schemaId, data, index, length, next);
+ return valLength > 0 ? prefix.sizeof() + valLength : -1;
+ }
+
+ @Override
+ public int encodePadding()
+ {
+ return MAX_PADDING_LENGTH;
+ }
+
private String sendHttpRequest(
String path)
{
diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfig.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfig.java
index 9febe26531..eabefbf822 100644
--- a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfig.java
+++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfig.java
@@ -14,6 +14,7 @@
*/
package io.aklivity.zilla.runtime.catalog.schema.registry.internal.config;
+import java.time.Duration;
import java.util.function.Function;
import io.aklivity.zilla.runtime.engine.config.OptionsConfig;
@@ -22,6 +23,7 @@ public class SchemaRegistryOptionsConfig extends OptionsConfig
{
public final String url;
public final String context;
+ public final Duration maxAge;
public static SchemaRegistryOptionsConfigBuilder builder()
{
@@ -36,9 +38,11 @@ public static SchemaRegistryOptionsConfigBuilder builder(
public SchemaRegistryOptionsConfig(
String url,
- String context)
+ String context,
+ Duration maxAge)
{
this.url = url;
this.context = context;
+ this.maxAge = maxAge;
}
}
diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapter.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapter.java
index 7b8c01552b..fe98b95780 100644
--- a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapter.java
+++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapter.java
@@ -14,6 +14,8 @@
*/
package io.aklivity.zilla.runtime.catalog.schema.registry.internal.config;
+import java.time.Duration;
+
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
@@ -26,6 +28,7 @@ public class SchemaRegistryOptionsConfigAdapter implements OptionsConfigAdapterS
{
private static final String URL = "url";
private static final String CONTEXT = "context";
+ private static final String MAX_AGE_NAME = "max-age";
@Override
public Kind kind()
@@ -58,6 +61,12 @@ public JsonObject adaptToJson(
catalog.add(CONTEXT, config.context);
}
+ Duration maxAge = config.maxAge;
+ if (maxAge != null)
+ {
+ catalog.add(MAX_AGE_NAME, maxAge.toSeconds());
+ }
+
return catalog.build();
}
@@ -78,6 +87,11 @@ public OptionsConfig adaptFromJson(
{
options.context(object.getString(CONTEXT));
}
+
+ if (object.containsKey(MAX_AGE_NAME))
+ {
+ options.maxAge(Duration.ofSeconds(object.getJsonNumber(MAX_AGE_NAME).longValue()));
+ }
}
return options.build();
diff --git a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigBuilder.java b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigBuilder.java
index 8e05c4049b..eb06664c25 100644
--- a/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigBuilder.java
+++ b/incubator/catalog-schema-registry/src/main/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigBuilder.java
@@ -14,6 +14,7 @@
*/
package io.aklivity.zilla.runtime.catalog.schema.registry.internal.config;
+import java.time.Duration;
import java.util.function.Function;
import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
@@ -21,10 +22,13 @@
public final class SchemaRegistryOptionsConfigBuilder extends ConfigBuilder>
{
+ private static final Duration MAX_AGE_DEFAULT = Duration.ofSeconds(300);
+
private final Function mapper;
private String url;
private String context;
+ private Duration maxAge;
SchemaRegistryOptionsConfigBuilder(
Function mapper)
@@ -53,9 +57,17 @@ public SchemaRegistryOptionsConfigBuilder context(
return this;
}
+ public SchemaRegistryOptionsConfigBuilder maxAge(
+ Duration maxAge)
+ {
+ this.maxAge = maxAge;
+ return this;
+ }
+
@Override
public T build()
{
- return mapper.apply(new SchemaRegistryOptionsConfig(url, context));
+ Duration maxAge = (this.maxAge != null) ? this.maxAge : MAX_AGE_DEFAULT;
+ return mapper.apply(new SchemaRegistryOptionsConfig(url, context, maxAge));
}
}
diff --git a/incubator/catalog-schema-registry/src/main/zilla/internal.idl b/incubator/catalog-schema-registry/src/main/zilla/internal.idl
new file mode 100644
index 0000000000..8a57eb7c2b
--- /dev/null
+++ b/incubator/catalog-schema-registry/src/main/zilla/internal.idl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+scope internal
+{
+ option byteorder network;
+
+ struct SchemaRegistryPrefix
+ {
+ uint8 magic = 0;
+ int32 schemaId;
+ }
+}
diff --git a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogFactoryTest.java b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogFactoryTest.java
index 91bea45a61..ab68d6bf65 100644
--- a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogFactoryTest.java
+++ b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryCatalogFactoryTest.java
@@ -19,6 +19,8 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
+import java.time.Duration;
+
import org.junit.Test;
import io.aklivity.zilla.runtime.catalog.schema.registry.internal.config.SchemaRegistryOptionsConfig;
@@ -45,10 +47,14 @@ public void shouldLoadAndCreate()
CatalogContext context = catalog.supply(mock(EngineContext.class));
assertThat(context, instanceOf(SchemaRegistryCatalogContext.class));
- SchemaRegistryOptionsConfig catalogConfig =
- new SchemaRegistryOptionsConfig("http://localhost:8081", "default");
+ SchemaRegistryOptionsConfig catalogConfig = SchemaRegistryOptionsConfig.builder()
+ .url("http://localhost:8081")
+ .context("default")
+ .maxAge(Duration.ofSeconds(100))
+ .build();
CatalogConfig options = new CatalogConfig("test", "catalog0", "schema-registry", catalogConfig);
CatalogHandler handler = context.attach(options);
+
assertThat(handler, instanceOf(SchemaRegistryCatalogHandler.class));
}
}
diff --git a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryIT.java b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryIT.java
index c115321a4c..f65af539c1 100644
--- a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryIT.java
+++ b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/SchemaRegistryIT.java
@@ -21,6 +21,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.rules.RuleChain.outerRule;
+import java.time.Duration;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -31,6 +35,8 @@
import org.kaazing.k3po.junit.rules.K3poRule;
import io.aklivity.zilla.runtime.catalog.schema.registry.internal.config.SchemaRegistryOptionsConfig;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
public class SchemaRegistryIT
{
@@ -47,7 +53,11 @@ public class SchemaRegistryIT
@Before
public void setup()
{
- config = new SchemaRegistryOptionsConfig("http://localhost:8081", "default");
+ config = SchemaRegistryOptionsConfig.builder()
+ .url("http://localhost:8081")
+ .context("default")
+ .maxAge(Duration.ofSeconds(1))
+ .build();
}
@Test
@@ -153,4 +163,60 @@ public void shouldResolveSchemaViaSubjectVersionFromCache() throws Exception
assertThat(schema, not(nullValue()));
assertEquals(expected, schema);
}
+
+ @Test
+ public void shouldVerifyMaxPadding()
+ {
+ SchemaRegistryCatalogHandler catalog = new SchemaRegistryCatalogHandler(config);
+
+ assertEquals(5, catalog.encodePadding());
+ }
+
+ @Test
+ public void shouldVerifyEncodedData()
+ {
+ SchemaRegistryCatalogHandler catalog = new SchemaRegistryCatalogHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+
+ assertEquals(18, catalog.encode(1, data, 0, data.capacity(),
+ ValueConsumer.NOP, CatalogHandler.Encoder.IDENTITY));
+ }
+
+ @Test
+ public void shouldResolveSchemaIdAndProcessData()
+ {
+
+ SchemaRegistryCatalogHandler catalog = new SchemaRegistryCatalogHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+
+ int valLength = catalog.decode(data, 0, data.capacity(), ValueConsumer.NOP, CatalogHandler.Decoder.IDENTITY);
+
+ assertEquals(data.capacity() - 5, valLength);
+ }
+
+ @Test
+ public void shouldResolveSchemaIdFromData()
+ {
+ SchemaRegistryCatalogHandler catalog = new SchemaRegistryCatalogHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+
+ int schemaId = catalog.resolve(data, 0, data.capacity());
+
+ assertEquals(9, schemaId);
+ }
}
diff --git a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapterTest.java b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapterTest.java
index add863f2d5..0c957a87e2 100644
--- a/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapterTest.java
+++ b/incubator/catalog-schema-registry/src/test/java/io/aklivity/zilla/runtime/catalog/schema/registry/internal/config/SchemaRegistryOptionsConfigAdapterTest.java
@@ -19,6 +19,8 @@
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
+import java.time.Duration;
+
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbBuilder;
import jakarta.json.bind.JsonbConfig;
@@ -45,23 +47,28 @@ public void shouldReadCondition()
"{" +
"\"url\": \"http://localhost:8081\"," +
"\"context\": \"default\"," +
- "}";
+ "}";
SchemaRegistryOptionsConfig catalog = jsonb.fromJson(text, SchemaRegistryOptionsConfig.class);
assertThat(catalog, not(nullValue()));
assertThat(catalog.url, equalTo("http://localhost:8081"));
assertThat(catalog.context, equalTo("default"));
+ assertThat(catalog.maxAge.toSeconds(), equalTo(300L));
}
@Test
public void shouldWriteCondition()
{
- SchemaRegistryOptionsConfig catalog = new SchemaRegistryOptionsConfig("http://localhost:8081", "default");
+ SchemaRegistryOptionsConfig catalog = SchemaRegistryOptionsConfig.builder()
+ .url("http://localhost:8081")
+ .context("default")
+ .maxAge(Duration.ofSeconds(300))
+ .build();
String text = jsonb.toJson(catalog);
assertThat(text, not(nullValue()));
- assertThat(text, equalTo("{\"url\":\"http://localhost:8081\",\"context\":\"default\"}"));
+ assertThat(text, equalTo("{\"url\":\"http://localhost:8081\",\"context\":\"default\",\"max-age\":300}"));
}
}
diff --git a/incubator/command-dump/pom.xml b/incubator/command-dump/pom.xml
index 23c3d4c19e..53be863e0c 100644
--- a/incubator/command-dump/pom.xml
+++ b/incubator/command-dump/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/command-dump/src/main/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/zilla.lua b/incubator/command-dump/src/main/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/zilla.lua
index 355b14a8f0..9cf59d0b9f 100644
--- a/incubator/command-dump/src/main/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/zilla.lua
+++ b/incubator/command-dump/src/main/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/zilla.lua
@@ -142,6 +142,7 @@ local kafka_ext_apis = {
[253] = "GROUP",
[254] = "BOOTSTRAP",
[255] = "MERGED",
+ [22] = "INIT_PRODUCER_ID",
[3] = "META",
[8] = "OFFSET_COMMIT",
[9] = "OFFSET_FETCH",
@@ -432,7 +433,8 @@ local fields = {
mqtt_ext_topic_length = ProtoField.int16("zilla.mqtt_ext.topic_length", "Length", base.DEC),
mqtt_ext_topic = ProtoField.string("zilla.mqtt_ext.topic", "Topic", base.NONE),
mqtt_ext_expiry = ProtoField.int32("zilla.mqtt_ext.expiry", "Expiry", base.DEC),
- mqtt_ext_qos_max = ProtoField.uint16("zilla.mqtt_ext.qos_max", "QoS Maximum", base.DEC),
+ mqtt_ext_subscribe_qos_max = ProtoField.uint16("zilla.mqtt_ext.subscribe_qos_max", "Subscribe QoS Maximum", base.DEC),
+ mqtt_ext_publish_qos_max = ProtoField.uint16("zilla.mqtt_ext.publish_qos_max", "Publish QoS Maximum", base.DEC),
mqtt_ext_packet_size_max = ProtoField.uint32("zilla.mqtt_ext.packet_size_max", "Packet Size Maximum", base.DEC),
-- capabilities
mqtt_ext_capabilities = ProtoField.uint8("zilla.mqtt_ext.capabilities", "Capabilities", base.HEX),
@@ -584,6 +586,8 @@ local fields = {
kafka_ext_ancestor_offset = ProtoField.int64("zilla.kafka_ext.ancestor_offset", "Ancestor Offset", base.DEC),
kafka_ext_headers_array_length = ProtoField.int8("zilla.kafka_ext.headers_array_length", "Length", base.DEC),
kafka_ext_headers_array_size = ProtoField.int8("zilla.kafka_ext.headers_array_size", "Size", base.DEC),
+ kafka_ext_producer_id = ProtoField.uint64("zilla.kafka_ext.producer_id", "Producer ID", base.HEX),
+ kafka_ext_producer_epoch = ProtoField.uint16("zilla.kafka_ext.producer_epoch", "Producer Epoch", base.HEX),
-- meta
kafka_ext_partition_leader_id = ProtoField.int32("zilla.kafka_ext.partition_leader_id", "Leader ID", base.DEC),
-- offset_fetch
@@ -600,7 +604,6 @@ local fields = {
kafka_ext_config = ProtoField.string("zilla.kafka_ext.config", "Config", base.NONE),
-- fetch
kafka_ext_header_size_max = ProtoField.int32("zilla.kafka_ext.header_size_max", "Header Size Maximum", base.DEC),
- kafka_ext_producer_id = ProtoField.uint64("zilla.kafka_ext.producer_id", "Producer ID", base.HEX),
kafka_ext_transactions_array_length = ProtoField.int8("zilla.kafka_ext.transactions_array_length", "Length", base.DEC),
kafka_ext_transactions_array_size = ProtoField.int8("zilla.kafka_ext.transactions_array_size", "Size", base.DEC),
kafka_ext_transaction_result = ProtoField.int8("zilla.kafka_ext.transaction_result", "Result", base.DEC,
@@ -1611,8 +1614,12 @@ function handle_mqtt_extension(buffer, offset, ext_subtree, frame_type_id)
elseif kind == "SESSION" then
handle_mqtt_data_session_extension(buffer, offset + kind_length, ext_subtree)
end
- elseif frame_type_id == FLUSH_ID and kind == "SUBSCRIBE" then
- handle_mqtt_flush_subscribe_extension(buffer, offset + kind_length, ext_subtree)
+ elseif frame_type_id == FLUSH_ID then
+ if kind == "SUBSCRIBE" then
+ handle_mqtt_flush_subscribe_extension(buffer, offset + kind_length, ext_subtree)
+ elseif kind == "SESSION" then
+ handle_mqtt_flush_session_extension(buffer, offset + kind_length, ext_subtree)
+ end
end
elseif frame_type_id == RESET_ID then
handle_mqtt_reset_extension(buffer, offset, ext_subtree)
@@ -1718,13 +1725,18 @@ function handle_mqtt_begin_session_extension(buffer, offset, ext_subtree)
local expiry_length = 4
local slice_expiry = buffer(expiry_offset, expiry_length)
ext_subtree:add_le(fields.mqtt_ext_expiry, slice_expiry)
- -- qos_max
- local qos_max_offset = expiry_offset + expiry_length
- local qos_max_length = 2
- local slice_qos_max = buffer(qos_max_offset, qos_max_length)
- ext_subtree:add_le(fields.mqtt_ext_qos_max, slice_qos_max)
+ -- subscribe_qos_max
+ local subscribe_qos_max_offset = expiry_offset + expiry_length
+ local subscribe_qos_max_length = 2
+ local slice_subscribe_qos_max = buffer(subscribe_qos_max_offset, subscribe_qos_max_length)
+ ext_subtree:add_le(fields.mqtt_ext_subscribe_qos_max, slice_subscribe_qos_max)
+ -- publish_qos_max
+ local publish_qos_max_offset = subscribe_qos_max_offset + subscribe_qos_max_length
+ local publish_qos_max_length = 2
+ local slice_publish_qos_max = buffer(publish_qos_max_offset, publish_qos_max_length)
+ ext_subtree:add_le(fields.mqtt_ext_publish_qos_max, slice_publish_qos_max)
-- packet_size_max
- local packet_size_max_offset = qos_max_offset + qos_max_length
+ local packet_size_max_offset = publish_qos_max_offset + publish_qos_max_length
local packet_size_max_length = 4
local slice_packet_size_max = buffer(packet_size_max_offset, packet_size_max_length)
ext_subtree:add_le(fields.mqtt_ext_packet_size_max, slice_packet_size_max)
@@ -1763,8 +1775,13 @@ function handle_mqtt_data_publish_extension(buffer, offset, ext_subtree)
local flags_label = string.format("Flags: 0x%02x", slice_flags:le_uint())
local flags_subtree = ext_subtree:add(zilla_protocol, slice_flags, flags_label)
flags_subtree:add_le(fields.mqtt_ext_publish_flags_retain, slice_flags)
+ -- packet_id
+ local packet_id_offset = flags_offset + flags_length
+ local packet_id_length = 2
+ local slice_packet_id = buffer(packet_id_offset, packet_id_length)
+ ext_subtree:add_le(fields.mqtt_ext_packet_id, slice_packet_id)
-- expiry_interval
- local expiry_interval_offset = flags_offset + flags_length
+ local expiry_interval_offset = packet_id_offset + packet_id_length
local expiry_interval_length = 4
local slice_expiry_interval = buffer(expiry_interval_offset, expiry_interval_length)
ext_subtree:add_le(fields.mqtt_ext_expiry_interval, slice_expiry_interval)
@@ -1943,6 +1960,14 @@ function handle_mqtt_flush_subscribe_extension(buffer, offset, ext_subtree)
dissect_and_add_mqtt_topic_filters(buffer, topic_filters_offset, ext_subtree)
end
+function handle_mqtt_flush_session_extension(buffer, offset, ext_subtree)
+ -- packet_id
+ local packet_id_offset = offset
+ local packet_id_length = 2
+ local slice_packet_id = buffer(packet_id_offset, packet_id_length)
+ ext_subtree:add_le(fields.mqtt_ext_packet_id, slice_packet_id)
+end
+
function handle_mqtt_reset_extension(buffer, offset, ext_subtree)
-- server_ref
local server_ref_offset = offset
@@ -1976,6 +2001,8 @@ function handle_kafka_extension(buffer, offset, ext_subtree, frame_type_id)
handle_kafka_begin_bootstrap_extension(buffer, offset + api_length, ext_subtree)
elseif api == "MERGED" then
handle_kafka_begin_merged_extension(buffer, offset + api_length, ext_subtree)
+ elseif api == "INIT_PRODUCER_ID" then
+ handle_kafka_begin_init_producer_id_extension(buffer, offset + api_length, ext_subtree)
elseif api == "META" then
handle_kafka_begin_meta_extension(buffer, offset + api_length, ext_subtree)
elseif api == "OFFSET_COMMIT" then
@@ -2366,6 +2393,19 @@ function handle_kafka_begin_merged_extension(buffer, offset, ext_subtree)
ext_subtree:add(fields.kafka_ext_ack_mode, ack_mode)
end
+function handle_kafka_begin_init_producer_id_extension(buffer, offset, ext_subtree)
+ -- producer_id
+ local producer_id_offset = offset
+ local producer_id_length = 8
+ local slice_producer_id = buffer(producer_id_offset, producer_id_length)
+ ext_subtree:add_le(fields.kafka_ext_producer_id, slice_producer_id)
+ -- producer_epoch
+ local producer_epoch_offset = producer_id_offset + producer_id_length
+ local producer_epoch_length = 2
+ local slice_producer_epoch = buffer(producer_epoch_offset, producer_epoch_length)
+ ext_subtree:add_le(fields.kafka_ext_producer_epoch, slice_producer_epoch)
+end
+
function dissect_and_add_kafka_filters_array(buffer, offset, tree, field_array_length, field_array_size)
local length, array_size = dissect_and_add_array_header_as_subtree(buffer, offset, tree, "Filters (%d items)",
field_array_length, field_array_size)
@@ -2791,8 +2831,18 @@ function handle_kafka_data_merged_produce_extension(buffer, offset, ext_subtree)
local timestamp_length = 8
local slice_timestamp = buffer(timestamp_offset, timestamp_length)
ext_subtree:add_le(fields.sse_ext_timestamp, slice_timestamp)
+ -- producer_id
+ local producer_id_offset = timestamp_offset + timestamp_length
+ local producer_id_length = 8
+ local slice_producer_id = buffer(producer_id_offset, producer_id_length)
+ ext_subtree:add_le(fields.kafka_ext_producer_id, slice_producer_id)
+ -- producer_epoch
+ local producer_epoch_offset = producer_id_offset + producer_id_length
+ local producer_epoch_length = 2
+ local slice_producer_epoch = buffer(producer_epoch_offset, producer_epoch_length)
+ ext_subtree:add_le(fields.kafka_ext_producer_epoch, slice_producer_epoch)
-- partition
- local partition_offset = timestamp_offset + timestamp_length
+ local partition_offset = producer_epoch_offset + producer_epoch_length
local partition_length = resolve_length_of_kafka_offset(buffer, partition_offset)
dissect_and_add_kafka_offset(buffer, partition_offset, ext_subtree, "Partition: %d [%d]")
-- key
@@ -2909,13 +2959,8 @@ function dissect_and_add_kafka_partition_array(buffer, offset, tree, field_array
end
function handle_kafka_begin_offset_commit_extension(buffer, offset, ext_subtree)
- -- topic
- local topic_offset = offset
- local topic_length, slice_topic_length, slice_topic_text = dissect_length_value(buffer, topic_offset, 2)
- add_string_as_subtree(buffer(topic_offset, topic_length), ext_subtree, "Topic: %s",
- slice_topic_length, slice_topic_text, fields.mqtt_ext_topic_length, fields.mqtt_ext_topic)
-- group_id
- local group_id_offset = topic_offset + topic_length
+ local group_id_offset = offset
local group_id_length, slice_group_id_length, slice_group_id_text = dissect_length_value(buffer, group_id_offset, 2)
add_string_as_subtree(buffer(group_id_offset, group_id_length), ext_subtree, "Group ID: %s",
slice_group_id_length, slice_group_id_text, fields.kafka_ext_group_id_length, fields.kafka_ext_group_id)
@@ -2929,11 +2974,26 @@ function handle_kafka_begin_offset_commit_extension(buffer, offset, ext_subtree)
local instance_id_length, slice_instance_id_length, slice_instance_id_text = dissect_length_value(buffer, instance_id_offset, 2)
add_string_as_subtree(buffer(instance_id_offset, instance_id_length), ext_subtree, "Instance ID: %s",
slice_instance_id_length, slice_instance_id_text, fields.kafka_ext_instance_id_length, fields.kafka_ext_instance_id)
+ -- host
+ local host_offset = instance_id_offset + instance_id_length
+ local host_length, slice_host_length, slice_host_text = dissect_length_value(buffer, host_offset, 2)
+ add_string_as_subtree(buffer(host_offset, host_length), ext_subtree, "Host: %s",
+ slice_host_length, slice_host_text, fields.kafka_ext_host_length, fields.kafka_ext_host)
+ -- port
+ local port_offset = host_offset + host_length
+ local port_length = 4
+ local slice_port = buffer(port_offset, port_length)
+ ext_subtree:add_le(fields.kafka_ext_port, slice_port)
end
function handle_kafka_data_offset_commit_extension(buffer, offset, ext_subtree)
+ -- topic
+ local topic_offset = offset
+ local topic_lentgh, slice_topic_length, slice_topic_text = dissect_length_value(buffer, topic_offset, 2)
+ add_string_as_subtree(buffer(topic_offset, topic_length), ext_subtree, "Topic: %s",
+ slice_topic_length, slice_topic_text, fields.mqtt_ext_topic_length, fields.mqtt_ext_topic)
-- progress
- local progress_offset = offset
+ local progress_offset = topic_offset + topic_lentgh
local progress_length = resolve_length_of_kafka_offset(buffer, progress_offset)
dissect_and_add_kafka_offset(buffer, progress_offset, ext_subtree, "Progress: %d [%d]")
-- generation_id
@@ -3285,13 +3345,8 @@ function handle_kafka_begin_produce_extension(buffer, offset, ext_subtree)
local transaction_length, slice_transaction_length, slice_transaction_text = dissect_length_value(buffer, transaction_offset, 1)
add_string_as_subtree(buffer(transaction_offset, transaction_length), ext_subtree, "Transaction: %s", slice_transaction_length,
slice_transaction_text, fields.kafka_ext_transaction_length, fields.kafka_ext_transaction)
- -- producer_id
- local producer_id_offset = transaction_offset + transaction_length
- local producer_id_length = 8
- local slice_producer_id = buffer(producer_id_offset, producer_id_length)
- ext_subtree:add_le(fields.kafka_ext_producer_id, slice_producer_id)
-- topic
- local topic_offset = producer_id_offset + producer_id_length
+ local topic_offset = transaction_offset + transaction_length
local topic_length, slice_topic_length, slice_topic_text = dissect_length_value(buffer, topic_offset, 2)
add_string_as_subtree(buffer(topic_offset, topic_length), ext_subtree, "Topic: %s",
slice_topic_length, slice_topic_text, fields.mqtt_ext_topic_length, fields.mqtt_ext_topic)
@@ -3312,8 +3367,18 @@ function handle_kafka_data_produce_extension(buffer, offset, ext_subtree)
local timestamp_length = 8
local slice_timestamp = buffer(timestamp_offset, timestamp_length)
ext_subtree:add_le(fields.sse_ext_timestamp, slice_timestamp)
+ -- producer_id
+ local producer_id_offset = timestamp_offset + timestamp_length
+ local producer_id_length = 8
+ local slice_producer_id = buffer(producer_id_offset, producer_id_length)
+ ext_subtree:add_le(fields.kafka_ext_producer_id, slice_producer_id)
+ -- producer_epoch
+ local producer_epoch_offset = producer_id_offset + producer_id_length
+ local producer_epoch_length = 2
+ local slice_producer_epoch = buffer(producer_epoch_offset, producer_epoch_length)
+ ext_subtree:add_le(fields.kafka_ext_producer_epoch, slice_producer_epoch)
-- sequence
- local sequence_offset = timestamp_offset + timestamp_length
+ local sequence_offset = producer_epoch_offset + producer_epoch_length
local sequence_length = 4
local slice_sequence = buffer(sequence_offset, sequence_length)
ext_subtree:add_le(fields.kafka_ext_sequence, slice_sequence)
diff --git a/incubator/command-dump/src/test/java/io/aklivity/zilla/runtime/command/dump/internal/airline/ZillaDumpCommandTest.java b/incubator/command-dump/src/test/java/io/aklivity/zilla/runtime/command/dump/internal/airline/ZillaDumpCommandTest.java
index 483c3a3c06..faa4f8abf9 100644
--- a/incubator/command-dump/src/test/java/io/aklivity/zilla/runtime/command/dump/internal/airline/ZillaDumpCommandTest.java
+++ b/incubator/command-dump/src/test/java/io/aklivity/zilla/runtime/command/dump/internal/airline/ZillaDumpCommandTest.java
@@ -1272,6 +1272,7 @@ public void generateStreamsBuffer() throws Exception
.publish()
.qos("EXACTLY_ONCE")
.flags("RETAIN")
+ .packetId(0x42)
.expiryInterval(77)
.contentType("Content Type")
.format("BINARY")
@@ -1493,7 +1494,8 @@ public void generateStreamsBuffer() throws Exception
.session()
.flags("CLEAN_START")
.expiry(42)
- .qosMax(2)
+ .subscribeQosMax(2)
+ .publishQosMax(1)
.packetSizeMax(42_000)
.capabilities("RETAIN")
.clientId("client-id")
@@ -1518,7 +1520,8 @@ public void generateStreamsBuffer() throws Exception
.session()
.flags("CLEAN_START", "WILL")
.expiry(42)
- .qosMax(2)
+ .subscribeQosMax(1)
+ .publishQosMax(2)
.packetSizeMax(42_000)
.capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS")
.clientId("client-id")
@@ -1585,6 +1588,27 @@ public void generateStreamsBuffer() throws Exception
.build();
streams[0].write(DataFW.TYPE_ID, data23.buffer(), 0, data23.sizeof());
+ DirectBuffer mqttSessionFlushEx1 = new UnsafeBuffer(MqttFunctions.flushEx()
+ .typeId(MQTT_TYPE_ID)
+ .session()
+ .packetId(0x2142)
+ .build()
+ .build());
+ FlushFW flush5 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ .originId(0x0000000900000022L) // north_mqtt_server
+ .routedId(0x0000000900000023L) // north_mqtt_kafka_mapping
+ .streamId(0x0000000000000025L) // INI
+ .sequence(401)
+ .acknowledge(402)
+ .maximum(7777)
+ .timestamp(0x0000000000000143L)
+ .traceId(0x0000000000000025L)
+ .budgetId(0x0000000000000000L)
+ .reserved(0x00000000)
+ .extension(mqttSessionFlushEx1, 0, mqttSessionFlushEx1.capacity())
+ .build();
+ streams[0].write(FlushFW.TYPE_ID, flush5.buffer(), 0, flush5.sizeof());
+
// kafka extension
// - CONSUMER
DirectBuffer kafkaConsumerBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
@@ -1680,7 +1704,7 @@ public void generateStreamsBuffer() throws Exception
.correlationId(77)
.build()
.build());
- FlushFW flush5 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush6 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000027L) // INI
@@ -1693,7 +1717,7 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaConsumerFlushEx1, 0, kafkaConsumerFlushEx1.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush5.buffer(), 0, flush5.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush6.buffer(), 0, flush6.sizeof());
DirectBuffer kafkaResetEx1 = new UnsafeBuffer(KafkaFunctions.resetEx()
.typeId(KAFKA_TYPE_ID)
@@ -1773,7 +1797,7 @@ public void generateStreamsBuffer() throws Exception
.memberId("member-id")
.build()
.build());
- FlushFW flush6 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush7 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000029L) // INI
@@ -1786,7 +1810,7 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaGroupFlushEx1, 0, kafkaGroupFlushEx1.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush6.buffer(), 0, flush6.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush7.buffer(), 0, flush7.sizeof());
DirectBuffer kafkaGroupFlushEx2 = new UnsafeBuffer(KafkaFunctions.flushEx()
.typeId(KAFKA_TYPE_ID)
@@ -1799,7 +1823,7 @@ public void generateStreamsBuffer() throws Exception
.members("member-3")
.build()
.build());
- FlushFW flush7 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush8 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000028L) // REP
@@ -1812,7 +1836,7 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaGroupFlushEx2, 0, kafkaGroupFlushEx2.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush7.buffer(), 0, flush7.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush8.buffer(), 0, flush8.sizeof());
// - BOOTSTRAP
DirectBuffer kafkaBootstrapBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
@@ -2029,6 +2053,8 @@ public void generateStreamsBuffer() throws Exception
.produce()
.deferred(100)
.timestamp(0x53)
+ .producerId(0x77L)
+ .producerEpoch((short) 0x42)
.partition(1, 77_000)
.key("key")
.hashKey("hash-key")
@@ -2060,7 +2086,7 @@ public void generateStreamsBuffer() throws Exception
.correlationId(77)
.build()
.build());
- FlushFW flush8 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush9 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000033L) // INI
@@ -2073,7 +2099,7 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaMergedConsumerFlushEx, 0, kafkaMergedConsumerFlushEx.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush8.buffer(), 0, flush8.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush9.buffer(), 0, flush9.sizeof());
DirectBuffer kafkaMergedFetchFlushEx = new UnsafeBuffer(KafkaFunctions.flushEx()
.typeId(KAFKA_TYPE_ID)
@@ -2090,7 +2116,7 @@ public void generateStreamsBuffer() throws Exception
.key("key")
.build()
.build());
- FlushFW flush9 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush10 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000033L) // INI
@@ -2103,16 +2129,59 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaMergedFetchFlushEx, 0, kafkaMergedFetchFlushEx.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush9.buffer(), 0, flush9.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush10.buffer(), 0, flush10.sizeof());
+
+ // - INIT_PRODUCER_ID
+ DirectBuffer kafkaInitProducerIdBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ .typeId(KAFKA_TYPE_ID)
+ .initProducerId()
+ .producerId(0x77L)
+ .producerEpoch((short) 0x42)
+ .build()
+ .build());
+ BeginFW begin34 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ .originId(0x000000090000000fL) // north_kafka_cache_client
+ .routedId(0x0000000900000010L) // south_kafka_cache_server
+ .streamId(0x0000000000000133L) // INI
+ .sequence(0)
+ .acknowledge(0)
+ .maximum(0)
+ .timestamp(0x0000000000000056L)
+ .traceId(0x0000000000000035L)
+ .affinity(0x0000000000000000L)
+ .extension(kafkaInitProducerIdBeginEx1, 0, kafkaInitProducerIdBeginEx1.capacity())
+ .build();
+ streams[0].write(BeginFW.TYPE_ID, begin34.buffer(), 0, begin34.sizeof());
+
+ DirectBuffer kafkaInitProducerIdBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ .typeId(KAFKA_TYPE_ID)
+ .initProducerId()
+ .producerId(0x88L)
+ .producerEpoch((short) 0x21)
+ .build()
+ .build());
+ BeginFW begin35 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ .originId(0x000000090000000fL) // north_kafka_cache_client
+ .routedId(0x0000000900000010L) // south_kafka_cache_server
+ .streamId(0x0000000000000132L) // REP
+ .sequence(0)
+ .acknowledge(0)
+ .maximum(0)
+ .timestamp(0x0000000000000057L)
+ .traceId(0x0000000000000035L)
+ .affinity(0x0000000000000000L)
+ .extension(kafkaInitProducerIdBeginEx2, 0, kafkaInitProducerIdBeginEx2.capacity())
+ .build();
+ streams[0].write(BeginFW.TYPE_ID, begin35.buffer(), 0, begin35.sizeof());
// - META
- DirectBuffer kafkaMetaBegin1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaMetaBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.meta()
.topic("topic")
.build()
.build());
- BeginFW begin34 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin36 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000035L) // INI
@@ -2122,17 +2191,17 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000056L)
.traceId(0x0000000000000035L)
.affinity(0x0000000000000000L)
- .extension(kafkaMetaBegin1, 0, kafkaMetaBegin1.capacity())
+ .extension(kafkaMetaBeginEx1, 0, kafkaMetaBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin34.buffer(), 0, begin34.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin36.buffer(), 0, begin36.sizeof());
- DirectBuffer kafkaMetaBegin2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaMetaBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.meta()
.topic("topic")
.build()
.build());
- BeginFW begin35 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin37 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000034L) // REP
@@ -2142,9 +2211,9 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000057L)
.traceId(0x0000000000000035L)
.affinity(0x0000000000000000L)
- .extension(kafkaMetaBegin2, 0, kafkaMetaBegin2.capacity())
+ .extension(kafkaMetaBeginEx2, 0, kafkaMetaBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin35.buffer(), 0, begin35.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin37.buffer(), 0, begin37.sizeof());
DirectBuffer kafkaMetaDataPayload = new String8FW("kafka meta data payload").value();
DirectBuffer kafkaMetaDataEx1 = new UnsafeBuffer(KafkaFunctions.dataEx()
@@ -2172,16 +2241,17 @@ public void generateStreamsBuffer() throws Exception
streams[0].write(DataFW.TYPE_ID, data27.buffer(), 0, data27.sizeof());
// - OFFSET_COMMIT
- DirectBuffer kafkaOffsetCommitBegin1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaOffsetCommitBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.offsetCommit()
- .topic("topic")
.groupId("group")
.memberId("member")
.instanceId("instance")
+ .host("host")
+ .port(4242)
.build()
.build());
- BeginFW begin36 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin38 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000037L) // INI
@@ -2191,20 +2261,21 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000059L)
.traceId(0x0000000000000037L)
.affinity(0x0000000000000000L)
- .extension(kafkaOffsetCommitBegin1, 0, kafkaOffsetCommitBegin1.capacity())
+ .extension(kafkaOffsetCommitBeginEx1, 0, kafkaOffsetCommitBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin36.buffer(), 0, begin36.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin38.buffer(), 0, begin38.sizeof());
- DirectBuffer kafkaOffsetCommitBegin2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaOffsetCommitBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.offsetCommit()
- .topic("topic")
.groupId("group")
.memberId("member")
.instanceId("instance")
+ .host("host")
+ .port(4242)
.build()
.build());
- BeginFW begin37 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin39 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000036L) // REP
@@ -2214,14 +2285,15 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x000000000000005aL)
.traceId(0x0000000000000037L)
.affinity(0x0000000000000000L)
- .extension(kafkaOffsetCommitBegin2, 0, kafkaOffsetCommitBegin2.capacity())
+ .extension(kafkaOffsetCommitBeginEx2, 0, kafkaOffsetCommitBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin37.buffer(), 0, begin37.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin39.buffer(), 0, begin39.sizeof());
DirectBuffer kafkaOffsetCommitDataPayload = new String8FW("kafka offset commit data payload").value();
DirectBuffer kafkaOffsetCommitDataEx1 = new UnsafeBuffer(KafkaFunctions.dataEx()
.typeId(KAFKA_TYPE_ID)
.offsetCommit()
+ .topic("test")
.progress(21, 1234, "metadata")
.generationId(42)
.leaderEpoch(77)
@@ -2244,7 +2316,7 @@ public void generateStreamsBuffer() throws Exception
streams[0].write(DataFW.TYPE_ID, data28.buffer(), 0, data28.sizeof());
// - OFFSET_FETCH
- DirectBuffer kafkaOffsetFetchBegin1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaOffsetFetchBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.offsetFetch()
.groupId("group")
@@ -2257,7 +2329,7 @@ public void generateStreamsBuffer() throws Exception
.partition(88)
.build()
.build());
- BeginFW begin38 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin40 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000039L) // INI
@@ -2267,11 +2339,11 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x000000000000005cL)
.traceId(0x0000000000000039L)
.affinity(0x0000000000000000L)
- .extension(kafkaOffsetFetchBegin1, 0, kafkaOffsetFetchBegin1.capacity())
+ .extension(kafkaOffsetFetchBeginEx1, 0, kafkaOffsetFetchBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin38.buffer(), 0, begin38.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin40.buffer(), 0, begin40.sizeof());
- DirectBuffer kafkaOffsetFetchBegin2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaOffsetFetchBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.offsetFetch()
.groupId("group")
@@ -2281,7 +2353,7 @@ public void generateStreamsBuffer() throws Exception
.partition(42)
.build()
.build());
- BeginFW begin39 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin41 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x0000000000000038L) // REP
@@ -2291,9 +2363,9 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x000000000000005dL)
.traceId(0x0000000000000039L)
.affinity(0x0000000000000000L)
- .extension(kafkaOffsetFetchBegin2, 0, kafkaOffsetFetchBegin2.capacity())
+ .extension(kafkaOffsetFetchBeginEx2, 0, kafkaOffsetFetchBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin39.buffer(), 0, begin39.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin41.buffer(), 0, begin41.sizeof());
DirectBuffer kafkaOffsetFetchDataPayload = new String8FW("kafka offset fetch data payload").value();
DirectBuffer kafkaOffsetFetchDataEx1 = new UnsafeBuffer(KafkaFunctions.dataEx()
@@ -2321,7 +2393,7 @@ public void generateStreamsBuffer() throws Exception
streams[0].write(DataFW.TYPE_ID, data29.buffer(), 0, data29.sizeof());
// - DESCRIBE
- DirectBuffer kafkaDescribeBegin1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaDescribeBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.describe()
.topic("topic")
@@ -2330,7 +2402,7 @@ public void generateStreamsBuffer() throws Exception
.config("config3")
.build()
.build());
- BeginFW begin40 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin42 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003bL) // INI
@@ -2340,18 +2412,18 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x000000000000005fL)
.traceId(0x000000000000003bL)
.affinity(0x0000000000000000L)
- .extension(kafkaDescribeBegin1, 0, kafkaDescribeBegin1.capacity())
+ .extension(kafkaDescribeBeginEx1, 0, kafkaDescribeBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin40.buffer(), 0, begin40.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin42.buffer(), 0, begin42.sizeof());
- DirectBuffer kafkaDescribeBegin2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaDescribeBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.describe()
.topic("topic")
// configs omitted
.build()
.build());
- BeginFW begin41 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin43 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003aL) // REP
@@ -2361,9 +2433,9 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000060L)
.traceId(0x000000000000003bL)
.affinity(0x0000000000000000L)
- .extension(kafkaDescribeBegin2, 0, kafkaDescribeBegin2.capacity())
+ .extension(kafkaDescribeBeginEx2, 0, kafkaDescribeBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin41.buffer(), 0, begin41.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin43.buffer(), 0, begin43.sizeof());
DirectBuffer kafkaDescribeDataPayload = new String8FW("kafka describe payload").value();
DirectBuffer kafkaDescribeDataEx1 = new UnsafeBuffer(KafkaFunctions.dataEx()
@@ -2391,7 +2463,7 @@ public void generateStreamsBuffer() throws Exception
streams[0].write(DataFW.TYPE_ID, data30.buffer(), 0, data30.sizeof());
// - FETCH
- DirectBuffer kafkaFetchBegin1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaFetchBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.fetch()
.topic("topic")
@@ -2410,7 +2482,7 @@ public void generateStreamsBuffer() throws Exception
.deltaType("NONE")
.build()
.build());
- BeginFW begin42 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin44 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003dL) // INI
@@ -2420,11 +2492,11 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000062L)
.traceId(0x000000000000003dL)
.affinity(0x0000000000000000L)
- .extension(kafkaFetchBegin1, 0, kafkaFetchBegin1.capacity())
+ .extension(kafkaFetchBeginEx1, 0, kafkaFetchBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin42.buffer(), 0, begin42.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin44.buffer(), 0, begin44.sizeof());
- DirectBuffer kafkaFetchBegin2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaFetchBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.fetch()
.topic("topic")
@@ -2437,7 +2509,7 @@ public void generateStreamsBuffer() throws Exception
.deltaType("JSON_PATCH")
.build()
.build());
- BeginFW begin43 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin45 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003cL) // REP
@@ -2447,9 +2519,9 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000063L)
.traceId(0x000000000000003dL)
.affinity(0x0000000000000000L)
- .extension(kafkaFetchBegin2, 0, kafkaFetchBegin2.capacity())
+ .extension(kafkaFetchBeginEx2, 0, kafkaFetchBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin43.buffer(), 0, begin43.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin45.buffer(), 0, begin45.sizeof());
DirectBuffer kafkaFetchDataPayload = new String8FW("kafka fetch payload").value();
DirectBuffer kafkaFetchDataEx1 = new UnsafeBuffer(KafkaFunctions.dataEx()
@@ -2493,7 +2565,7 @@ public void generateStreamsBuffer() throws Exception
.build()
.build()
.build());
- FlushFW flush10 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush11 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003dL) // INI
@@ -2506,19 +2578,18 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaFetchFlushEx, 0, kafkaFetchFlushEx.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush10.buffer(), 0, flush10.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush11.buffer(), 0, flush11.sizeof());
// - PRODUCE
- DirectBuffer kafkaProduceBegin1 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaProduceBeginEx1 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.produce()
.transaction("transaction")
- .producerId(0x770042)
.topic("topic")
.partition(2, 42_000, 77_000)
.build()
.build());
- BeginFW begin44 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin46 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003fL) // INI
@@ -2528,20 +2599,19 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000066L)
.traceId(0x000000000000003fL)
.affinity(0x0000000000000000L)
- .extension(kafkaProduceBegin1, 0, kafkaProduceBegin1.capacity())
+ .extension(kafkaProduceBeginEx1, 0, kafkaProduceBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin44.buffer(), 0, begin44.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin46.buffer(), 0, begin46.sizeof());
- DirectBuffer kafkaProduceBegin2 = new UnsafeBuffer(KafkaFunctions.beginEx()
+ DirectBuffer kafkaProduceBeginEx2 = new UnsafeBuffer(KafkaFunctions.beginEx()
.typeId(KAFKA_TYPE_ID)
.produce()
.transaction("transaction")
- .producerId(0x210088)
.topic("topic")
.partition(1, 21_000)
.build()
.build());
- BeginFW begin45 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin47 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003eL) // REP
@@ -2551,9 +2621,9 @@ public void generateStreamsBuffer() throws Exception
.timestamp(0x0000000000000067L)
.traceId(0x000000000000003fL)
.affinity(0x0000000000000000L)
- .extension(kafkaProduceBegin2, 0, kafkaProduceBegin2.capacity())
+ .extension(kafkaProduceBeginEx2, 0, kafkaProduceBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin45.buffer(), 0, begin45.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin47.buffer(), 0, begin47.sizeof());
DirectBuffer kafkaProduceDataPayload = new String8FW("kafka produce payload").value();
DirectBuffer kafkaProduceDataEx1 = new UnsafeBuffer(KafkaFunctions.dataEx()
@@ -2561,6 +2631,8 @@ public void generateStreamsBuffer() throws Exception
.produce()
.deferred(999)
.timestamp(0x68)
+ .producerId(0x77L)
+ .producerEpoch((short) 0x42)
.sequence(777)
.ackMode("LEADER_ONLY")
.key("key")
@@ -2591,7 +2663,7 @@ public void generateStreamsBuffer() throws Exception
.key("key")
.build()
.build());
- FlushFW flush11 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush12 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x000000090000000fL) // north_kafka_cache_client
.routedId(0x0000000900000010L) // south_kafka_cache_server
.streamId(0x000000000000003fL) // INI
@@ -2604,7 +2676,7 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(kafkaProduceFlushEx, 0, kafkaProduceFlushEx.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush11.buffer(), 0, flush11.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush12.buffer(), 0, flush12.sizeof());
// amqp extension
DirectBuffer amqpBeginEx1 = new UnsafeBuffer(AmqpFunctions.beginEx()
@@ -2614,7 +2686,7 @@ public void generateStreamsBuffer() throws Exception
.senderSettleMode("SETTLED")
.receiverSettleMode("FIRST")
.build());
- BeginFW begin46 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin48 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x0000000900000025L) // north_amqp_server
.routedId(0x0000000900000026L) // north_fan_server
.streamId(0x0000000000000041L) // INI
@@ -2626,7 +2698,7 @@ public void generateStreamsBuffer() throws Exception
.affinity(0x0000000000000000L)
.extension(amqpBeginEx1, 0, amqpBeginEx1.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin46.buffer(), 0, begin46.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin48.buffer(), 0, begin48.sizeof());
DirectBuffer amqpBeginEx2 = new UnsafeBuffer(AmqpFunctions.beginEx()
.typeId(AMQP_TYPE_ID)
@@ -2635,7 +2707,7 @@ public void generateStreamsBuffer() throws Exception
.senderSettleMode("MIXED")
.receiverSettleMode("SECOND")
.build());
- BeginFW begin47 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ BeginFW begin49 = beginRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x0000000900000025L) // north_amqp_server
.routedId(0x0000000900000026L) // north_fan_server
.streamId(0x0000000000000040L) // REP
@@ -2647,7 +2719,7 @@ public void generateStreamsBuffer() throws Exception
.affinity(0x0000000000000000L)
.extension(amqpBeginEx2, 0, amqpBeginEx2.capacity())
.build();
- streams[0].write(BeginFW.TYPE_ID, begin47.buffer(), 0, begin47.sizeof());
+ streams[0].write(BeginFW.TYPE_ID, begin49.buffer(), 0, begin49.sizeof());
DirectBuffer amqpPayload = new String8FW("amqp payload").value();
DirectBuffer amqpDataEx1 = new UnsafeBuffer(AmqpFunctions.dataEx()
@@ -2770,7 +2842,7 @@ public void generateStreamsBuffer() throws Exception
AMQP_TYPE_ID, 0, 0, 0, // int32 typeId
3 // uint8 AmqpCapabilities
});
- FlushFW flush12 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
+ FlushFW flush13 = flushRW.wrap(frameBuffer, 0, frameBuffer.capacity())
.originId(0x0000000900000025L) // north_amqp_server
.routedId(0x0000000900000026L) // north_fan_server
.streamId(0x0000000000000041L) // INI
@@ -2783,7 +2855,7 @@ public void generateStreamsBuffer() throws Exception
.reserved(0x00000000)
.extension(amqpFlushEx, 0, amqpFlushEx.capacity())
.build();
- streams[0].write(FlushFW.TYPE_ID, flush12.buffer(), 0, flush12.sizeof());
+ streams[0].write(FlushFW.TYPE_ID, flush13.buffer(), 0, flush13.sizeof());
DirectBuffer amqpAbortEx = new UnsafeBuffer(AmqpFunctions.abortEx()
.typeId(AMQP_TYPE_ID)
diff --git a/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/engine/data0 b/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/engine/data0
index ca669c8230..eeef5860f3 100644
Binary files a/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/engine/data0 and b/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/engine/data0 differ
diff --git a/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.pcap b/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.pcap
index eef6dcff71..7d791d8a02 100644
Binary files a/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.pcap and b/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.pcap differ
diff --git a/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.txt b/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.txt
index e2f3ab7c5a..0fb4a556a5 100644
--- a/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.txt
+++ b/incubator/command-dump/src/test/resources/io/aklivity/zilla/runtime/command/dump/internal/airline/expected_dump.txt
@@ -2665,10 +2665,10 @@ Zilla Frame
.... ...1 = RETAIN: Set (1)
QoS: EXACTLY_ONCE (2)
-Frame 61: 381 bytes on wire (3048 bits), 381 bytes captured (3048 bits)
+Frame 61: 383 bytes on wire (3064 bits), 383 bytes captured (3064 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::20, Dst: fe80::21
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 192, Ack: 193, Len: 307
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 192, Ack: 193, Len: 309
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
@@ -2712,6 +2712,7 @@ Zilla Frame
QoS: AT_LEAST_ONCE (1)
Flags: 0x00
.... ...0 = RETAIN: Not set (0)
+ Packet ID: 0x0000
Expiry Interval: 42
Content Type: Content Type
Length: 12
@@ -2748,17 +2749,17 @@ Zilla Frame
Length: 7
Value: value77
-Frame 62: 349 bytes on wire (2792 bits), 349 bytes captured (2792 bits)
+Frame 62: 351 bytes on wire (2808 bits), 351 bytes captured (2808 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::21, Dst: fe80::20
-Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 193, Ack: 499, Len: 275
+Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 193, Ack: 501, Len: 277
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00001c80
+ Offset: 0x00001c88
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -2795,6 +2796,7 @@ Zilla Frame
QoS: EXACTLY_ONCE (2)
Flags: 0x01
.... ...1 = RETAIN: Set (1)
+ Packet ID: 0x0042
Expiry Interval: 77
Content Type: Content Type
Length: 12
@@ -2827,7 +2829,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00001d40
+ Offset: 0x00001d50
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -2915,7 +2917,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00001df8
+ Offset: 0x00001e08
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3003,7 +3005,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00001eb0
+ Offset: 0x00001ec0
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3101,7 +3103,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00001fa0
+ Offset: 0x00001fb0
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3187,7 +3189,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002088
+ Offset: 0x00002098
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3239,7 +3241,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002108
+ Offset: 0x00002118
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3291,7 +3293,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002188
+ Offset: 0x00002198
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3319,17 +3321,17 @@ Zilla Frame
Length: 6
Value: Reason
-Frame 70: 269 bytes on wire (2152 bits), 269 bytes captured (2152 bits)
+Frame 70: 272 bytes on wire (2176 bits), 272 bytes captured (2176 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::24, Dst: fe80::25
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 195
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 198
Zilla Frame
Frame Type ID: 0x00000001
Frame Type: BEGIN
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000021f8
+ Offset: 0x00002208
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3355,7 +3357,8 @@ Zilla Frame
.... ..1. = CLEAN_START: Set (1)
.... .0.. = WILL: Not set (0)
Expiry: 42
- QoS Maximum: 2
+ Subscribe QoS Maximum: 2
+ Publish QoS Maximum: 1
Packet Size Maximum: 42000
Capabilities: 0x01
.... ...1 = RETAIN: Set (1)
@@ -3366,17 +3369,17 @@ Zilla Frame
Length: 9
Client ID: client-id
-Frame 71: 269 bytes on wire (2152 bits), 269 bytes captured (2152 bits)
+Frame 71: 272 bytes on wire (2176 bits), 272 bytes captured (2176 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::25, Dst: fe80::24
-Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 195, Len: 195
+Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 198, Len: 198
Zilla Frame
Frame Type ID: 0x00000001
Frame Type: BEGIN
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002268
+ Offset: 0x00002280
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3402,7 +3405,8 @@ Zilla Frame
.... ..1. = CLEAN_START: Set (1)
.... .1.. = WILL: Set (1)
Expiry: 42
- QoS Maximum: 2
+ Subscribe QoS Maximum: 1
+ Publish QoS Maximum: 2
Packet Size Maximum: 42000
Capabilities: 0x0f
.... ...1 = RETAIN: Set (1)
@@ -3416,14 +3420,14 @@ Zilla Frame
Frame 72: 280 bytes on wire (2240 bits), 280 bytes captured (2240 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::24, Dst: fe80::25
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 195, Ack: 196, Len: 206
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 198, Ack: 199, Len: 206
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000022d8
+ Offset: 0x000022f8
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3462,14 +3466,14 @@ Zilla Frame
Frame 73: 280 bytes on wire (2240 bits), 280 bytes captured (2240 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::25, Dst: fe80::24
-Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 196, Ack: 401, Len: 206
+Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 199, Ack: 404, Len: 206
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002358
+ Offset: 0x00002378
Origin ID: 0x0000000900000022
Origin Namespace: example
Origin Binding: north_mqtt_server
@@ -3505,7 +3509,42 @@ Zilla Frame
Deferred: 88
Data Kind: WILL (0x01)
-Frame 74: 317 bytes on wire (2536 bits), 317 bytes captured (2536 bits)
+Frame 74: 252 bytes on wire (2016 bits), 252 bytes captured (2016 bits)
+Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
+Internet Protocol Version 6, Src: fe80::24, Dst: fe80::25
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 404, Ack: 405, Len: 178
+Zilla Frame
+ Frame Type ID: 0x00000005
+ Frame Type: FLUSH
+ Protocol Type ID: 0x00000000
+ Protocol Type:
+ Worker: 0
+ Offset: 0x000023f8
+ Origin ID: 0x0000000900000022
+ Origin Namespace: example
+ Origin Binding: north_mqtt_server
+ Routed ID: 0x0000000900000023
+ Routed Namespace: example
+ Routed Binding: north_mqtt_kafka_mapping
+ Stream ID: 0x0000000000000025
+ Initial ID: 0x0000000000000025
+ Reply ID: 0x0000000000000024
+ Direction: INI
+ Sequence: 401
+ Acknowledge: 402
+ Maximum: 7777
+ Timestamp: 0x0000000000000143
+ Trace ID: 0x0000000000000025
+ Authorization: 0x0000000000000000
+ Budget ID: 0x0000000000000000
+ Reserved: 0
+ Extension: mqtt
+ Stream Type ID: 0x761ad4d0
+ Stream Type: mqtt
+ Kind: SESSION (2)
+ Packet ID: 0x2142
+
+Frame 75: 317 bytes on wire (2536 bits), 317 bytes captured (2536 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::26, Dst: fe80::27
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 243
@@ -3515,7 +3554,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000023d8
+ Offset: 0x00002458
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3559,7 +3598,7 @@ Zilla Frame
Partition ID: 77
Partition ID: 88
-Frame 75: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits)
+Frame 76: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::27, Dst: fe80::26
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 243, Len: 227
@@ -3569,7 +3608,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002478
+ Offset: 0x000024f8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3609,7 +3648,7 @@ Zilla Frame
Length: 4
Size: 0
-Frame 76: 379 bytes on wire (3032 bits), 379 bytes captured (3032 bits)
+Frame 77: 379 bytes on wire (3032 bits), 379 bytes captured (3032 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::26, Dst: fe80::27
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 243, Ack: 228, Len: 305
@@ -3619,7 +3658,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002508
+ Offset: 0x00002588
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3680,7 +3719,7 @@ Zilla Frame
Partition ID: 201
Partition ID: 202
-Frame 77: 307 bytes on wire (2456 bits), 307 bytes captured (2456 bits)
+Frame 78: 307 bytes on wire (2456 bits), 307 bytes captured (2456 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::26, Dst: fe80::27
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 548, Ack: 228, Len: 233
@@ -3690,7 +3729,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000025e0
+ Offset: 0x00002660
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3724,7 +3763,7 @@ Zilla Frame
Leader Epoch: 42
Correlation ID: 77
-Frame 78: 261 bytes on wire (2088 bits), 261 bytes captured (2088 bits)
+Frame 79: 261 bytes on wire (2088 bits), 261 bytes captured (2088 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::26, Dst: fe80::27
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 781, Ack: 228, Len: 187
@@ -3734,7 +3773,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002670
+ Offset: 0x000026f0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3759,7 +3798,7 @@ Zilla Frame
Length: 11
Consumer ID: consumer-id
-Frame 79: 306 bytes on wire (2448 bits), 306 bytes captured (2448 bits)
+Frame 80: 306 bytes on wire (2448 bits), 306 bytes captured (2448 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::28, Dst: fe80::29
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 232
@@ -3769,7 +3808,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000026d8
+ Offset: 0x00002758
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3810,7 +3849,7 @@ Zilla Frame
Length: 5
Metadata: 1122334455
-Frame 80: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits)
+Frame 81: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::29, Dst: fe80::28
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 232, Len: 227
@@ -3820,7 +3859,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002768
+ Offset: 0x000027e8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3860,7 +3899,7 @@ Zilla Frame
Length (varint32): 01
Length: 0
-Frame 81: 291 bytes on wire (2328 bits), 291 bytes captured (2328 bits)
+Frame 82: 291 bytes on wire (2328 bits), 291 bytes captured (2328 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::28, Dst: fe80::29
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 232, Ack: 228, Len: 217
@@ -3870,7 +3909,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000027f8
+ Offset: 0x00002878
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3904,7 +3943,7 @@ Zilla Frame
Length: 4
Size: 0
-Frame 82: 343 bytes on wire (2744 bits), 343 bytes captured (2744 bits)
+Frame 83: 343 bytes on wire (2744 bits), 343 bytes captured (2744 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::29, Dst: fe80::28
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 228, Ack: 449, Len: 269
@@ -3914,7 +3953,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002878
+ Offset: 0x000028f8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -3970,7 +4009,7 @@ Zilla Frame
Length (varint32): 01
Length: 0
-Frame 83: 287 bytes on wire (2296 bits), 287 bytes captured (2296 bits)
+Frame 84: 287 bytes on wire (2296 bits), 287 bytes captured (2296 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::30, Dst: fe80::31
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 213
@@ -3980,7 +4019,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002930
+ Offset: 0x000029b0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4013,7 +4052,7 @@ Zilla Frame
Consumer ID: consumer-id
Timeout: 0
-Frame 84: 287 bytes on wire (2296 bits), 287 bytes captured (2296 bits)
+Frame 85: 287 bytes on wire (2296 bits), 287 bytes captured (2296 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::31, Dst: fe80::30
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 213, Len: 213
@@ -4023,7 +4062,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000029b0
+ Offset: 0x00002a30
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4056,7 +4095,7 @@ Zilla Frame
Consumer ID: consumer-id
Timeout: 999999
-Frame 85: 658 bytes on wire (5264 bits), 658 bytes captured (5264 bits)
+Frame 86: 658 bytes on wire (5264 bits), 658 bytes captured (5264 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::32, Dst: fe80::33
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 584
@@ -4066,7 +4105,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002a30
+ Offset: 0x00002ab0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4309,7 +4348,7 @@ Zilla Frame
Ack Mode ID: 0
Ack Mode: NONE
-Frame 86: 407 bytes on wire (3256 bits), 407 bytes captured (3256 bits)
+Frame 87: 407 bytes on wire (3256 bits), 407 bytes captured (3256 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::33, Dst: fe80::32
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 584, Len: 333
@@ -4319,7 +4358,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002c20
+ Offset: 0x00002ca0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4388,7 +4427,7 @@ Zilla Frame
Ack Mode ID: 1
Ack Mode: LEADER_ONLY
-Frame 87: 339 bytes on wire (2712 bits), 339 bytes captured (2712 bits)
+Frame 88: 339 bytes on wire (2712 bits), 339 bytes captured (2712 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::33, Dst: fe80::32
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 334, Ack: 584, Len: 265
@@ -4398,7 +4437,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002d18
+ Offset: 0x00002d98
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4451,7 +4490,7 @@ Zilla Frame
Ack Mode ID: -1
Ack Mode: IN_SYNC_REPLICAS
-Frame 88: 459 bytes on wire (3672 bits), 459 bytes captured (3672 bits)
+Frame 89: 459 bytes on wire (3672 bits), 459 bytes captured (3672 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::32, Dst: fe80::33
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 584, Ack: 599, Len: 385
@@ -4461,7 +4500,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002dc8
+ Offset: 0x00002e48
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4555,17 +4594,17 @@ Zilla Frame
Length: 6
Value: value2
-Frame 89: 385 bytes on wire (3080 bits), 385 bytes captured (3080 bits)
+Frame 90: 395 bytes on wire (3160 bits), 395 bytes captured (3160 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::32, Dst: fe80::33
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 969, Ack: 599, Len: 311
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 969, Ack: 599, Len: 321
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002ef0
+ Offset: 0x00002f70
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4601,6 +4640,8 @@ Zilla Frame
Merged API: PRODUCE (0)
Deferred: 100
Timestamp: 0x0000000000000053
+ Producer ID: 0x0000000000000077
+ Producer Epoch: 0x0042
Partition: 1 [77000]
Partition ID: 1
Partition Offset: 77000
@@ -4641,17 +4682,17 @@ Zilla Frame
Length: 6
Value: value2
-Frame 90: 304 bytes on wire (2432 bits), 304 bytes captured (2432 bits)
+Frame 91: 304 bytes on wire (2432 bits), 304 bytes captured (2432 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::32, Dst: fe80::33
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 1280, Ack: 599, Len: 230
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 1290, Ack: 599, Len: 230
Zilla Frame
Frame Type ID: 0x00000005
Frame Type: FLUSH
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00002fd0
+ Offset: 0x00003058
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4685,17 +4726,17 @@ Zilla Frame
Metadata: metadata
Correlation ID: 77
-Frame 91: 420 bytes on wire (3360 bits), 420 bytes captured (3360 bits)
+Frame 92: 420 bytes on wire (3360 bits), 420 bytes captured (3360 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::32, Dst: fe80::33
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 1510, Ack: 599, Len: 346
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 1520, Ack: 599, Len: 346
Zilla Frame
Frame Type ID: 0x00000005
Frame Type: FLUSH
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003060
+ Offset: 0x000030e8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4774,7 +4815,77 @@ Zilla Frame
Length: 3
Key: key
-Frame 92: 260 bytes on wire (2080 bits), 260 bytes captured (2080 bits)
+Frame 93: 263 bytes on wire (2104 bits), 263 bytes captured (2104 bits)
+Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
+Internet Protocol Version 6, Src: fe80::132, Dst: fe80::133
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 189
+Zilla Frame
+ Frame Type ID: 0x00000001
+ Frame Type: BEGIN
+ Protocol Type ID: 0x00000000
+ Protocol Type:
+ Worker: 0
+ Offset: 0x000031e8
+ Origin ID: 0x000000090000000f
+ Origin Namespace: example
+ Origin Binding: north_kafka_cache_client
+ Routed ID: 0x0000000900000010
+ Routed Namespace: example
+ Routed Binding: south_kafka_cache_server
+ Stream ID: 0x0000000000000133
+ Initial ID: 0x0000000000000133
+ Reply ID: 0x0000000000000132
+ Direction: INI
+ Sequence: 0
+ Acknowledge: 0
+ Maximum: 0
+ Timestamp: 0x0000000000000056
+ Trace ID: 0x0000000000000035
+ Authorization: 0x0000000000000000
+ Affinity: 0x0000000000000000
+ Extension: kafka
+ Stream Type ID: 0xe1204b08
+ Stream Type: kafka
+ API: INIT_PRODUCER_ID (22)
+ Producer ID: 0x0000000000000077
+ Producer Epoch: 0x0042
+
+Frame 94: 263 bytes on wire (2104 bits), 263 bytes captured (2104 bits)
+Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
+Internet Protocol Version 6, Src: fe80::133, Dst: fe80::132
+Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 189, Len: 189
+Zilla Frame
+ Frame Type ID: 0x00000001
+ Frame Type: BEGIN
+ Protocol Type ID: 0x00000000
+ Protocol Type:
+ Worker: 0
+ Offset: 0x00003250
+ Origin ID: 0x000000090000000f
+ Origin Namespace: example
+ Origin Binding: north_kafka_cache_client
+ Routed ID: 0x0000000900000010
+ Routed Namespace: example
+ Routed Binding: south_kafka_cache_server
+ Stream ID: 0x0000000000000132
+ Initial ID: 0x0000000000000133
+ Reply ID: 0x0000000000000132
+ Direction: REP
+ Sequence: 0
+ Acknowledge: 0
+ Maximum: 0
+ Timestamp: 0x0000000000000057
+ Trace ID: 0x0000000000000035
+ Authorization: 0x0000000000000000
+ Affinity: 0x0000000000000000
+ Extension: kafka
+ Stream Type ID: 0xe1204b08
+ Stream Type: kafka
+ API: INIT_PRODUCER_ID (22)
+ Producer ID: 0x0000000000000088
+ Producer Epoch: 0x0021
+
+Frame 95: 260 bytes on wire (2080 bits), 260 bytes captured (2080 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::34, Dst: fe80::35
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 186
@@ -4784,7 +4895,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003160
+ Offset: 0x000032b8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4810,7 +4921,7 @@ Zilla Frame
Length: 5
Topic: topic
-Frame 93: 260 bytes on wire (2080 bits), 260 bytes captured (2080 bits)
+Frame 96: 260 bytes on wire (2080 bits), 260 bytes captured (2080 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::35, Dst: fe80::34
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 186, Len: 186
@@ -4820,7 +4931,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000031c0
+ Offset: 0x00003318
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4846,7 +4957,7 @@ Zilla Frame
Length: 5
Topic: topic
-Frame 94: 317 bytes on wire (2536 bits), 317 bytes captured (2536 bits)
+Frame 97: 317 bytes on wire (2536 bits), 317 bytes captured (2536 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::34, Dst: fe80::35
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 186, Ack: 187, Len: 243
@@ -4856,7 +4967,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003220
+ Offset: 0x00003378
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4902,17 +5013,17 @@ Zilla Frame
Partition ID: 100
Leader ID: 4200
-Frame 95: 285 bytes on wire (2280 bits), 285 bytes captured (2280 bits)
+Frame 98: 288 bytes on wire (2304 bits), 288 bytes captured (2304 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::36, Dst: fe80::37
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 211
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 214
Zilla Frame
Frame Type ID: 0x00000001
Frame Type: BEGIN
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000032c0
+ Offset: 0x00003418
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4934,9 +5045,6 @@ Zilla Frame
Stream Type ID: 0xe1204b08
Stream Type: kafka
API: OFFSET_COMMIT (8)
- Topic: topic
- Length: 5
- Topic: topic
Group ID: group
Length: 5
Group ID: group
@@ -4946,18 +5054,22 @@ Zilla Frame
Instance ID: instance
Length: 8
Instance ID: instance
+ Host: host
+ Length: 4
+ Host: host
+ Port: 4242
-Frame 96: 285 bytes on wire (2280 bits), 285 bytes captured (2280 bits)
+Frame 99: 288 bytes on wire (2304 bits), 288 bytes captured (2304 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::37, Dst: fe80::36
-Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 211, Len: 211
+Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 214, Len: 214
Zilla Frame
Frame Type ID: 0x00000001
Frame Type: BEGIN
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003340
+ Offset: 0x00003498
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -4979,9 +5091,6 @@ Zilla Frame
Stream Type ID: 0xe1204b08
Stream Type: kafka
API: OFFSET_COMMIT (8)
- Topic: topic
- Length: 5
- Topic: topic
Group ID: group
Length: 5
Group ID: group
@@ -4991,18 +5100,22 @@ Zilla Frame
Instance ID: instance
Length: 8
Instance ID: instance
+ Host: host
+ Length: 4
+ Host: host
+ Port: 4242
-Frame 97: 340 bytes on wire (2720 bits), 340 bytes captured (2720 bits)
+Frame 100: 346 bytes on wire (2768 bits), 346 bytes captured (2768 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::36, Dst: fe80::37
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 211, Ack: 212, Len: 266
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 214, Ack: 215, Len: 272
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000033c0
+ Offset: 0x00003518
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5035,6 +5148,9 @@ Zilla Frame
Stream Type ID: 0xe1204b08
Stream Type: kafka
API: OFFSET_COMMIT (8)
+ Topic: test
+ Length: 4
+ Topic: test
Progress: 21 [1234]
Partition ID: 21
Partition Offset: 1234
@@ -5046,7 +5162,7 @@ Zilla Frame
Generation ID: 42
Leader Epoch: 77
-Frame 98: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits)
+Frame 101: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::38, Dst: fe80::39
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 227
@@ -5056,7 +5172,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003470
+ Offset: 0x000035d0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5096,7 +5212,7 @@ Zilla Frame
Partition ID: 77
Partition ID: 88
-Frame 99: 289 bytes on wire (2312 bits), 289 bytes captured (2312 bits)
+Frame 102: 289 bytes on wire (2312 bits), 289 bytes captured (2312 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::39, Dst: fe80::38
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 227, Len: 215
@@ -5106,7 +5222,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003500
+ Offset: 0x00003660
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5143,7 +5259,7 @@ Zilla Frame
Size: 1
Partition ID: 42
-Frame 100: 382 bytes on wire (3056 bits), 382 bytes captured (3056 bits)
+Frame 103: 382 bytes on wire (3056 bits), 382 bytes captured (3056 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::38, Dst: fe80::39
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 227, Ack: 216, Len: 308
@@ -5153,7 +5269,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003580
+ Offset: 0x000036e0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5211,7 +5327,7 @@ Zilla Frame
Length: 9
Metadata: metadata3
-Frame 101: 295 bytes on wire (2360 bits), 295 bytes captured (2360 bits)
+Frame 104: 295 bytes on wire (2360 bits), 295 bytes captured (2360 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3a, Dst: fe80::3b
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 221
@@ -5221,7 +5337,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003660
+ Offset: 0x000037c0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5259,7 +5375,7 @@ Zilla Frame
Length: 7
Config: config3
-Frame 102: 268 bytes on wire (2144 bits), 268 bytes captured (2144 bits)
+Frame 105: 268 bytes on wire (2144 bits), 268 bytes captured (2144 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3b, Dst: fe80::3a
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 221, Len: 194
@@ -5269,7 +5385,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000036e8
+ Offset: 0x00003848
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5298,7 +5414,7 @@ Zilla Frame
Length: 4
Size: 0
-Frame 103: 337 bytes on wire (2696 bits), 337 bytes captured (2696 bits)
+Frame 106: 337 bytes on wire (2696 bits), 337 bytes captured (2696 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3a, Dst: fe80::3b
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 221, Ack: 195, Len: 263
@@ -5308,7 +5424,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003750
+ Offset: 0x000038b0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5366,7 +5482,7 @@ Zilla Frame
Length: 6
Value: value3
-Frame 104: 363 bytes on wire (2904 bits), 363 bytes captured (2904 bits)
+Frame 107: 363 bytes on wire (2904 bits), 363 bytes captured (2904 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3c, Dst: fe80::3d
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 289
@@ -5376,7 +5492,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003800
+ Offset: 0x00003960
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5462,7 +5578,7 @@ Zilla Frame
Isolation: READ_UNCOMMITTED (0)
Delta Type: NONE (0)
-Frame 105: 315 bytes on wire (2520 bits), 315 bytes captured (2520 bits)
+Frame 108: 315 bytes on wire (2520 bits), 315 bytes captured (2520 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3d, Dst: fe80::3c
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 289, Len: 241
@@ -5472,7 +5588,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000038c8
+ Offset: 0x00003a28
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5522,7 +5638,7 @@ Zilla Frame
Isolation: READ_COMMITTED (1)
Delta Type: JSON_PATCH (1)
-Frame 106: 390 bytes on wire (3120 bits), 390 bytes captured (3120 bits)
+Frame 109: 390 bytes on wire (3120 bits), 390 bytes captured (3120 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3c, Dst: fe80::3d
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 289, Ack: 242, Len: 316
@@ -5532,7 +5648,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003960
+ Offset: 0x00003ac0
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5608,7 +5724,7 @@ Zilla Frame
Length: 6
Value: value2
-Frame 107: 336 bytes on wire (2688 bits), 336 bytes captured (2688 bits)
+Frame 110: 336 bytes on wire (2688 bits), 336 bytes captured (2688 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3c, Dst: fe80::3d
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 605, Ack: 242, Len: 262
@@ -5618,7 +5734,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003a48
+ Offset: 0x00003ba8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5673,17 +5789,17 @@ Zilla Frame
Key: key1
Evaluation: LAZY (0)
-Frame 108: 310 bytes on wire (2480 bits), 310 bytes captured (2480 bits)
+Frame 111: 302 bytes on wire (2416 bits), 302 bytes captured (2416 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3e, Dst: fe80::3f
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 236
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 228
Zilla Frame
Frame Type ID: 0x00000001
Frame Type: BEGIN
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003af8
+ Offset: 0x00003c58
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5708,7 +5824,6 @@ Zilla Frame
Transaction: transaction
Length: 11
Transaction: transaction
- Producer ID: 0x0000000000770042
Topic: topic
Length: 5
Topic: topic
@@ -5721,17 +5836,17 @@ Zilla Frame
Length: -1
Metadata:
-Frame 109: 310 bytes on wire (2480 bits), 310 bytes captured (2480 bits)
+Frame 112: 302 bytes on wire (2416 bits), 302 bytes captured (2416 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3f, Dst: fe80::3e
-Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 236, Len: 236
+Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 228, Len: 228
Zilla Frame
Frame Type ID: 0x00000001
Frame Type: BEGIN
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003b90
+ Offset: 0x00003ce8
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5756,7 +5871,6 @@ Zilla Frame
Transaction: transaction
Length: 11
Transaction: transaction
- Producer ID: 0x0000000000210088
Topic: topic
Length: 5
Topic: topic
@@ -5769,17 +5883,17 @@ Zilla Frame
Length: -1
Metadata:
-Frame 110: 343 bytes on wire (2744 bits), 343 bytes captured (2744 bits)
+Frame 113: 353 bytes on wire (2824 bits), 353 bytes captured (2824 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3e, Dst: fe80::3f
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 236, Ack: 237, Len: 269
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 228, Ack: 229, Len: 279
Zilla Frame
Frame Type ID: 0x00000002
Frame Type: DATA
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003c28
+ Offset: 0x00003d78
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5814,6 +5928,8 @@ Zilla Frame
API: PRODUCE (0)
Deferred: 999
Timestamp: 0x0000000000000068
+ Producer ID: 0x0000000000000077
+ Producer Epoch: 0x0042
Sequence: 777
CRC32C: 0x00000000
Ack Mode ID: 1
@@ -5845,17 +5961,17 @@ Zilla Frame
Length: 6
Value: value2
-Frame 111: 295 bytes on wire (2360 bits), 295 bytes captured (2360 bits)
+Frame 114: 295 bytes on wire (2360 bits), 295 bytes captured (2360 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::3e, Dst: fe80::3f
-Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 505, Ack: 237, Len: 221
+Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 507, Ack: 229, Len: 221
Zilla Frame
Frame Type ID: 0x00000005
Frame Type: FLUSH
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003ce0
+ Offset: 0x00003e38
Origin ID: 0x000000090000000f
Origin Namespace: example
Origin Binding: north_kafka_cache_client
@@ -5893,7 +6009,7 @@ Zilla Frame
Key: key
Error: 0
-Frame 112: 248 bytes on wire (1984 bits), 248 bytes captured (1984 bits)
+Frame 115: 248 bytes on wire (1984 bits), 248 bytes captured (1984 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::40, Dst: fe80::41
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 0, Ack: 1, Len: 174
@@ -5903,7 +6019,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003d68
+ Offset: 0x00003ec0
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
@@ -5931,7 +6047,7 @@ Zilla Frame
Sender Settle Mode: SETTLED (1)
Receiver Settle Mode: FIRST (0)
-Frame 113: 248 bytes on wire (1984 bits), 248 bytes captured (1984 bits)
+Frame 116: 248 bytes on wire (1984 bits), 248 bytes captured (1984 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::41, Dst: fe80::40
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 1, Ack: 174, Len: 174
@@ -5941,7 +6057,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003dd0
+ Offset: 0x00003f28
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
@@ -5969,7 +6085,7 @@ Zilla Frame
Sender Settle Mode: MIXED (2)
Receiver Settle Mode: SECOND (1)
-Frame 114: 433 bytes on wire (3464 bits), 433 bytes captured (3464 bits)
+Frame 117: 433 bytes on wire (3464 bits), 433 bytes captured (3464 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::40, Dst: fe80::41
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 174, Ack: 175, Len: 359
@@ -5979,7 +6095,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003e38
+ Offset: 0x00003f90
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
@@ -6074,7 +6190,7 @@ Zilla Frame
Body Kind: VALUE (9)
Deferred: 9999
-Frame 115: 526 bytes on wire (4208 bits), 526 bytes captured (4208 bits)
+Frame 118: 526 bytes on wire (4208 bits), 526 bytes captured (4208 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::41, Dst: fe80::40
Transmission Control Protocol, Src Port: 7114, Dst Port: 0, Seq: 175, Ack: 533, Len: 452
@@ -6084,7 +6200,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00003f58
+ Offset: 0x000040b0
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
@@ -6199,7 +6315,7 @@ Zilla Frame
Body Kind: VALUE_STRING32 (2)
Deferred: 3333
-Frame 116: 498 bytes on wire (3984 bits), 498 bytes captured (3984 bits)
+Frame 119: 498 bytes on wire (3984 bits), 498 bytes captured (3984 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::40, Dst: fe80::41
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 533, Ack: 627, Len: 424
@@ -6209,7 +6325,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x000040d8
+ Offset: 0x00004230
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
@@ -6316,7 +6432,7 @@ Zilla Frame
Body Kind: VALUE_STRING32 (2)
Deferred: 4444
-Frame 117: 242 bytes on wire (1936 bits), 242 bytes captured (1936 bits)
+Frame 120: 242 bytes on wire (1936 bits), 242 bytes captured (1936 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::40, Dst: fe80::41
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 957, Ack: 627, Len: 168
@@ -6326,7 +6442,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00004238
+ Offset: 0x00004390
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
@@ -6350,7 +6466,7 @@ Zilla Frame
Stream Type: amqp
Capabilities: SEND_AND_RECEIVE (3)
-Frame 118: 239 bytes on wire (1912 bits), 239 bytes captured (1912 bits)
+Frame 121: 239 bytes on wire (1912 bits), 239 bytes captured (1912 bits)
Ethernet II, Src: Send_00 (20:53:45:4e:44:00), Dst: Receive_00 (20:52:45:43:56:00)
Internet Protocol Version 6, Src: fe80::40, Dst: fe80::41
Transmission Control Protocol, Src Port: 0, Dst Port: 7114, Seq: 1125, Ack: 627, Len: 165
@@ -6360,7 +6476,7 @@ Zilla Frame
Protocol Type ID: 0x00000000
Protocol Type:
Worker: 0
- Offset: 0x00004298
+ Offset: 0x000043f0
Origin ID: 0x0000000900000025
Origin Namespace: example
Origin Binding: north_amqp_server
diff --git a/incubator/command-generate/pom.xml b/incubator/command-generate/pom.xml
index 18e2c21d1d..d956af5203 100644
--- a/incubator/command-generate/pom.xml
+++ b/incubator/command-generate/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
@@ -87,19 +87,25 @@
io.aklivity.zilla
- validator-avro
+ model-avro
${project.version}
provided
io.aklivity.zilla
- validator-core
+ model-core
${project.version}
provided
io.aklivity.zilla
- validator-json
+ model-json
+ ${project.version}
+ provided
+
+
+ io.aklivity.zilla
+ model-protobuf
${project.version}
provided
diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java
index ea664debf1..caf0718114 100644
--- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java
+++ b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java
@@ -28,9 +28,9 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfig;
-import io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
public abstract class ConfigGenerator
{
@@ -40,9 +40,9 @@ public abstract class ConfigGenerator
protected static final String VERSION_LATEST = "latest";
protected static final Pattern JSON_CONTENT_TYPE = Pattern.compile("^application/(?:.+\\+)?json$");
- protected final Map validators = Map.of(
- "string", StringValidatorConfig.builder().build(),
- "integer", IntegerValidatorConfig.builder().build()
+ protected final Map models = Map.of(
+ "string", StringModelConfig.builder().build(),
+ "integer", IntegerModelConfig.builder().build()
);
protected final Matcher jsonContentType = JSON_CONTENT_TYPE.matcher("");
diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java
index 381452608f..cba4f9c148 100644
--- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java
+++ b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java
@@ -55,11 +55,11 @@
import io.aklivity.zilla.runtime.engine.config.EngineConfig;
import io.aklivity.zilla.runtime.engine.config.EngineConfigWriter;
import io.aklivity.zilla.runtime.engine.config.GuardedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
import io.aklivity.zilla.runtime.guard.jwt.config.JwtOptionsConfig;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig;
public class AsyncApiHttpProxyConfigGenerator extends AsyncApiConfigGenerator
@@ -357,7 +357,7 @@ private HttpRequestConfigBuilder injectContent(
if (hasJsonContentType())
{
request.
- content(JsonValidatorConfig::builder)
+ content(JsonModelConfig::builder)
.catalog()
.name(INLINE_CATALOG_NAME)
.inject(catalog -> injectSchemas(catalog, messages))
@@ -396,13 +396,13 @@ private HttpRequestConfigBuilder injectPathParams(
Parameter parameter = parameters.get(name);
if (parameter.schema != null && parameter.schema.type != null)
{
- ValidatorConfig validator = validators.get(parameter.schema.type);
- if (validator != null)
+ ModelConfig model = models.get(parameter.schema.type);
+ if (model != null)
{
request
.pathParam()
.name(name)
- .validator(validator)
+ .model(model)
.build();
}
}
diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java
index 2d80accf23..edc1d1d971 100644
--- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java
+++ b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java
@@ -46,7 +46,7 @@
import io.aklivity.zilla.runtime.engine.config.EngineConfig;
import io.aklivity.zilla.runtime.engine.config.EngineConfigWriter;
import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig;
public class AsyncApiMqttProxyConfigGenerator extends AsyncApiConfigGenerator
@@ -250,7 +250,7 @@ private BindingConfigBuilder injectMqttServerOptions(
.options(MqttOptionsConfig::builder)
.topic()
.name(topic)
- .content(JsonValidatorConfig::builder)
+ .content(JsonModelConfig::builder)
.catalog()
.name(INLINE_CATALOG_NAME)
.inject(cataloged -> injectJsonSchemas(cataloged, messages, APPLICATION_JSON))
diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java
index 04f5e65cfa..50b86387a9 100644
--- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java
+++ b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java
@@ -58,11 +58,11 @@
import io.aklivity.zilla.runtime.engine.config.EngineConfig;
import io.aklivity.zilla.runtime.engine.config.EngineConfigWriter;
import io.aklivity.zilla.runtime.engine.config.GuardedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder;
import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
import io.aklivity.zilla.runtime.guard.jwt.config.JwtOptionsConfig;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig;
public class OpenApiHttpProxyConfigGenerator extends OpenApiConfigGenerator
@@ -335,7 +335,7 @@ private HttpRequestConfigBuilder injectContent(
if (schema != null)
{
request.
- content(JsonValidatorConfig::builder)
+ content(JsonModelConfig::builder)
.catalog()
.name(INLINE_CATALOG_NAME)
.schema()
@@ -358,8 +358,8 @@ private HttpRequestConfigBuilder injectParams(
{
if (parameter.schema != null && parameter.schema.type != null)
{
- ValidatorConfig validator = validators.get(parameter.schema.type);
- if (validator != null)
+ ModelConfig model = models.get(parameter.schema.type);
+ if (model != null)
{
switch (parameter.in)
{
@@ -367,21 +367,21 @@ private HttpRequestConfigBuilder injectParams(
request.
pathParam()
.name(parameter.name)
- .validator(validator)
+ .model(model)
.build();
break;
case "query":
request.
queryParam()
.name(parameter.name)
- .validator(validator)
+ .model(model)
.build();
break;
case "header":
request.
header()
.name(parameter.name)
- .validator(validator)
+ .model(model)
.build();
break;
}
@@ -451,7 +451,7 @@ private HttpRequestConfigBuilder injectResponses(
.status(Integer.parseInt(status))
.contentType(response2.getKey())
.inject(response -> injectResponseHeaders(responses1, response))
- .content(JsonValidatorConfig::builder)
+ .content(JsonModelConfig::builder)
.catalog()
.name(INLINE_CATALOG_NAME)
.schema()
@@ -476,13 +476,13 @@ private HttpResponseConfigBuilder injectResponseHeaders(
for (Map.Entry header : responses.headers.entrySet())
{
String name = header.getKey();
- ValidatorConfig validator = validators.get(header.getValue().schema.type);
- if (validator != null)
+ ModelConfig model = models.get(header.getValue().schema.type);
+ if (model != null)
{
response
.header()
.name(name)
- .validator(validator)
+ .model(model)
.build();
}
}
diff --git a/incubator/command-generate/src/main/moditect/module-info.java b/incubator/command-generate/src/main/moditect/module-info.java
index fe511b5c48..0c03ce63de 100644
--- a/incubator/command-generate/src/main/moditect/module-info.java
+++ b/incubator/command-generate/src/main/moditect/module-info.java
@@ -23,9 +23,10 @@
requires io.aklivity.zilla.runtime.catalog.inline;
requires io.aklivity.zilla.runtime.guard.jwt;
requires io.aklivity.zilla.runtime.vault.filesystem;
- requires io.aklivity.zilla.runtime.validator.avro;
- requires io.aklivity.zilla.runtime.validator.core;
- requires io.aklivity.zilla.runtime.validator.json;
+ requires io.aklivity.zilla.runtime.model.avro;
+ requires io.aklivity.zilla.runtime.model.core;
+ requires io.aklivity.zilla.runtime.model.json;
+ requires io.aklivity.zilla.runtime.model.protobuf;
requires com.fasterxml.jackson.dataformat.yaml;
requires com.fasterxml.jackson.databind;
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml
index 26cea2474d..14c6d158ef 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml
@@ -45,14 +45,14 @@ bindings:
path:
id: string
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: item
- path: /items
method: POST
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: item
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml
index 449cdb7269..d97ca1fed1 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml
@@ -23,14 +23,14 @@ bindings:
path:
id: string
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: item
- path: /items
method: POST
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: item
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml
index 23be2cb3d7..630cd6ddf8 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml
@@ -34,7 +34,7 @@ bindings:
topics:
- name: smartylighting/streetlights/1/0/event/*/lighting/measured
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: items
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml
index 4204654d97..8f8348a2f0 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml
@@ -17,7 +17,7 @@ bindings:
topics:
- name: smartylighting/streetlights/1/0/event/*/lighting/measured
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: items
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml
index d4a05cff4a..3d4edbea3e 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml
@@ -47,7 +47,7 @@ bindings:
- path: /items
method: POST
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Item
@@ -113,7 +113,7 @@ bindings:
x-pages: integer
x-next: string
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Items
@@ -124,7 +124,7 @@ bindings:
content-type:
- application/json
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Item
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml
index cd157b190e..65dc139e8c 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml
@@ -25,7 +25,7 @@ bindings:
- path: /items
method: POST
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Item
diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml
index 2e33053261..c3e2168170 100644
--- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml
+++ b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml
@@ -25,7 +25,7 @@ bindings:
- path: /items
method: POST
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Item
@@ -90,7 +90,7 @@ bindings:
x-pages: integer
x-next: string
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Items
@@ -101,7 +101,7 @@ bindings:
content-type:
- application/json
content:
- type: json
+ model: json
catalog:
catalog0:
- subject: Item
diff --git a/incubator/command-log/pom.xml b/incubator/command-log/pom.xml
index 5b2a23ff10..08af549262 100644
--- a/incubator/command-log/pom.xml
+++ b/incubator/command-log/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/LoggableStream.java b/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/LoggableStream.java
index 0aeb4ef3eb..72f04d6576 100644
--- a/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/LoggableStream.java
+++ b/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/LoggableStream.java
@@ -110,8 +110,10 @@
import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttPublishBeginExFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttPublishDataExFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttSessionBeginExFW;
+import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttSessionFlushExFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttSubscribeBeginExFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttSubscribeDataExFW;
+import io.aklivity.zilla.runtime.command.log.internal.types.stream.MqttSubscribeFlushExFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.ProxyBeginExFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.ResetFW;
import io.aklivity.zilla.runtime.command.log.internal.types.stream.SignalFW;
@@ -1513,7 +1515,33 @@ private void onMqttFlushEx(
final OctetsFW extension = flush.extension();
final MqttFlushExFW mqttFlushEx = mqttFlushExRO.wrap(extension.buffer(), extension.offset(), extension.limit());
- final Array32FW filters = mqttFlushEx.subscribe().filters();
+
+
+ switch (mqttFlushEx.kind())
+ {
+ case MqttFlushExFW.KIND_SESSION:
+ onMqttSessionFlushEx(offset, timestamp, mqttFlushEx.session());
+ break;
+ case MqttFlushExFW.KIND_SUBSCRIBE:
+ onMqttSubscribeFlushEx(offset, timestamp, mqttFlushEx.subscribe());
+ break;
+ }
+ }
+
+ private void onMqttSessionFlushEx(
+ int offset,
+ long timestamp,
+ MqttSessionFlushExFW session)
+ {
+ out.printf(verboseFormat, index, offset, timestamp, format("%d", session.packetId()));
+ }
+
+ private void onMqttSubscribeFlushEx(
+ int offset,
+ long timestamp,
+ MqttSubscribeFlushExFW subscribe)
+ {
+ final Array32FW filters = subscribe.filters();
filters.forEach(f -> out.printf(verboseFormat, index, offset, timestamp,
format("%s %d %d", f.pattern(), f.subscriptionId(), f.flags())));
diff --git a/incubator/command-tune/pom.xml b/incubator/command-tune/pom.xml
index 0a4e91116b..504b5fd873 100644
--- a/incubator/command-tune/pom.xml
+++ b/incubator/command-tune/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/exporter-otlp.spec/pom.xml b/incubator/exporter-otlp.spec/pom.xml
index e1f4a4d536..a4a60d9231 100644
--- a/incubator/exporter-otlp.spec/pom.xml
+++ b/incubator/exporter-otlp.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/exporter-otlp/pom.xml b/incubator/exporter-otlp/pom.xml
index b83e2c9fcf..c03bc00a80 100644
--- a/incubator/exporter-otlp/pom.xml
+++ b/incubator/exporter-otlp/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/incubator/validator-avro.spec/COPYRIGHT b/incubator/model-avro.spec/COPYRIGHT
similarity index 100%
rename from incubator/validator-avro.spec/COPYRIGHT
rename to incubator/model-avro.spec/COPYRIGHT
diff --git a/incubator/validator-avro.spec/LICENSE b/incubator/model-avro.spec/LICENSE
similarity index 100%
rename from incubator/validator-avro.spec/LICENSE
rename to incubator/model-avro.spec/LICENSE
diff --git a/incubator/validator-avro.spec/NOTICE b/incubator/model-avro.spec/NOTICE
similarity index 100%
rename from incubator/validator-avro.spec/NOTICE
rename to incubator/model-avro.spec/NOTICE
diff --git a/incubator/validator-avro.spec/NOTICE.template b/incubator/model-avro.spec/NOTICE.template
similarity index 100%
rename from incubator/validator-avro.spec/NOTICE.template
rename to incubator/model-avro.spec/NOTICE.template
diff --git a/incubator/validator-avro.spec/mvnw b/incubator/model-avro.spec/mvnw
similarity index 100%
rename from incubator/validator-avro.spec/mvnw
rename to incubator/model-avro.spec/mvnw
diff --git a/incubator/validator-avro.spec/mvnw.cmd b/incubator/model-avro.spec/mvnw.cmd
similarity index 100%
rename from incubator/validator-avro.spec/mvnw.cmd
rename to incubator/model-avro.spec/mvnw.cmd
diff --git a/incubator/validator-avro.spec/pom.xml b/incubator/model-avro.spec/pom.xml
similarity index 93%
rename from incubator/validator-avro.spec/pom.xml
rename to incubator/model-avro.spec/pom.xml
index 505f136cec..49633ad0a8 100644
--- a/incubator/validator-avro.spec/pom.xml
+++ b/incubator/model-avro.spec/pom.xml
@@ -8,12 +8,12 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
- validator-avro.spec
- zilla::incubator::validator-avro.spec
+ model-avro.spec
+ zilla::incubator::model-avro.spec
@@ -79,7 +79,7 @@
${project.version}
core
- io.aklivity.zilla.specs.validator.avro.internal.types
+ io.aklivity.zilla.specs.model.avro.internal.types
@@ -135,7 +135,7 @@
jacoco-maven-plugin
- io/aklivity/zilla/specs/validator/avro/internal/types/**/*.class
+ io/aklivity/zilla/specs/model/avro/internal/types/**/*.class
diff --git a/incubator/validator-avro.spec/src/main/moditect/module-info.java b/incubator/model-avro.spec/src/main/moditect/module-info.java
similarity index 92%
rename from incubator/validator-avro.spec/src/main/moditect/module-info.java
rename to incubator/model-avro.spec/src/main/moditect/module-info.java
index b289801500..99ce1d21bf 100644
--- a/incubator/validator-avro.spec/src/main/moditect/module-info.java
+++ b/incubator/model-avro.spec/src/main/moditect/module-info.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-open module io.aklivity.zilla.specs.validator.avro
+open module io.aklivity.zilla.specs.model.avro
{
requires transitive io.aklivity.zilla.specs.engine;
}
diff --git a/incubator/model-avro.spec/src/main/scripts/io/aklivity/zilla/specs/model/avro/config/model.yaml b/incubator/model-avro.spec/src/main/scripts/io/aklivity/zilla/specs/model/avro/config/model.yaml
new file mode 100644
index 0000000000..dbb4b6ecdd
--- /dev/null
+++ b/incubator/model-avro.spec/src/main/scripts/io/aklivity/zilla/specs/model/avro/config/model.yaml
@@ -0,0 +1,50 @@
+#
+# Copyright 2021-2023 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+---
+name: test
+catalogs:
+ test0:
+ type: test
+ options:
+ schema: |
+ {
+ "fields": [
+ {
+ "name": "id",
+ "type": "string"
+ },
+ {
+ "name": "status",
+ "type": "string"
+ }
+ ],
+ "name": "Event",
+ "namespace": "io.aklivity.example",
+ "type": "record"
+ }
+bindings:
+ test:
+ kind: server
+ type: test
+ options:
+ value:
+ model: avro
+ view: json
+ catalog:
+ catalog0:
+ - subject: test0
+ version: latest
+ exit: test
diff --git a/incubator/model-avro.spec/src/main/scripts/io/aklivity/zilla/specs/model/avro/schema/avro.schema.patch.json b/incubator/model-avro.spec/src/main/scripts/io/aklivity/zilla/specs/model/avro/schema/avro.schema.patch.json
new file mode 100644
index 0000000000..7d1a7c526b
--- /dev/null
+++ b/incubator/model-avro.spec/src/main/scripts/io/aklivity/zilla/specs/model/avro/schema/avro.schema.patch.json
@@ -0,0 +1,136 @@
+[
+ {
+ "op": "add",
+ "path": "/$defs/converter/types/enum/-",
+ "value": "avro"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/converter/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "avro"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "avro"
+ },
+ "view":
+ {
+ "type": "string",
+ "enum":
+ [
+ "json"
+ ]
+ },
+ "catalog":
+ {
+ "type": "object",
+ "patternProperties":
+ {
+ "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$":
+ {
+ "type": "array",
+ "items":
+ {
+ "oneOf":
+ [
+ {
+ "type": "object",
+ "properties":
+ {
+ "id":
+ {
+ "type": "integer"
+ }
+ },
+ "required":
+ [
+ "id"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "schema":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "schema"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "strategy":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "strategy"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "subject":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "subject"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ }
+ },
+ "maxProperties": 1
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+]
diff --git a/incubator/model-avro.spec/src/test/java/io/aklivity/zilla/specs/model/avro/config/SchemaTest.java b/incubator/model-avro.spec/src/test/java/io/aklivity/zilla/specs/model/avro/config/SchemaTest.java
new file mode 100644
index 0000000000..e907872462
--- /dev/null
+++ b/incubator/model-avro.spec/src/test/java/io/aklivity/zilla/specs/model/avro/config/SchemaTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.specs.model.avro.config;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import jakarta.json.JsonObject;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import io.aklivity.zilla.specs.engine.config.ConfigSchemaRule;
+
+public class SchemaTest
+{
+ @Rule
+ public final ConfigSchemaRule schema = new ConfigSchemaRule()
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/catalog/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/model/avro/schema/avro.schema.patch.json")
+ .configurationRoot("io/aklivity/zilla/specs/model/avro/config");
+
+ @Test
+ public void shouldValidateCatalog()
+ {
+ JsonObject config = schema.validate("model.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+}
diff --git a/incubator/validator-avro/COPYRIGHT b/incubator/model-avro/COPYRIGHT
similarity index 100%
rename from incubator/validator-avro/COPYRIGHT
rename to incubator/model-avro/COPYRIGHT
diff --git a/incubator/validator-avro/LICENSE b/incubator/model-avro/LICENSE
similarity index 100%
rename from incubator/validator-avro/LICENSE
rename to incubator/model-avro/LICENSE
diff --git a/incubator/validator-avro/NOTICE b/incubator/model-avro/NOTICE
similarity index 100%
rename from incubator/validator-avro/NOTICE
rename to incubator/model-avro/NOTICE
diff --git a/incubator/validator-avro/NOTICE.template b/incubator/model-avro/NOTICE.template
similarity index 100%
rename from incubator/validator-avro/NOTICE.template
rename to incubator/model-avro/NOTICE.template
diff --git a/incubator/validator-avro/mvnw b/incubator/model-avro/mvnw
similarity index 100%
rename from incubator/validator-avro/mvnw
rename to incubator/model-avro/mvnw
diff --git a/incubator/validator-avro/mvnw.cmd b/incubator/model-avro/mvnw.cmd
similarity index 100%
rename from incubator/validator-avro/mvnw.cmd
rename to incubator/model-avro/mvnw.cmd
diff --git a/incubator/validator-avro/pom.xml b/incubator/model-avro/pom.xml
similarity index 87%
rename from incubator/validator-avro/pom.xml
rename to incubator/model-avro/pom.xml
index 87e8b62542..88026c65a4 100644
--- a/incubator/validator-avro/pom.xml
+++ b/incubator/model-avro/pom.xml
@@ -8,12 +8,12 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
- validator-avro
- zilla::incubator::validator-avro
+ model-avro
+ zilla::incubator::model-avro
@@ -26,14 +26,14 @@
11
11
- 0.80
+ 0.88
0
${project.groupId}
- validator-avro.spec
+ model-avro.spec
${project.version}
provided
@@ -83,7 +83,7 @@
${project.version}
core
- io.aklivity.zilla.runtime.validator.avro.internal.types
+ io.aklivity.zilla.runtime.model.avro.internal.types
@@ -120,16 +120,16 @@
${project.groupId}
- validator-avro.spec
+ model-avro.spec
- ^\Qio/aklivity/zilla/specs/validator/avro/\E
- io/aklivity/zilla/runtime/validator/avro/
+ ^\Qio/aklivity/zilla/specs/model/avro/\E
+ io/aklivity/zilla/runtime/model/avro/internal/
- io/aklivity/zilla/specs/validator/avro/schema/avro.schema.patch.json
+ io/aklivity/zilla/specs/model/avro/schema/avro.schema.patch.json
${project.build.directory}/classes
@@ -153,7 +153,7 @@
org.apache.avro
- io.aklivity.zilla.runtime.validator.avro.internal.avro
+ io.aklivity.zilla.runtime.model.avro.internal.avro
true
@@ -187,7 +187,7 @@
jacoco-maven-plugin
- io/aklivity/zilla/runtime/validator/avro/internal/types/**/*.class
+ io/aklivity/zilla/runtime/model/avro/internal/types/**/*.class
diff --git a/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/config/AvroModelConfig.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/config/AvroModelConfig.java
new file mode 100644
index 0000000000..57005925db
--- /dev/null
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/config/AvroModelConfig.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.config;
+
+import java.util.List;
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+
+public final class AvroModelConfig extends ModelConfig
+{
+ public final String subject;
+ public final String view;
+
+ public AvroModelConfig(
+ List cataloged,
+ String subject,
+ String view)
+ {
+ super("avro", cataloged);
+ this.subject = subject;
+ this.view = view;
+ }
+
+ public static AvroModelConfigBuilder builder(
+ Function mapper)
+ {
+ return new AvroModelConfigBuilder<>(mapper::apply);
+ }
+
+ public static AvroModelConfigBuilder builder()
+ {
+ return new AvroModelConfigBuilder<>(AvroModelConfig.class::cast);
+ }
+}
diff --git a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigBuilder.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/config/AvroModelConfigBuilder.java
similarity index 59%
rename from incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigBuilder.java
rename to incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/config/AvroModelConfigBuilder.java
index c1596da4cc..476bc23ee8 100644
--- a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigBuilder.java
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/config/AvroModelConfigBuilder.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.json.config;
+package io.aklivity.zilla.runtime.model.avro.config;
import java.util.LinkedList;
import java.util.List;
@@ -22,31 +22,47 @@
import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder;
import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
-public class JsonValidatorConfigBuilder extends ConfigBuilder>
+public class AvroModelConfigBuilder extends ConfigBuilder>
{
- private final Function mapper;
+ private final Function mapper;
private List catalogs;
+ private String subject;
+ private String view;
- JsonValidatorConfigBuilder(
- Function mapper)
+ AvroModelConfigBuilder(
+ Function mapper)
{
this.mapper = mapper;
}
@Override
@SuppressWarnings("unchecked")
- protected Class> thisType()
+ protected Class> thisType()
{
- return (Class>) getClass();
+ return (Class>) getClass();
}
- public CatalogedConfigBuilder> catalog()
+ public AvroModelConfigBuilder subject(
+ String subject)
+ {
+ this.subject = subject;
+ return this;
+ }
+
+ public AvroModelConfigBuilder view(
+ String view)
+ {
+ this.view = view;
+ return this;
+ }
+
+ public CatalogedConfigBuilder> catalog()
{
return CatalogedConfig.builder(this::catalog);
}
- public JsonValidatorConfigBuilder catalog(
+ public AvroModelConfigBuilder catalog(
CatalogedConfig catalog)
{
if (catalogs == null)
@@ -60,6 +76,6 @@ public JsonValidatorConfigBuilder catalog(
@Override
public T build()
{
- return mapper.apply(new JsonValidatorConfig(catalogs));
+ return mapper.apply(new AvroModelConfig(catalogs, subject, view));
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfig.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModel.java
similarity index 50%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfig.java
rename to incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModel.java
index 5deba72254..4f7fb5f910 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfig.java
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModel.java
@@ -12,27 +12,34 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.avro.internal;
-import java.util.function.Function;
+import java.net.URL;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
-public class LongValidatorConfig extends ValidatorConfig
+public class AvroModel implements Model
{
- public LongValidatorConfig()
+ public static final String NAME = "avro";
+
+ @Override
+ public String name()
{
- super("long");
+ return NAME;
}
- public static LongValidatorConfigBuilder builder(
- Function mapper)
+ @Override
+ public ModelContext supply(
+ EngineContext context)
{
- return new LongValidatorConfigBuilder<>(mapper::apply);
+ return new AvroModelContext(context);
}
- public static LongValidatorConfigBuilder builder()
+ @Override
+ public URL type()
{
- return new LongValidatorConfigBuilder<>(LongValidatorConfig.class::cast);
+ return getClass().getResource("schema/avro.schema.patch.json");
}
}
diff --git a/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelContext.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelContext.java
new file mode 100644
index 0000000000..fa4a25232c
--- /dev/null
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelContext.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal;
+
+import java.util.function.LongFunction;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public class AvroModelContext implements ModelContext
+{
+ private final LongFunction supplyCatalog;
+
+ public AvroModelContext(
+ EngineContext context)
+ {
+ this.supplyCatalog = context::supplyCatalog;
+ }
+
+ @Override
+ public ConverterHandler supplyReadConverterHandler(
+ ModelConfig config)
+ {
+ return new AvroReadConverterHandler(AvroModelConfig.class.cast(config), supplyCatalog);
+ }
+
+ @Override
+ public ConverterHandler supplyWriteConverterHandler(
+ ModelConfig config)
+ {
+ return new AvroWriteConverterHandler(AvroModelConfig.class.cast(config), supplyCatalog);
+ }
+}
diff --git a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorFactory.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelFactorySpi.java
similarity index 51%
rename from incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorFactory.java
rename to incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelFactorySpi.java
index 982d366907..52e851123e 100644
--- a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorFactory.java
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelFactorySpi.java
@@ -12,26 +12,22 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.avro;
+package io.aklivity.zilla.runtime.model.avro.internal;
import java.net.URL;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
import io.aklivity.zilla.runtime.common.feature.Incubating;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi;
-import io.aklivity.zilla.runtime.validator.avro.config.AvroValidatorConfig;
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelFactorySpi;
@Incubating
-public final class AvroValidatorFactory implements ValidatorFactorySpi
+public final class AvroModelFactorySpi implements ModelFactorySpi
{
@Override
public String type()
{
- return "avro";
+ return AvroModel.NAME;
}
public URL schema()
@@ -40,11 +36,9 @@ public URL schema()
}
@Override
- public Validator create(
- ValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
+ public Model create(
+ Configuration config)
{
- return new AvroValidator(AvroValidatorConfig.class.cast(config), resolveId, supplyCatalog);
+ return new AvroModel();
}
}
diff --git a/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java
new file mode 100644
index 0000000000..184cfd10e5
--- /dev/null
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.agrona.ExpandableDirectByteBuffer;
+import org.agrona.collections.Int2IntHashMap;
+import org.agrona.collections.Int2ObjectCache;
+import org.agrona.io.DirectBufferInputStream;
+import org.agrona.io.ExpandableDirectBufferOutputStream;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumReader;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.io.BinaryDecoder;
+import org.apache.avro.io.BinaryEncoder;
+import org.apache.avro.io.DecoderFactory;
+import org.apache.avro.io.EncoderFactory;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public abstract class AvroModelHandler
+{
+ protected static final String VIEW_JSON = "json";
+
+ private static final InputStream EMPTY_INPUT_STREAM = new ByteArrayInputStream(new byte[0]);
+ private static final OutputStream EMPTY_OUTPUT_STREAM = new ByteArrayOutputStream(0);
+ private static final int JSON_FIELD_STRUCTURE_LENGTH = "\"\":\"\",".length();
+
+ protected final SchemaConfig catalog;
+ protected final CatalogHandler handler;
+ protected final DecoderFactory decoderFactory;
+ protected final EncoderFactory encoderFactory;
+ protected final BinaryDecoder decoder;
+ protected final BinaryEncoder encoder;
+ protected final String subject;
+ protected final String view;
+ protected final ExpandableDirectBufferOutputStream expandable;
+ protected final DirectBufferInputStream in;
+
+ private final Int2ObjectCache schemas;
+ private final Int2ObjectCache> readers;
+ private final Int2ObjectCache> writers;
+ private final Int2ObjectCache records;
+ private final Int2IntHashMap paddings;
+
+ protected AvroModelHandler(
+ AvroModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ this.decoderFactory = DecoderFactory.get();
+ this.decoder = decoderFactory.binaryDecoder(EMPTY_INPUT_STREAM, null);
+ this.encoderFactory = EncoderFactory.get();
+ this.encoder = encoderFactory.binaryEncoder(EMPTY_OUTPUT_STREAM, null);
+ CatalogedConfig cataloged = config.cataloged.get(0);
+ this.handler = supplyCatalog.apply(cataloged.id);
+ this.catalog = cataloged.schemas.size() != 0 ? cataloged.schemas.get(0) : null;
+ this.view = config.view;
+ this.subject = catalog != null && catalog.subject != null
+ ? catalog.subject
+ : config.subject;
+ this.schemas = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.readers = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.writers = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.records = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.paddings = new Int2IntHashMap(-1);
+ this.expandable = new ExpandableDirectBufferOutputStream(new ExpandableDirectByteBuffer());
+ this.in = new DirectBufferInputStream();
+ }
+
+ protected final boolean validate(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ boolean status = false;
+ try
+ {
+ GenericRecord record = supplyRecord(schemaId);
+ in.wrap(buffer, index, length);
+ GenericDatumReader reader = supplyReader(schemaId);
+ if (reader != null)
+ {
+ reader.read(record, decoderFactory.binaryDecoder(in, decoder));
+ status = true;
+ }
+ }
+ catch (IOException | AvroRuntimeException ex)
+ {
+ ex.printStackTrace();
+ }
+ return status;
+ }
+
+ protected final Schema supplySchema(
+ int schemaId)
+ {
+ return schemas.computeIfAbsent(schemaId, this::resolveSchema);
+ }
+
+ protected final int supplyPadding(
+ int schemaId)
+ {
+ return paddings.computeIfAbsent(schemaId, id -> calculatePadding(supplySchema(id)));
+ }
+
+ protected final GenericDatumReader supplyReader(
+ int schemaId)
+ {
+ return readers.computeIfAbsent(schemaId, this::createReader);
+ }
+
+ protected final GenericDatumWriter supplyWriter(
+ int schemaId)
+ {
+ return writers.computeIfAbsent(schemaId, this::createWriter);
+ }
+
+ protected final GenericRecord supplyRecord(
+ int schemaId)
+ {
+ return records.computeIfAbsent(schemaId, this::createRecord);
+ }
+
+ private GenericDatumReader createReader(
+ int schemaId)
+ {
+ Schema schema = supplySchema(schemaId);
+ GenericDatumReader reader = null;
+ if (schema != null)
+ {
+ reader = new GenericDatumReader(schema);
+ }
+ return reader;
+ }
+
+ private GenericDatumWriter createWriter(
+ int schemaId)
+ {
+ Schema schema = supplySchema(schemaId);
+ GenericDatumWriter writer = null;
+ if (schema != null)
+ {
+ writer = new GenericDatumWriter(schema);
+ }
+ return writer;
+ }
+
+ private GenericRecord createRecord(
+ int schemaId)
+ {
+ Schema schema = supplySchema(schemaId);
+ GenericRecord record = null;
+ if (schema != null)
+ {
+ record = new GenericData.Record(schema);
+ }
+ return record;
+ }
+
+ private Schema resolveSchema(
+ int schemaId)
+ {
+ Schema schema = null;
+ String schemaText = handler.resolve(schemaId);
+ if (schemaText != null)
+ {
+ schema = new Schema.Parser().parse(schemaText);
+ }
+ return schema;
+ }
+
+ private int calculatePadding(
+ Schema schema)
+ {
+ int padding = 0;
+
+ if (schema != null)
+ {
+ padding = 2;
+ for (Schema.Field field : schema.getFields())
+ {
+ if (field.schema().getType().equals(Schema.Type.RECORD))
+ {
+ padding += calculatePadding(field.schema());
+ }
+ else
+ {
+ padding += field.name().getBytes().length + JSON_FIELD_STRUCTURE_LENGTH;
+ }
+ }
+ }
+ return padding;
+ }
+}
diff --git a/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroReadConverterHandler.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroReadConverterHandler.java
new file mode 100644
index 0000000000..3518cd39fd
--- /dev/null
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroReadConverterHandler.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal;
+
+import static io.aklivity.zilla.runtime.engine.catalog.CatalogHandler.NO_SCHEMA_ID;
+
+import java.io.IOException;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericDatumReader;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.io.JsonEncoder;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public class AvroReadConverterHandler extends AvroModelHandler implements ConverterHandler
+{
+ public AvroReadConverterHandler(
+ AvroModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ }
+
+ @Override
+ public int padding(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ int padding = 0;
+ if (VIEW_JSON.equals(view))
+ {
+ int schemaId = handler.resolve(data, index, length);
+
+ if (schemaId == NO_SCHEMA_ID)
+ {
+ if (catalog.id != NO_SCHEMA_ID)
+ {
+ schemaId = catalog.id;
+ }
+ else
+ {
+ schemaId = handler.resolve(subject, catalog.version);
+ }
+ }
+ padding = supplyPadding(schemaId);
+ }
+ return padding;
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ return handler.decode(data, index, length, next, this::decodePayload);
+ }
+
+ private int decodePayload(
+ int schemaId,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+
+ if (schemaId == NO_SCHEMA_ID)
+ {
+ if (catalog.id != NO_SCHEMA_ID)
+ {
+ schemaId = catalog.id;
+ }
+ else
+ {
+ schemaId = handler.resolve(subject, catalog.version);
+ }
+ }
+
+ if (VIEW_JSON.equals(view))
+ {
+ deserializeRecord(schemaId, data, index, length);
+ int recordLength = expandable.position();
+ if (recordLength > 0)
+ {
+ next.accept(expandable.buffer(), 0, recordLength);
+ valLength = recordLength;
+ }
+ }
+ else if (validate(schemaId, data, index, length))
+ {
+ next.accept(data, index, length);
+ valLength = length;
+ }
+ return valLength;
+ }
+
+ private void deserializeRecord(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ try
+ {
+ GenericDatumReader reader = supplyReader(schemaId);
+ GenericDatumWriter writer = supplyWriter(schemaId);
+ if (reader != null)
+ {
+ GenericRecord record = supplyRecord(schemaId);
+ in.wrap(buffer, index, length);
+ expandable.wrap(expandable.buffer());
+ record = reader.read(record, decoderFactory.binaryDecoder(in, decoder));
+ Schema schema = record.getSchema();
+ JsonEncoder out = encoderFactory.jsonEncoder(schema, expandable);
+ writer.write(record, out);
+ out.flush();
+ }
+ }
+ catch (IOException | AvroRuntimeException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroWriteConverterHandler.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroWriteConverterHandler.java
new file mode 100644
index 0000000000..31f1bff334
--- /dev/null
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroWriteConverterHandler.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal;
+
+import java.io.IOException;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericDatumReader;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public class AvroWriteConverterHandler extends AvroModelHandler implements ConverterHandler
+{
+ public AvroWriteConverterHandler(
+ AvroModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ }
+
+ @Override
+ public int padding(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ return handler.encodePadding();
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+
+ int schemaId = catalog != null && catalog.id > 0
+ ? catalog.id
+ : handler.resolve(subject, catalog.version);
+
+ if (VIEW_JSON.equals(view))
+ {
+ valLength = handler.encode(schemaId, data, index, length, next, this::serializeJsonRecord);
+ }
+ else if (validate(schemaId, data, index, length))
+ {
+ valLength = handler.encode(schemaId, data, index, length, next, CatalogHandler.Encoder.IDENTITY);
+ }
+ return valLength;
+ }
+
+ private int serializeJsonRecord(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ try
+ {
+ Schema schema = supplySchema(schemaId);
+ GenericDatumReader reader = supplyReader(schemaId);
+ GenericDatumWriter writer = supplyWriter(schemaId);
+ if (reader != null)
+ {
+ GenericRecord record = supplyRecord(schemaId);
+ in.wrap(buffer, index, length);
+ expandable.wrap(expandable.buffer());
+ record = reader.read(record, decoderFactory.jsonDecoder(schema, in));
+ encoderFactory.binaryEncoder(expandable, encoder);
+ writer.write(record, encoder);
+ encoder.flush();
+ next.accept(expandable.buffer(), 0, expandable.position());
+ }
+ }
+ catch (IOException | AvroRuntimeException ex)
+ {
+ ex.printStackTrace();
+ }
+ return expandable.position();
+ }
+}
diff --git a/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/config/AvroModelConfigAdapter.java b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/config/AvroModelConfigAdapter.java
new file mode 100644
index 0000000000..f635804a60
--- /dev/null
+++ b/incubator/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/config/AvroModelConfigAdapter.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal.config;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonArrayBuilder;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.JsonValue;
+import jakarta.json.bind.adapter.JsonbAdapter;
+
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfigAdapter;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public final class AvroModelConfigAdapter implements ModelConfigAdapterSpi, JsonbAdapter
+{
+ private static final String AVRO = "avro";
+ private static final String MODEL_NAME = "model";
+ private static final String CATALOG_NAME = "catalog";
+ private static final String SUBJECT_NAME = "subject";
+ private static final String VIEW = "view";
+
+ private final SchemaConfigAdapter schema = new SchemaConfigAdapter();
+
+ @Override
+ public String type()
+ {
+ return AVRO;
+ }
+
+ @Override
+ public JsonValue adaptToJson(
+ ModelConfig config)
+ {
+ AvroModelConfig converterConfig = (AvroModelConfig) config;
+ JsonObjectBuilder converter = Json.createObjectBuilder();
+
+ if (converterConfig.view != null)
+ {
+ converter.add(VIEW, converterConfig.view);
+ }
+
+ converter.add(MODEL_NAME, AVRO);
+ if (converterConfig.cataloged != null && !converterConfig.cataloged.isEmpty())
+ {
+ JsonObjectBuilder catalogs = Json.createObjectBuilder();
+ for (CatalogedConfig catalog : converterConfig.cataloged)
+ {
+ JsonArrayBuilder array = Json.createArrayBuilder();
+ for (SchemaConfig schemaItem: catalog.schemas)
+ {
+ array.add(schema.adaptToJson(schemaItem));
+ }
+ catalogs.add(catalog.name, array);
+ }
+ converter.add(CATALOG_NAME, catalogs);
+ }
+ return converter.build();
+ }
+
+ @Override
+ public ModelConfig adaptFromJson(
+ JsonValue value)
+ {
+ JsonObject object = (JsonObject) value;
+
+ assert object.containsKey(CATALOG_NAME);
+
+ JsonObject catalogsJson = object.getJsonObject(CATALOG_NAME);
+ List catalogs = new LinkedList<>();
+ for (String catalogName: catalogsJson.keySet())
+ {
+ JsonArray schemasJson = catalogsJson.getJsonArray(catalogName);
+ List schemas = new LinkedList<>();
+ for (JsonValue item : schemasJson)
+ {
+ JsonObject schemaJson = (JsonObject) item;
+ SchemaConfig schemaElement = schema.adaptFromJson(schemaJson);
+ schemas.add(schemaElement);
+ }
+ catalogs.add(new CatalogedConfig(catalogName, schemas));
+ }
+
+ String subject = object.containsKey(SUBJECT_NAME)
+ ? object.getString(SUBJECT_NAME)
+ : null;
+
+ String view = object.containsKey(VIEW)
+ ? object.getString(VIEW)
+ : null;
+
+ return new AvroModelConfig(catalogs, subject, view);
+ }
+}
diff --git a/incubator/validator-avro/src/main/moditect/module-info.java b/incubator/model-avro/src/main/moditect/module-info.java
similarity index 55%
rename from incubator/validator-avro/src/main/moditect/module-info.java
rename to incubator/model-avro/src/main/moditect/module-info.java
index 058ec63edf..1bae61c43e 100644
--- a/incubator/validator-avro/src/main/moditect/module-info.java
+++ b/incubator/model-avro/src/main/moditect/module-info.java
@@ -12,21 +12,21 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-module io.aklivity.zilla.runtime.validator.avro
+module io.aklivity.zilla.runtime.model.avro
{
requires com.fasterxml.jackson.core;
requires com.fasterxml.jackson.databind;
requires org.slf4j;
requires io.aklivity.zilla.runtime.engine;
- exports io.aklivity.zilla.runtime.validator.avro.config;
+ exports io.aklivity.zilla.runtime.model.avro.config;
- uses io.aklivity.zilla.runtime.validator.avro.internal.avro.Conversion;
- uses io.aklivity.zilla.runtime.validator.avro.internal.avro.LogicalTypes$LogicalTypeFactory;
+ uses io.aklivity.zilla.runtime.model.avro.internal.avro.Conversion;
+ uses io.aklivity.zilla.runtime.model.avro.internal.avro.LogicalTypes$LogicalTypeFactory;
- provides io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
- with io.aklivity.zilla.runtime.validator.avro.config.AvroValidatorConfigAdapter;
+ provides io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
+ with io.aklivity.zilla.runtime.model.avro.internal.config.AvroModelConfigAdapter;
- provides io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
- with io.aklivity.zilla.runtime.validator.avro.AvroValidatorFactory;
+ provides io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
+ with io.aklivity.zilla.runtime.model.avro.internal.AvroModelFactorySpi;
}
diff --git a/incubator/model-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi b/incubator/model-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
new file mode 100644
index 0000000000..4bab78031f
--- /dev/null
+++ b/incubator/model-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
@@ -0,0 +1 @@
+io.aklivity.zilla.runtime.model.avro.internal.config.AvroModelConfigAdapter
diff --git a/incubator/model-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi b/incubator/model-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
new file mode 100644
index 0000000000..2e6820134a
--- /dev/null
+++ b/incubator/model-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
@@ -0,0 +1 @@
+io.aklivity.zilla.runtime.model.avro.internal.AvroModelFactorySpi
diff --git a/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelFactorySpiTest.java b/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelFactorySpiTest.java
new file mode 100644
index 0000000000..5e89a00f20
--- /dev/null
+++ b/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelFactorySpiTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ModelFactory;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public class AvroModelFactorySpiTest
+{
+ @Test
+ public void shouldLoadAndCreate()
+ {
+ Configuration config = new Configuration();
+ ModelFactory factory = ModelFactory.instantiate();
+ Model model = factory.create("avro", config);
+
+ ModelContext context = new AvroModelContext(mock(EngineContext.class));
+
+ ModelConfig modelConfig = AvroModelConfig.builder()
+ .subject("test-value")
+ .catalog()
+ .name("test0")
+ .schema()
+ .subject("subject1")
+ .version("latest")
+ .build()
+ .build()
+ .build();
+
+ assertThat(model, instanceOf(AvroModel.class));
+ assertThat(context.supplyReadConverterHandler(modelConfig), instanceOf(AvroReadConverterHandler.class));
+ assertThat(context.supplyWriteConverterHandler(modelConfig), instanceOf(AvroWriteConverterHandler.class));
+ }
+}
diff --git a/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java b/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java
new file mode 100644
index 0000000000..5c56de4336
--- /dev/null
+++ b/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal;
+
+import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_DIRECTORY;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import java.util.Properties;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.catalog.Catalog;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogContext;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.CatalogConfig;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalog;
+import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public class AvroModelTest
+{
+ private static final String SCHEMA = "{\"fields\":[{\"name\":\"id\",\"type\":\"string\"}," +
+ "{\"name\":\"status\",\"type\":\"string\"}]," +
+ "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}";
+
+ private final AvroModelConfig avroConfig = AvroModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ private CatalogContext context;
+
+ @Before
+ public void init()
+ {
+ Properties properties = new Properties();
+ properties.setProperty(ENGINE_DIRECTORY.name(), "target/zilla-itests");
+ Configuration config = new Configuration(properties);
+ Catalog catalog = new TestCatalog(config);
+ context = catalog.supply(mock(EngineContext.class));
+ }
+
+ @Test
+ public void shouldVerifyValidAvroEvent()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ AvroReadConverterHandler converter = new AvroReadConverterHandler(avroConfig, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldWriteValidAvroEvent()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ AvroWriteConverterHandler converter = new AvroWriteConverterHandler(avroConfig, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64, 0x30, 0x10, 0x70, 0x6f,
+ 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInvalidAvroEvent()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ AvroReadConverterHandler converter = new AvroReadConverterHandler(avroConfig, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64, 0x30, 0x10};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldReadAvroEventExpectJson()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ AvroModelConfig config = AvroModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ AvroReadConverterHandler converter = new AvroReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+
+ String json =
+ "{" +
+ "\"id\":\"id0\"," +
+ "\"status\":\"positive\"" +
+ "}";
+
+ DirectBuffer expected = new UnsafeBuffer();
+ expected.wrap(json.getBytes(), 0, json.getBytes().length);
+
+ int progress = converter.convert(data, 0, data.capacity(), ValueConsumer.NOP);
+ assertEquals(expected.capacity(), progress);
+
+ assertEquals(expected.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldWriteJsonEventExpectAvro()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ AvroModelConfig config = AvroModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ AvroWriteConverterHandler converter = new AvroWriteConverterHandler(config, handler);
+
+ DirectBuffer expected = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ expected.wrap(bytes, 0, bytes.length);
+
+ String payload =
+ "{" +
+ "\"id\":\"id0\"," +
+ "\"status\":\"positive\"" +
+ "}";
+
+ DirectBuffer data = new UnsafeBuffer();
+ data.wrap(payload.getBytes(), 0, payload.getBytes().length);
+ int progress = converter.convert(data, 0, data.capacity(), ValueConsumer.NOP);
+ assertEquals(expected.capacity(), progress);
+
+ assertEquals(expected.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyPaddingLength()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ AvroModelConfig config = AvroModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ AvroReadConverterHandler converter = new AvroReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x06, 0x69, 0x64,
+ 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
+ data.wrap(bytes, 0, bytes.length);
+
+ assertEquals(22, converter.padding(data, 0, data.capacity()));
+
+ }
+}
diff --git a/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/config/AvroModelConfigAdapterTest.java b/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/config/AvroModelConfigAdapterTest.java
new file mode 100644
index 0000000000..94af0fe895
--- /dev/null
+++ b/incubator/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/config/AvroModelConfigAdapterTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.avro.internal.config;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+import jakarta.json.bind.JsonbConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.model.avro.config.AvroModelConfig;
+
+public class AvroModelConfigAdapterTest
+{
+ private Jsonb jsonb;
+
+ @Before
+ public void initJson()
+ {
+ JsonbConfig config = new JsonbConfig()
+ .withAdapters(new AvroModelConfigAdapter());
+ jsonb = JsonbBuilder.create(config);
+ }
+
+ @Test
+ public void shouldReadAvroconverter()
+ {
+ // GIVEN
+ String json =
+ "{" +
+ "\"view\":\"json\"," +
+ "\"model\": \"avro\"," +
+ "\"catalog\":" +
+ "{" +
+ "\"test0\":" +
+ "[" +
+ "{" +
+ "\"strategy\": \"topic\"," +
+ "\"version\": \"latest\"" +
+ "}," +
+ "{" +
+ "\"subject\": \"cat\"," +
+ "\"version\": \"latest\"" +
+ "}," +
+ "{" +
+ "\"id\": 42" +
+ "}" +
+ "]" +
+ "}" +
+ "}";
+
+ // WHEN
+ AvroModelConfig converter = jsonb.fromJson(json, AvroModelConfig.class);
+
+ // THEN
+ assertThat(converter, not(nullValue()));
+ assertThat(converter.view, equalTo("json"));
+ assertThat(converter.model, equalTo("avro"));
+ assertThat(converter.cataloged.size(), equalTo(1));
+ assertThat(converter.cataloged.get(0).name, equalTo("test0"));
+ assertThat(converter.cataloged.get(0).schemas.get(0).strategy, equalTo("topic"));
+ assertThat(converter.cataloged.get(0).schemas.get(0).version, equalTo("latest"));
+ assertThat(converter.cataloged.get(0).schemas.get(0).id, equalTo(0));
+ assertThat(converter.cataloged.get(0).schemas.get(1).subject, equalTo("cat"));
+ assertThat(converter.cataloged.get(0).schemas.get(1).strategy, nullValue());
+ assertThat(converter.cataloged.get(0).schemas.get(1).version, equalTo("latest"));
+ assertThat(converter.cataloged.get(0).schemas.get(1).id, equalTo(0));
+ assertThat(converter.cataloged.get(0).schemas.get(2).strategy, nullValue());
+ assertThat(converter.cataloged.get(0).schemas.get(2).version, nullValue());
+ assertThat(converter.cataloged.get(0).schemas.get(2).id, equalTo(42));
+ }
+
+ @Test
+ public void shouldWriteAvroconverter()
+ {
+ // GIVEN
+ String expectedJson =
+ "{" +
+ "\"view\":\"json\"," +
+ "\"model\":\"avro\"," +
+ "\"catalog\":" +
+ "{" +
+ "\"test0\":" +
+ "[" +
+ "{" +
+ "\"strategy\":\"topic\"," +
+ "\"version\":\"latest\"" +
+ "}," +
+ "{" +
+ "\"subject\":\"cat\"," +
+ "\"version\":\"latest\"" +
+ "}," +
+ "{" +
+ "\"id\":42" +
+ "}" +
+ "]" +
+ "}" +
+ "}";
+ AvroModelConfig converter = AvroModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .build()
+ .schema()
+ .subject("cat")
+ .version("latest")
+ .build()
+ .schema()
+ .id(42)
+ .build()
+ .build()
+ .build();
+
+ // WHEN
+ String json = jsonb.toJson(converter);
+
+ // THEN
+ assertThat(json, not(nullValue()));
+ assertThat(json, equalTo(expectedJson));
+ }
+}
diff --git a/incubator/validator-core.spec/COPYRIGHT b/incubator/model-core.spec/COPYRIGHT
similarity index 100%
rename from incubator/validator-core.spec/COPYRIGHT
rename to incubator/model-core.spec/COPYRIGHT
diff --git a/incubator/validator-core.spec/LICENSE b/incubator/model-core.spec/LICENSE
similarity index 100%
rename from incubator/validator-core.spec/LICENSE
rename to incubator/model-core.spec/LICENSE
diff --git a/incubator/validator-core.spec/NOTICE b/incubator/model-core.spec/NOTICE
similarity index 100%
rename from incubator/validator-core.spec/NOTICE
rename to incubator/model-core.spec/NOTICE
diff --git a/incubator/validator-core.spec/NOTICE.template b/incubator/model-core.spec/NOTICE.template
similarity index 100%
rename from incubator/validator-core.spec/NOTICE.template
rename to incubator/model-core.spec/NOTICE.template
diff --git a/incubator/validator-core.spec/mvnw b/incubator/model-core.spec/mvnw
similarity index 100%
rename from incubator/validator-core.spec/mvnw
rename to incubator/model-core.spec/mvnw
diff --git a/incubator/validator-core.spec/mvnw.cmd b/incubator/model-core.spec/mvnw.cmd
similarity index 100%
rename from incubator/validator-core.spec/mvnw.cmd
rename to incubator/model-core.spec/mvnw.cmd
diff --git a/incubator/validator-core.spec/pom.xml b/incubator/model-core.spec/pom.xml
similarity index 93%
rename from incubator/validator-core.spec/pom.xml
rename to incubator/model-core.spec/pom.xml
index ee32d6be74..a6d8437d3a 100644
--- a/incubator/validator-core.spec/pom.xml
+++ b/incubator/model-core.spec/pom.xml
@@ -8,12 +8,12 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
- validator-core.spec
- zilla::incubator::validator-core.spec
+ model-core.spec
+ zilla::incubator::model-core.spec
@@ -79,7 +79,7 @@
${project.version}
core
- io.aklivity.zilla.specs.validator.core.internal.types
+ io.aklivity.zilla.specs.model.core.internal.types
@@ -135,7 +135,7 @@
jacoco-maven-plugin
- io/aklivity/zilla/specs/validator/core/internal/types/**/*.class
+ io/aklivity/zilla/specs/model/core/internal/types/**/*.class
diff --git a/incubator/validator-core.spec/src/main/moditect/module-info.java b/incubator/model-core.spec/src/main/moditect/module-info.java
similarity index 92%
rename from incubator/validator-core.spec/src/main/moditect/module-info.java
rename to incubator/model-core.spec/src/main/moditect/module-info.java
index 89567c9647..71b092d9a6 100644
--- a/incubator/validator-core.spec/src/main/moditect/module-info.java
+++ b/incubator/model-core.spec/src/main/moditect/module-info.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-open module io.aklivity.zilla.specs.validator.core
+open module io.aklivity.zilla.specs.model.core
{
requires transitive io.aklivity.zilla.specs.engine;
}
diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.server.sent.flush/server.rpt b/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/config/string.model.yaml
similarity index 54%
rename from specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.server.sent.flush/server.rpt
rename to incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/config/string.model.yaml
index 4fae513f0c..83777f49cf 100644
--- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.server.sent.flush/server.rpt
+++ b/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/config/string.model.yaml
@@ -13,19 +13,14 @@
# specific language governing permissions and limitations under the License.
#
-accept "zilla://streams/mqtt0"
- option zilla:window 8192
- option zilla:transmission "duplex"
-accepted
-
-read zilla:begin.ext ${mqtt:matchBeginEx()
- .typeId(zilla:id("mqtt"))
- .publish()
- .clientId("client")
- .topic("sensor/one")
- .build()
- .build()}
-
-connected
-
-write advise zilla:flush
+---
+name: test
+bindings:
+ test:
+ kind: server
+ type: test
+ options:
+ value:
+ model: string
+ encoding: utf_8
+ exit: test
diff --git a/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/integer.schema.patch.json b/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/schema/integer.schema.patch.json
similarity index 50%
rename from incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/integer.schema.patch.json
rename to incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/schema/integer.schema.patch.json
index 4e671fa357..6f19753e68 100644
--- a/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/integer.schema.patch.json
+++ b/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/schema/integer.schema.patch.json
@@ -1,4 +1,9 @@
[
+ {
+ "op": "add",
+ "path": "/$defs/converter/types/enum/-",
+ "value": "integer"
+ },
{
"op": "add",
"path": "/$defs/validator/types/enum/-",
diff --git a/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/schema/string.schema.patch.json b/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/schema/string.schema.patch.json
new file mode 100644
index 0000000000..80ad373a2f
--- /dev/null
+++ b/incubator/model-core.spec/src/main/scripts/io/aklivity/zilla/specs/model/core/schema/string.schema.patch.json
@@ -0,0 +1,85 @@
+[
+ {
+ "op": "add",
+ "path": "/$defs/converter/types/enum/-",
+ "value": "string"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/converter/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "string"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "string"
+ },
+ "encoding":
+ {
+ "type": "string",
+ "enum":
+ [
+ "utf_8",
+ "utf_16"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ {
+ "op": "add",
+ "path": "/$defs/validator/types/enum/-",
+ "value": "string"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/validator/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "string"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "string"
+ },
+ "encoding":
+ {
+ "type": "string",
+ "enum":
+ [
+ "utf_8"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+]
diff --git a/incubator/model-core.spec/src/test/java/io/aklivity/zilla/specs/model/core/config/SchemaTest.java b/incubator/model-core.spec/src/test/java/io/aklivity/zilla/specs/model/core/config/SchemaTest.java
new file mode 100644
index 0000000000..e8895daca3
--- /dev/null
+++ b/incubator/model-core.spec/src/test/java/io/aklivity/zilla/specs/model/core/config/SchemaTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.specs.model.core.config;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import jakarta.json.JsonObject;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import io.aklivity.zilla.specs.engine.config.ConfigSchemaRule;
+
+public class SchemaTest
+{
+ @Rule
+ public final ConfigSchemaRule schema = new ConfigSchemaRule()
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/model/core/schema/string.schema.patch.json")
+ .configurationRoot("io/aklivity/zilla/specs/model/core/config");
+
+ @Test
+ public void shouldValidateCatalog()
+ {
+ JsonObject config = schema.validate("string.model.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+}
diff --git a/incubator/validator-core/COPYRIGHT b/incubator/model-core/COPYRIGHT
similarity index 100%
rename from incubator/validator-core/COPYRIGHT
rename to incubator/model-core/COPYRIGHT
diff --git a/incubator/validator-core/LICENSE b/incubator/model-core/LICENSE
similarity index 100%
rename from incubator/validator-core/LICENSE
rename to incubator/model-core/LICENSE
diff --git a/incubator/validator-core/NOTICE b/incubator/model-core/NOTICE
similarity index 100%
rename from incubator/validator-core/NOTICE
rename to incubator/model-core/NOTICE
diff --git a/incubator/validator-core/NOTICE.template b/incubator/model-core/NOTICE.template
similarity index 100%
rename from incubator/validator-core/NOTICE.template
rename to incubator/model-core/NOTICE.template
diff --git a/incubator/validator-core/mvnw b/incubator/model-core/mvnw
similarity index 100%
rename from incubator/validator-core/mvnw
rename to incubator/model-core/mvnw
diff --git a/incubator/validator-core/mvnw.cmd b/incubator/model-core/mvnw.cmd
similarity index 100%
rename from incubator/validator-core/mvnw.cmd
rename to incubator/model-core/mvnw.cmd
diff --git a/incubator/validator-core/pom.xml b/incubator/model-core/pom.xml
similarity index 87%
rename from incubator/validator-core/pom.xml
rename to incubator/model-core/pom.xml
index 22c385aed1..2adb8d1ee8 100644
--- a/incubator/validator-core/pom.xml
+++ b/incubator/model-core/pom.xml
@@ -8,12 +8,12 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
- validator-core
- zilla::incubator::validator-core
+ model-core
+ zilla::incubator::model-core
@@ -26,14 +26,14 @@
11
11
- 0.70
+ 0.83
0
${project.groupId}
- validator-core.spec
+ model-core.spec
${project.version}
provided
@@ -79,7 +79,7 @@
${project.version}
core
- io.aklivity.zilla.runtime.validator.core.internal.types
+ io.aklivity.zilla.runtime.model.core.internal.types
@@ -116,16 +116,16 @@
${project.groupId}
- validator-core.spec
+ model-core.spec
- ^\Qio/aklivity/zilla/specs/validator/core/\E
- io/aklivity/zilla/runtime/validator/core/
+ ^\Qio/aklivity/zilla/specs/model/core/\E
+ io/aklivity/zilla/runtime/model/core/internal/
- io/aklivity/zilla/specs/validator/core/schema/*.schema.patch.json
+ io/aklivity/zilla/specs/model/core/schema/*.schema.patch.json
${project.build.directory}/classes
@@ -155,7 +155,7 @@
jacoco-maven-plugin
- io/aklivity/zilla/runtime/validator/core/internal/types/**/*.class
+ io/aklivity/zilla/runtime/model/core/internal/types/**/*.class
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfig.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/IntegerModelConfig.java
similarity index 55%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfig.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/IntegerModelConfig.java
index 27a4400fb4..436a1f59ca 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfig.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/IntegerModelConfig.java
@@ -12,27 +12,27 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.config;
import java.util.function.Function;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
-public class IntegerValidatorConfig extends ValidatorConfig
+public class IntegerModelConfig extends ModelConfig
{
- public IntegerValidatorConfig()
+ public IntegerModelConfig()
{
super("integer");
}
- public static IntegerValidatorConfigBuilder builder(
- Function mapper)
+ public static IntegerModelConfigBuilder builder(
+ Function mapper)
{
- return new IntegerValidatorConfigBuilder<>(mapper::apply);
+ return new IntegerModelConfigBuilder<>(mapper::apply);
}
- public static IntegerValidatorConfigBuilder builder()
+ public static IntegerModelConfigBuilder builder()
{
- return new IntegerValidatorConfigBuilder<>(IntegerValidatorConfig.class::cast);
+ return new IntegerModelConfigBuilder<>(IntegerModelConfig.class::cast);
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigBuilder.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/IntegerModelConfigBuilder.java
similarity index 63%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigBuilder.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/IntegerModelConfigBuilder.java
index fc843c2da7..35f5061aec 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigBuilder.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/IntegerModelConfigBuilder.java
@@ -12,32 +12,32 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.config;
import java.util.function.Function;
import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
-public class LongValidatorConfigBuilder extends ConfigBuilder>
+public class IntegerModelConfigBuilder extends ConfigBuilder>
{
- private final Function mapper;
+ private final Function mapper;
- LongValidatorConfigBuilder(
- Function mapper)
+ IntegerModelConfigBuilder(
+ Function mapper)
{
this.mapper = mapper;
}
@Override
@SuppressWarnings("unchecked")
- protected Class> thisType()
+ protected Class> thisType()
{
- return (Class>) getClass();
+ return (Class>) getClass();
}
@Override
public T build()
{
- return mapper.apply(new LongValidatorConfig());
+ return mapper.apply(new IntegerModelConfig());
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfig.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringModelConfig.java
similarity index 61%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfig.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringModelConfig.java
index 7d2af19e7b..d18a80bc6d 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfig.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringModelConfig.java
@@ -12,33 +12,33 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.config;
import java.util.function.Function;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
-public final class StringValidatorConfig extends ValidatorConfig
+public final class StringModelConfig extends ModelConfig
{
public static final String DEFAULT_ENCODING = "utf_8";
public final String encoding;
- public StringValidatorConfig(
+ public StringModelConfig(
String encoding)
{
super("string");
this.encoding = encoding != null ? encoding : DEFAULT_ENCODING;
}
- public static StringValidatorConfigBuilder builder(
- Function mapper)
+ public static StringModelConfigBuilder builder(
+ Function mapper)
{
- return new StringValidatorConfigBuilder<>(mapper::apply);
+ return new StringModelConfigBuilder<>(mapper::apply);
}
- public static StringValidatorConfigBuilder builder()
+ public static StringModelConfigBuilder builder()
{
- return new StringValidatorConfigBuilder<>(StringValidatorConfig.class::cast);
+ return new StringModelConfigBuilder<>(StringModelConfig.class::cast);
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigBuilder.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringModelConfigBuilder.java
similarity index 63%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigBuilder.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringModelConfigBuilder.java
index ce700243eb..9ef65f5738 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigBuilder.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringModelConfigBuilder.java
@@ -12,32 +12,32 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.config;
import java.util.function.Function;
import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
-public class StringValidatorConfigBuilder extends ConfigBuilder>
+public class StringModelConfigBuilder extends ConfigBuilder>
{
- private final Function mapper;
+ private final Function mapper;
private String encoding;
- StringValidatorConfigBuilder(
- Function mapper)
+ StringModelConfigBuilder(
+ Function mapper)
{
this.mapper = mapper;
}
@Override
@SuppressWarnings("unchecked")
- protected Class> thisType()
+ protected Class> thisType()
{
- return (Class>) getClass();
+ return (Class>) getClass();
}
- public StringValidatorConfigBuilder encoding(
+ public StringModelConfigBuilder encoding(
String encoding)
{
this.encoding = encoding;
@@ -47,6 +47,6 @@ public StringValidatorConfigBuilder encoding(
@Override
public T build()
{
- return mapper.apply(new StringValidatorConfig(encoding));
+ return mapper.apply(new StringModelConfig(encoding));
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/LongValidator.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerConverterHandler.java
similarity index 51%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/LongValidator.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerConverterHandler.java
index dc9b4fd84b..2fb1f89880 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/LongValidator.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerConverterHandler.java
@@ -12,43 +12,35 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core;
+package io.aklivity.zilla.runtime.model.core.internal;
import org.agrona.DirectBuffer;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.core.config.LongValidatorConfig;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
-public class LongValidator implements Validator
+public class IntegerConverterHandler implements ConverterHandler
{
- public LongValidator(
- LongValidatorConfig config)
+ public IntegerConverterHandler(
+ IntegerModelConfig config)
{
}
@Override
- public boolean read(
+ public int convert(
DirectBuffer data,
int index,
- int length)
+ int length,
+ ValueConsumer next)
{
- return validate(data, index, length);
- }
+ boolean valid = length == 4;
- @Override
- public boolean write(
- DirectBuffer data,
- int index,
- int length)
- {
- return validate(data, index, length);
- }
+ if (valid)
+ {
+ next.accept(data, index, length);
+ }
- private boolean validate(
- DirectBuffer data,
- int index,
- int length)
- {
- return length == 8;
+ return valid ? length : -1;
}
}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModel.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModel.java
new file mode 100644
index 0000000000..58c214bafd
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import java.net.URL;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+
+public class IntegerModel implements Model
+{
+ public static final String NAME = "integer";
+
+ @Override
+ public String name()
+ {
+ return NAME;
+ }
+
+ @Override
+ public ModelContext supply(
+ EngineContext context)
+ {
+ return new IntegerModelContext(context);
+ }
+
+ @Override
+ public URL type()
+ {
+ return getClass().getResource("schema/integer.schema.patch.json");
+ }
+}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelContext.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelContext.java
new file mode 100644
index 0000000000..1320b7c7df
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelContext.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+
+public class IntegerModelContext implements ModelContext
+{
+ public IntegerModelContext(
+ EngineContext context)
+ {
+ }
+
+ @Override
+ public ConverterHandler supplyReadConverterHandler(
+ ModelConfig config)
+ {
+ return supply(config);
+ }
+
+ @Override
+ public ConverterHandler supplyWriteConverterHandler(
+ ModelConfig config)
+ {
+ return supply(config);
+ }
+
+ @Override
+ public ValidatorHandler supplyValidatorHandler(
+ ModelConfig config)
+ {
+ return new IntegerValidatorHandler(IntegerModelConfig.class.cast(config));
+ }
+
+ private IntegerConverterHandler supply(
+ ModelConfig config)
+ {
+ return new IntegerConverterHandler(IntegerModelConfig.class.cast(config));
+ }
+}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorFactory.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelFactorySpi.java
similarity index 52%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorFactory.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelFactorySpi.java
index da00c4fb58..1b50c0c260 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorFactory.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelFactorySpi.java
@@ -12,26 +12,22 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core;
+package io.aklivity.zilla.runtime.model.core.internal;
import java.net.URL;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
import io.aklivity.zilla.runtime.common.feature.Incubating;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi;
-import io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfig;
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelFactorySpi;
@Incubating
-public class IntegerValidatorFactory implements ValidatorFactorySpi
+public class IntegerModelFactorySpi implements ModelFactorySpi
{
@Override
public String type()
{
- return "integer";
+ return IntegerModel.NAME;
}
@Override
@@ -41,11 +37,9 @@ public URL schema()
}
@Override
- public Validator create(
- ValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
+ public Model create(
+ Configuration config)
{
- return new IntegerValidator(IntegerValidatorConfig.class.cast(config));
+ return new IntegerModel();
}
}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerValidatorHandler.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerValidatorHandler.java
new file mode 100644
index 0000000000..48dd67b542
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/IntegerValidatorHandler.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import org.agrona.DirectBuffer;
+
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+
+public class IntegerValidatorHandler implements ValidatorHandler
+{
+ private int pendingBytes;
+
+ public IntegerValidatorHandler(
+ IntegerModelConfig config)
+ {
+ }
+
+ @Override
+ public boolean validate(
+ int flags,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ boolean valid;
+
+ if ((flags & FLAGS_INIT) != 0x00)
+ {
+ pendingBytes = 4;
+ }
+
+ pendingBytes = pendingBytes - length;
+
+ if ((flags & FLAGS_FIN) != 0x00)
+ {
+ valid = pendingBytes == 0;
+ }
+ else
+ {
+ valid = pendingBytes >= 0;
+ }
+ return valid;
+ }
+}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringConverterHandler.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringConverterHandler.java
new file mode 100644
index 0000000000..4398a134a8
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringConverterHandler.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import org.agrona.DirectBuffer;
+
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+
+public class StringConverterHandler implements ConverterHandler
+{
+ private StringEncoding encoding;
+
+ public StringConverterHandler(
+ StringModelConfig config)
+ {
+ this.encoding = StringEncoding.of(config.encoding);
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+
+ if (encoding.validate(data, index, length))
+ {
+ next.accept(data, index, length);
+ valLength = length;
+ }
+
+ return valLength;
+ }
+}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringEncoding.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringEncoding.java
new file mode 100644
index 0000000000..d3fbda2281
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringEncoding.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import org.agrona.DirectBuffer;
+
+public enum StringEncoding
+{
+ UTF_8
+ {
+ @Override
+ public boolean validate(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ final int limit = index + length;
+ validate:
+ while (index < limit)
+ {
+ final int charByte0 = data.getByte(index);
+ final int charByteCount = (charByte0 & 0b1000_0000) != 0
+ ? Integer.numberOfLeadingZeros((~charByte0 & 0xff) << 24)
+ : 1;
+
+ final int charByteLimit = index + charByteCount;
+ for (int charByteIndex = index + 1; charByteIndex < charByteLimit; charByteIndex++)
+ {
+ if (charByteIndex >= limit || (data.getByte(charByteIndex) & 0b11000000) != 0b10000000)
+ {
+ break validate;
+ }
+ }
+ index += charByteCount;
+ }
+ return index == limit;
+ }
+ },
+
+ UTF_16
+ {
+ @Override
+ public boolean validate(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ final int limit = index + length;
+
+ while (index < limit)
+ {
+ if (index == limit - 1)
+ {
+ break;
+ }
+
+ int highByte = data.getByte(index) & 0xFF;
+ int lowByte = data.getByte(index + 1) & 0xFF;
+ int codeUnit = (highByte << 8) | lowByte;
+
+ if (codeUnit >= 0xD800 && codeUnit <= 0xDBFF)
+ {
+ if (index + 3 >= limit)
+ {
+ break;
+ }
+ int secondHighByte = data.getByte(index + 2) & 0xFF;
+ int secondLowByte = data.getByte(index + 3) & 0xFF;
+ int secondCodeUnit = (secondHighByte << 8) | secondLowByte;
+ if (secondCodeUnit < 0xDC00 || secondCodeUnit > 0xDFFF)
+ {
+ break;
+ }
+ index += 4;
+ }
+ else if (codeUnit >= 0xDC00 && codeUnit <= 0xDFFF)
+ {
+ break;
+ }
+ else
+ {
+ index += 2;
+ }
+ }
+ return index == limit;
+ }
+ };
+
+ public abstract boolean validate(
+ DirectBuffer data,
+ int index,
+ int length);
+
+ public static StringEncoding of(
+ String encoding)
+ {
+ switch (encoding)
+ {
+ case "utf_16":
+ return UTF_16;
+ default:
+ return UTF_8;
+ }
+ }
+}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModel.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModel.java
new file mode 100644
index 0000000000..ab456f1756
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import java.net.URL;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+
+public class StringModel implements Model
+{
+ public static final String NAME = "string";
+
+ @Override
+ public String name()
+ {
+ return NAME;
+ }
+
+ @Override
+ public ModelContext supply(
+ EngineContext context)
+ {
+ return new StringModelContext(context);
+ }
+
+ @Override
+ public URL type()
+ {
+ return getClass().getResource("schema/string.schema.patch.json");
+ }
+}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModelContext.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModelContext.java
new file mode 100644
index 0000000000..112d15d1e4
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModelContext.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+
+public class StringModelContext implements ModelContext
+{
+ public StringModelContext(
+ EngineContext context)
+ {
+ }
+
+ @Override
+ public ConverterHandler supplyReadConverterHandler(
+ ModelConfig config)
+ {
+ return supply(config);
+ }
+
+ @Override
+ public ConverterHandler supplyWriteConverterHandler(
+ ModelConfig config)
+ {
+ return supply(config);
+ }
+
+ @Override
+ public ValidatorHandler supplyValidatorHandler(
+ ModelConfig config)
+ {
+ return new StringValidatorHandler(StringModelConfig.class.cast(config));
+ }
+
+ private StringConverterHandler supply(
+ ModelConfig config)
+ {
+ return new StringConverterHandler(StringModelConfig.class.cast(config));
+ }
+}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/StringValidatorFactory.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModelFactorySpi.java
similarity index 54%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/StringValidatorFactory.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModelFactorySpi.java
index be226c7e35..5a0d547d33 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/StringValidatorFactory.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringModelFactorySpi.java
@@ -12,21 +12,17 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core;
+package io.aklivity.zilla.runtime.model.core.internal;
import java.net.URL;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
import io.aklivity.zilla.runtime.common.feature.Incubating;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi;
-import io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfig;
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelFactorySpi;
@Incubating
-public final class StringValidatorFactory implements ValidatorFactorySpi
+public final class StringModelFactorySpi implements ModelFactorySpi
{
@Override
public String type()
@@ -41,11 +37,11 @@ public URL schema()
}
@Override
- public Validator create(
- ValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
+ public Model create(
+ Configuration config)
{
- return new StringValidator(StringValidatorConfig.class.cast(config));
+ return new StringModel();
}
+
+
}
diff --git a/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorEncoding.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorEncoding.java
new file mode 100644
index 0000000000..801b67d841
--- /dev/null
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorEncoding.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static io.aklivity.zilla.runtime.engine.model.ValidatorHandler.FLAGS_FIN;
+import static io.aklivity.zilla.runtime.engine.model.ValidatorHandler.FLAGS_INIT;
+
+import org.agrona.DirectBuffer;
+
+public enum StringValidatorEncoding
+{
+ UTF_8
+ {
+ private int pendingCharBytes;
+
+ @Override
+ public boolean validate(
+ int flags,
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ if ((flags & FLAGS_INIT) != 0x00)
+ {
+ pendingCharBytes = 0;
+ }
+
+ final int limit = index + length;
+
+ while (index < limit)
+ {
+ final int charByte0 = data.getByte(index);
+
+ if (pendingCharBytes > 0)
+ {
+ if ((charByte0 & 0b11000000) != 0b10000000)
+ {
+ break;
+ }
+ pendingCharBytes--;
+ index++;
+ }
+ else
+ {
+ final int charByteCount = (charByte0 & 0b1000_0000) != 0
+ ? Integer.numberOfLeadingZeros((~charByte0 & 0xff) << 24)
+ : 1;
+ final int charByteLimit = index + charByteCount;
+ for (int charByteIndex = index + 1; charByteIndex < charByteLimit; charByteIndex++)
+ {
+ if (charByteIndex >= limit || (data.getByte(charByteIndex) & 0b11000000) != 0b10000000)
+ {
+ pendingCharBytes = charByteLimit - charByteIndex;
+ break;
+ }
+ }
+ index += pendingCharBytes == 0 ? charByteCount : pendingCharBytes;
+ }
+ }
+
+ return (flags & FLAGS_FIN) == 0x00
+ ? index == limit
+ : pendingCharBytes == 0 && index == limit;
+ }
+ };
+
+ public abstract boolean validate(
+ int flags,
+ DirectBuffer data,
+ int index,
+ int length);
+
+ public static StringValidatorEncoding of(
+ String encoding)
+ {
+ switch (encoding)
+ {
+ default:
+ return UTF_8;
+ }
+ }
+}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/IntegerValidator.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorHandler.java
similarity index 50%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/IntegerValidator.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorHandler.java
index 0d0fff271f..642a7aed50 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/IntegerValidator.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorHandler.java
@@ -12,42 +12,32 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core;
+package io.aklivity.zilla.runtime.model.core.internal;
import org.agrona.DirectBuffer;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfig;
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
-public class IntegerValidator implements Validator
+public class StringValidatorHandler implements ValidatorHandler
{
- public IntegerValidator(IntegerValidatorConfig config)
- {
- }
+ private final StringValidatorEncoding encoding;
- @Override
- public boolean read(
- DirectBuffer data,
- int index,
- int length)
+ public StringValidatorHandler(
+ StringModelConfig config)
{
- return validate(data, index, length);
+ this.encoding = StringValidatorEncoding.of(config.encoding);
}
@Override
- public boolean write(
- DirectBuffer data,
- int index,
- int length)
- {
- return validate(data, index, length);
- }
-
- private boolean validate(
+ public boolean validate(
+ int flags,
DirectBuffer data,
int index,
- int length)
+ int length,
+ ValueConsumer next)
{
- return length == 4;
+ return encoding.validate(flags, data, index, length);
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigAdapter.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/config/IntegerModelConfigAdapter.java
similarity index 66%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigAdapter.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/config/IntegerModelConfigAdapter.java
index 6a7927ff67..dc7638660f 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigAdapter.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/config/IntegerModelConfigAdapter.java
@@ -12,16 +12,17 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.internal.config;
import jakarta.json.Json;
import jakarta.json.JsonValue;
import jakarta.json.bind.adapter.JsonbAdapter;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
-public class IntegerValidatorConfigAdapter implements ValidatorConfigAdapterSpi, JsonbAdapter
+public class IntegerModelConfigAdapter implements ModelConfigAdapterSpi, JsonbAdapter
{
@Override
public String type()
@@ -31,15 +32,15 @@ public String type()
@Override
public JsonValue adaptToJson(
- ValidatorConfig options)
+ ModelConfig options)
{
return Json.createValue(type());
}
@Override
- public ValidatorConfig adaptFromJson(
+ public ModelConfig adaptFromJson(
JsonValue object)
{
- return new IntegerValidatorConfig();
+ return new IntegerModelConfig();
}
}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigAdapter.java b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/config/StringModelConfigAdapter.java
similarity index 63%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigAdapter.java
rename to incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/config/StringModelConfigAdapter.java
index 5536b28f2e..5265efecd9 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigAdapter.java
+++ b/incubator/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/internal/config/StringModelConfigAdapter.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.internal.config;
import jakarta.json.Json;
import jakarta.json.JsonObject;
@@ -21,26 +21,27 @@
import jakarta.json.JsonValue;
import jakarta.json.bind.adapter.JsonbAdapter;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
-public final class StringValidatorConfigAdapter implements ValidatorConfigAdapterSpi, JsonbAdapter
+public final class StringModelConfigAdapter implements ModelConfigAdapterSpi, JsonbAdapter
{
- private static final String TYPE_NAME = "type";
+ private static final String MODEL_NAME = "model";
private static final String ENCODING_NAME = "encoding";
@Override
public JsonValue adaptToJson(
- ValidatorConfig config)
+ ModelConfig config)
{
JsonValue result;
- String encoding = ((StringValidatorConfig) config).encoding;
- if (encoding != null && !encoding.isEmpty() && !encoding.equals(StringValidatorConfig.DEFAULT_ENCODING))
+ String encoding = ((StringModelConfig) config).encoding;
+ if (encoding != null && !encoding.isEmpty() && !encoding.equals(StringModelConfig.DEFAULT_ENCODING))
{
- JsonObjectBuilder validator = Json.createObjectBuilder();
- validator.add(TYPE_NAME, type());
- validator.add(ENCODING_NAME, encoding);
- result = validator.build();
+ JsonObjectBuilder converter = Json.createObjectBuilder();
+ converter.add(MODEL_NAME, type());
+ converter.add(ENCODING_NAME, encoding);
+ result = converter.build();
}
else
{
@@ -50,13 +51,13 @@ public JsonValue adaptToJson(
}
@Override
- public StringValidatorConfig adaptFromJson(
+ public StringModelConfig adaptFromJson(
JsonValue value)
{
- StringValidatorConfig result = null;
+ StringModelConfig result = null;
if (value instanceof JsonString)
{
- result = StringValidatorConfig.builder().build();
+ result = StringModelConfig.builder().build();
}
else if (value instanceof JsonObject)
{
@@ -64,7 +65,7 @@ else if (value instanceof JsonObject)
String encoding = object.containsKey(ENCODING_NAME)
? object.getString(ENCODING_NAME)
: null;
- result = new StringValidatorConfig(encoding);
+ result = new StringModelConfig(encoding);
}
else
{
diff --git a/incubator/model-core/src/main/moditect/module-info.java b/incubator/model-core/src/main/moditect/module-info.java
new file mode 100644
index 0000000000..e85c2b65f9
--- /dev/null
+++ b/incubator/model-core/src/main/moditect/module-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+module io.aklivity.zilla.runtime.model.core
+{
+ requires io.aklivity.zilla.runtime.engine;
+
+ exports io.aklivity.zilla.runtime.model.core.config;
+
+ provides io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
+ with io.aklivity.zilla.runtime.model.core.internal.config.IntegerModelConfigAdapter,
+ io.aklivity.zilla.runtime.model.core.internal.config.StringModelConfigAdapter;
+
+ provides io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
+ with io.aklivity.zilla.runtime.model.core.internal.IntegerModelFactorySpi,
+ io.aklivity.zilla.runtime.model.core.internal.StringModelFactorySpi;
+}
diff --git a/incubator/model-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi b/incubator/model-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
new file mode 100644
index 0000000000..b81e71d6a3
--- /dev/null
+++ b/incubator/model-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
@@ -0,0 +1,2 @@
+io.aklivity.zilla.runtime.model.core.internal.config.IntegerModelConfigAdapter
+io.aklivity.zilla.runtime.model.core.internal.config.StringModelConfigAdapter
diff --git a/incubator/model-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi b/incubator/model-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
new file mode 100644
index 0000000000..1d8a29a482
--- /dev/null
+++ b/incubator/model-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
@@ -0,0 +1,2 @@
+io.aklivity.zilla.runtime.model.core.internal.IntegerModelFactorySpi
+io.aklivity.zilla.runtime.model.core.internal.StringModelFactorySpi
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerConverterTest.java
similarity index 63%
rename from incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorTest.java
rename to incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerConverterTest.java
index 3f76925cfd..072a0b1cd5 100644
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorTest.java
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerConverterTest.java
@@ -12,21 +12,21 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core;
+package io.aklivity.zilla.runtime.model.core.internal;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import org.agrona.DirectBuffer;
import org.agrona.concurrent.UnsafeBuffer;
import org.junit.Test;
-import io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfig;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
-public class IntegerValidatorTest
+public class IntegerConverterTest
{
- private final IntegerValidatorConfig config = new IntegerValidatorConfig();
- private final IntegerValidator validator = new IntegerValidator(config);
+ private final IntegerModelConfig config = new IntegerModelConfig();
+ private final IntegerConverterHandler converter = new IntegerConverterHandler(config);
@Test
public void shouldVerifyValidInteger()
@@ -35,7 +35,7 @@ public void shouldVerifyValidInteger()
byte[] bytes = {0, 0, 0, 42};
data.wrap(bytes, 0, bytes.length);
- assertTrue(validator.read(data, 0, data.capacity()));
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
}
@Test
@@ -45,6 +45,6 @@ public void shouldVerifyInvalidInteger()
byte[] bytes = "Not an Integer".getBytes();
data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.write(data, 0, data.capacity()));
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
}
}
diff --git a/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelFactoryTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelFactoryTest.java
new file mode 100644
index 0000000000..385add14d1
--- /dev/null
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerModelFactoryTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ModelFactory;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+
+public class IntegerModelFactoryTest
+{
+ @Test
+ public void shouldCreateReader()
+ {
+ Configuration config = new Configuration();
+ ModelFactory factory = ModelFactory.instantiate();
+ Model model = factory.create("integer", config);
+
+ ModelContext context = new IntegerModelContext(mock(EngineContext.class));
+
+ ModelConfig modelConfig = IntegerModelConfig.builder().build();
+
+ assertThat(model, instanceOf(IntegerModel.class));
+ assertThat(context.supplyReadConverterHandler(modelConfig), instanceOf(IntegerConverterHandler.class));
+ assertThat(context.supplyWriteConverterHandler(modelConfig), instanceOf(IntegerConverterHandler.class));
+ assertThat(context.supplyValidatorHandler(modelConfig), instanceOf(IntegerValidatorHandler.class));
+ }
+}
diff --git a/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerValidatorTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerValidatorTest.java
new file mode 100644
index 0000000000..f3244ebb8f
--- /dev/null
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/IntegerValidatorTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+
+public class IntegerValidatorTest
+{
+ private final IntegerModelConfig config = IntegerModelConfig.builder().build();
+ private final IntegerValidatorHandler handler = new IntegerValidatorHandler(config);
+
+ @Test
+ public void shouldVerifyValidIntegerCompleteMessage()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0, 0, 0, 42};
+ data.wrap(bytes, 0, bytes.length);
+ assertTrue(handler.validate(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyValidIntegerFragmentedMessage()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0, 0, 0, 42};
+
+ data.wrap(bytes, 0, 2);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_INIT, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 2, 1);
+ assertTrue(handler.validate(0x00, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 3, 1);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_FIN, data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInvalidIntegerCompleteMessage()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Not an Integer".getBytes();
+ data.wrap(bytes, 0, bytes.length);
+ assertFalse(handler.validate(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInValidIntegerFragmentedMessage()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] firstFragment = {0, 0, 0};
+ data.wrap(firstFragment, 0, firstFragment.length);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_INIT, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ byte[] secondFragment = {0, 0};
+ data.wrap(secondFragment, 0, secondFragment.length);
+ assertFalse(handler.validate(0x00, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ byte[] finalFragment = {42};
+ data.wrap(finalFragment, 0, finalFragment.length);
+ assertFalse(handler.validate(ValidatorHandler.FLAGS_FIN, data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+}
diff --git a/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringConverterTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringConverterTest.java
new file mode 100644
index 0000000000..c9f93d1aea
--- /dev/null
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringConverterTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.charset.StandardCharsets;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+
+public class StringConverterTest
+{
+ @Test
+ public void shouldVerifyValidUtf8()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_8")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Valid String".getBytes();
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInvalidUtf8()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_8")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {(byte) 0xc0};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyValidUtf16()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_16")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Valid String".getBytes(StandardCharsets.UTF_16);
+ data.wrap(bytes, 0, bytes.length);
+
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyIncompleteUtf16()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_16")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x48};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyIncompleteSurrogatePairUtf16()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_16")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {(byte) 0xD8, (byte) 0x00};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInvalidSecondSurrogateUtf16()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_16")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {(byte) 0xDC, (byte) 0x01};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyUnexpectedSecondSurrogateUtf16()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_16")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {(byte) 0xDC, (byte) 0x80};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyValidMixedUtf16()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_16")
+ .build();
+ StringConverterHandler converter = new StringConverterHandler(config);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 65, 66, 67};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+}
diff --git a/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringEncodingTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringEncodingTest.java
new file mode 100644
index 0000000000..5ff69589ab
--- /dev/null
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringEncodingTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static io.aklivity.zilla.runtime.engine.model.ValidatorHandler.FLAGS_COMPLETE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.charset.StandardCharsets;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Test;
+
+public class StringEncodingTest
+{
+ @Test
+ public void shouldVerifyValidUTF8()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Valid String".getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ assertTrue(StringEncoding.UTF_8.validate(data, 0, bytes.length));
+
+ assertTrue(StringValidatorEncoding.UTF_8.validate(FLAGS_COMPLETE, data, 0, bytes.length));
+ }
+
+ @Test
+ public void shouldVerifyValidUTF16()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Valid String".getBytes(StandardCharsets.UTF_16);
+ data.wrap(bytes, 0, bytes.length);
+
+ assertTrue(StringEncoding.UTF_16.validate(data, 0, bytes.length));
+ }
+
+ @Test
+ public void shouldVerifyInvalidUTF16()
+ {
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {(byte) 0xD8, (byte) 0x00};
+ data.wrap(bytes, 0, bytes.length);
+
+ assertFalse(StringEncoding.UTF_16.validate(data, 0, bytes.length));
+ }
+
+ @Test
+ public void shouldVerifyStringEncodingOf()
+ {
+ assertEquals(StringEncoding.UTF_8, StringEncoding.of("utf_8"));
+ assertEquals(StringEncoding.UTF_16, StringEncoding.of("utf_16"));
+
+ assertEquals(StringValidatorEncoding.UTF_8, StringValidatorEncoding.of("utf_8"));
+ }
+}
diff --git a/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringModelFactoryTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringModelFactoryTest.java
new file mode 100644
index 0000000000..2913220059
--- /dev/null
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringModelFactoryTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ModelFactory;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+
+public class StringModelFactoryTest
+{
+ @Test
+ public void shouldCreateReader()
+ {
+ Configuration config = new Configuration();
+ ModelFactory factory = ModelFactory.instantiate();
+ Model model = factory.create("string", config);
+
+ ModelContext context = new StringModelContext(mock(EngineContext.class));
+
+ ModelConfig modelConfig = StringModelConfig.builder().encoding("utf_8").build();
+
+ assertThat(model, instanceOf(StringModel.class));
+ assertThat(context.supplyReadConverterHandler(modelConfig), instanceOf(StringConverterHandler.class));
+ assertThat(context.supplyWriteConverterHandler(modelConfig), instanceOf(StringConverterHandler.class));
+ assertThat(context.supplyValidatorHandler(modelConfig), instanceOf(StringValidatorHandler.class));
+ }
+}
diff --git a/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorTest.java
new file mode 100644
index 0000000000..34db2cc059
--- /dev/null
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/StringValidatorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.core.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+
+public class StringValidatorTest
+{
+ @Test
+ public void shouldVerifyValidUtf8()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_8")
+ .build();
+ StringValidatorHandler handler = new StringValidatorHandler(config);
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Valid String".getBytes();
+ data.wrap(bytes, 0, bytes.length);
+ assertTrue(handler.validate(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyFragmentedValidUtf8()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_8")
+ .build();
+ StringValidatorHandler handler = new StringValidatorHandler(config);
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = "Valid String".getBytes();
+
+ data.wrap(bytes, 0, 6);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_INIT, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 6, 5);
+ assertTrue(handler.validate(0x00, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 11, 1);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_FIN, data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyFragmentedInValidUtf8()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_8")
+ .build();
+ StringValidatorHandler handler = new StringValidatorHandler(config);
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {
+ (byte) 'S', (byte) 't', (byte) 'r', (byte) 'i', (byte) 'n', (byte) 'g',
+ (byte) 0xc0, (byte) 'V', (byte) 'a', (byte) 'l', (byte) 'i',
+ (byte) 'd'
+ };
+
+ data.wrap(bytes, 0, 6);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_INIT, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 6, 5);
+ assertFalse(handler.validate(0x00, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 11, 1);
+ assertFalse(handler.validate(ValidatorHandler.FLAGS_FIN, data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyWithPendingCharBytes()
+ {
+ StringModelConfig config = StringModelConfig.builder()
+ .encoding("utf_8")
+ .build();
+ StringValidatorHandler handler = new StringValidatorHandler(config);
+ UnsafeBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {(byte) 0xc3, (byte) 0xa4};
+
+ data.wrap(bytes, 0, 1);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_INIT, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ data.wrap(bytes, 1, 1);
+ assertTrue(handler.validate(ValidatorHandler.FLAGS_FIN, data, 0, data.capacity(), ValueConsumer.NOP));
+
+ }
+}
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigAdapterTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/IntegerModelConfigAdapterTest.java
similarity index 67%
rename from incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigAdapterTest.java
rename to incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/IntegerModelConfigAdapterTest.java
index da6befc886..384e75c76b 100644
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigAdapterTest.java
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/IntegerModelConfigAdapterTest.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.internal.config;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@@ -26,7 +26,9 @@
import org.junit.Before;
import org.junit.Test;
-public class IntegerValidatorConfigAdapterTest
+import io.aklivity.zilla.runtime.model.core.config.IntegerModelConfig;
+
+public class IntegerModelConfigAdapterTest
{
private Jsonb jsonb;
@@ -34,36 +36,36 @@ public class IntegerValidatorConfigAdapterTest
public void initJson()
{
JsonbConfig config = new JsonbConfig()
- .withAdapters(new IntegerValidatorConfigAdapter());
+ .withAdapters(new IntegerModelConfigAdapter());
jsonb = JsonbBuilder.create(config);
}
@Test
- public void shouldReadIntegerValidator()
+ public void shouldReadIntegerconverter()
{
// GIVEN
String json =
"{" +
- "\"type\": \"integer\"" +
+ "\"model\": \"integer\"" +
"}";
// WHEN
- IntegerValidatorConfig validator = jsonb.fromJson(json, IntegerValidatorConfig.class);
+ IntegerModelConfig converter = jsonb.fromJson(json, IntegerModelConfig.class);
// THEN
- assertThat(validator, not(nullValue()));
- assertThat(validator.type, equalTo("integer"));
+ assertThat(converter, not(nullValue()));
+ assertThat(converter.model, equalTo("integer"));
}
@Test
- public void shouldWriteIntegerValidator()
+ public void shouldWriteIntegerconverter()
{
// GIVEN
String expectedJson = "\"integer\"";
- IntegerValidatorConfig validator = IntegerValidatorConfig.builder().build();
+ IntegerModelConfig converter = IntegerModelConfig.builder().build();
// WHEN
- String json = jsonb.toJson(validator);
+ String json = jsonb.toJson(converter);
// THEN
assertThat(json, not(nullValue()));
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigAdapterTest.java b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/StringModelConfigAdapterTest.java
similarity index 66%
rename from incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigAdapterTest.java
rename to incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/StringModelConfigAdapterTest.java
index 89ab178016..a05af5433c 100644
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/StringValidatorConfigAdapterTest.java
+++ b/incubator/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/StringModelConfigAdapterTest.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.core.internal.config;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@@ -26,7 +26,9 @@
import org.junit.Before;
import org.junit.Test;
-public class StringValidatorConfigAdapterTest
+import io.aklivity.zilla.runtime.model.core.config.StringModelConfig;
+
+public class StringModelConfigAdapterTest
{
private Jsonb jsonb;
@@ -34,38 +36,38 @@ public class StringValidatorConfigAdapterTest
public void initJson()
{
JsonbConfig config = new JsonbConfig()
- .withAdapters(new StringValidatorConfigAdapter());
+ .withAdapters(new StringModelConfigAdapter());
jsonb = JsonbBuilder.create(config);
}
@Test
- public void shouldReadStringValidator()
+ public void shouldReadStringconverter()
{
// GIVEN
String json =
"{" +
- "\"type\": \"string\"," +
+ "\"model\": \"string\"," +
"\"encoding\": \"utf_8\"" +
"}";
// WHEN
- StringValidatorConfig validator = jsonb.fromJson(json, StringValidatorConfig.class);
+ StringModelConfig model = jsonb.fromJson(json, StringModelConfig.class);
// THEN
- assertThat(validator, not(nullValue()));
- assertThat(validator.type, equalTo("string"));
- assertThat(validator.encoding, equalTo("utf_8"));
+ assertThat(model, not(nullValue()));
+ assertThat(model.model, equalTo("string"));
+ assertThat(model.encoding, equalTo("utf_8"));
}
@Test
- public void shouldWriteDefaultEncodingStringValidator()
+ public void shouldWriteDefaultEncodingStringconverter()
{
// GIVEN
String expectedJson = "\"string\"";
- StringValidatorConfig validator = StringValidatorConfig.builder().build();
+ StringModelConfig converter = StringModelConfig.builder().build();
// WHEN
- String json = jsonb.toJson(validator);
+ String json = jsonb.toJson(converter);
// THEN
assertThat(json, not(nullValue()));
@@ -73,20 +75,20 @@ public void shouldWriteDefaultEncodingStringValidator()
}
@Test
- public void shouldWriteStringValidator()
+ public void shouldWriteStringconverter()
{
// GIVEN
String expectedJson =
"{" +
- "\"type\":\"string\"," +
+ "\"model\":\"string\"," +
"\"encoding\":\"utf_16\"" +
"}";
- StringValidatorConfig validator = StringValidatorConfig.builder()
+ StringModelConfig model = StringModelConfig.builder()
.encoding("utf_16")
.build();
// WHEN
- String json = jsonb.toJson(validator);
+ String json = jsonb.toJson(model);
// THEN
assertThat(json, not(nullValue()));
diff --git a/incubator/validator-json.spec/COPYRIGHT b/incubator/model-json.spec/COPYRIGHT
similarity index 100%
rename from incubator/validator-json.spec/COPYRIGHT
rename to incubator/model-json.spec/COPYRIGHT
diff --git a/incubator/validator-json.spec/LICENSE b/incubator/model-json.spec/LICENSE
similarity index 100%
rename from incubator/validator-json.spec/LICENSE
rename to incubator/model-json.spec/LICENSE
diff --git a/incubator/validator-json.spec/NOTICE b/incubator/model-json.spec/NOTICE
similarity index 100%
rename from incubator/validator-json.spec/NOTICE
rename to incubator/model-json.spec/NOTICE
diff --git a/incubator/validator-json.spec/NOTICE.template b/incubator/model-json.spec/NOTICE.template
similarity index 100%
rename from incubator/validator-json.spec/NOTICE.template
rename to incubator/model-json.spec/NOTICE.template
diff --git a/incubator/validator-json.spec/mvnw b/incubator/model-json.spec/mvnw
similarity index 100%
rename from incubator/validator-json.spec/mvnw
rename to incubator/model-json.spec/mvnw
diff --git a/incubator/validator-json.spec/mvnw.cmd b/incubator/model-json.spec/mvnw.cmd
similarity index 100%
rename from incubator/validator-json.spec/mvnw.cmd
rename to incubator/model-json.spec/mvnw.cmd
diff --git a/incubator/validator-json.spec/pom.xml b/incubator/model-json.spec/pom.xml
similarity index 96%
rename from incubator/validator-json.spec/pom.xml
rename to incubator/model-json.spec/pom.xml
index f66dd0bef5..ca5acf9951 100644
--- a/incubator/validator-json.spec/pom.xml
+++ b/incubator/model-json.spec/pom.xml
@@ -8,12 +8,12 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
-validator-json.spec
-zilla::incubator::validator-json.spec
+model-json.spec
+zilla::incubator::model-json.spec
diff --git a/incubator/validator-json.spec/src/main/moditect/module-info.java b/incubator/model-json.spec/src/main/moditect/module-info.java
similarity index 92%
rename from incubator/validator-json.spec/src/main/moditect/module-info.java
rename to incubator/model-json.spec/src/main/moditect/module-info.java
index 08a27de593..a93c2004e4 100644
--- a/incubator/validator-json.spec/src/main/moditect/module-info.java
+++ b/incubator/model-json.spec/src/main/moditect/module-info.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-open module io.aklivity.zilla.specs.validator.json
+open module io.aklivity.zilla.specs.model.json
{
requires transitive io.aklivity.zilla.specs.engine;
}
diff --git a/incubator/model-json.spec/src/main/scripts/io/aklivity/zilla/specs/model/json/config/model.yaml b/incubator/model-json.spec/src/main/scripts/io/aklivity/zilla/specs/model/json/config/model.yaml
new file mode 100644
index 0000000000..bffde5db5b
--- /dev/null
+++ b/incubator/model-json.spec/src/main/scripts/io/aklivity/zilla/specs/model/json/config/model.yaml
@@ -0,0 +1,49 @@
+#
+# Copyright 2021-2023 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+---
+name: test
+catalogs:
+ test0:
+ type: test
+ options:
+ schema: |
+ {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "status"
+ ]
+ }
+bindings:
+ test:
+ kind: server
+ type: test
+ options:
+ value:
+ model: json
+ catalog:
+ catalog0:
+ - subject: test0
+ version: latest
+ exit: test
diff --git a/incubator/model-json.spec/src/main/scripts/io/aklivity/zilla/specs/model/json/schema/json.schema.patch.json b/incubator/model-json.spec/src/main/scripts/io/aklivity/zilla/specs/model/json/schema/json.schema.patch.json
new file mode 100644
index 0000000000..b9469bc6dc
--- /dev/null
+++ b/incubator/model-json.spec/src/main/scripts/io/aklivity/zilla/specs/model/json/schema/json.schema.patch.json
@@ -0,0 +1,254 @@
+[
+ {
+ "op": "add",
+ "path": "/$defs/converter/types/enum/-",
+ "value": "json"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/converter/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "json"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "json"
+ },
+ "catalog":
+ {
+ "type": "object",
+ "patternProperties":
+ {
+ "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$":
+ {
+ "type": "array",
+ "items":
+ {
+ "oneOf":
+ [
+ {
+ "type": "object",
+ "properties":
+ {
+ "id":
+ {
+ "type": "integer"
+ }
+ },
+ "required":
+ [
+ "id"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "schema":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "schema"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "strategy":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "strategy"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "subject":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "subject"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ }
+ },
+ "maxProperties": 1
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ {
+ "op": "add",
+ "path": "/$defs/validator/types/enum/-",
+ "value": "json"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/validator/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "json"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "json"
+ },
+ "catalog":
+ {
+ "type": "object",
+ "patternProperties":
+ {
+ "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$":
+ {
+ "type": "array",
+ "items":
+ {
+ "oneOf":
+ [
+ {
+ "type": "object",
+ "properties":
+ {
+ "id":
+ {
+ "type": "integer"
+ }
+ },
+ "required":
+ [
+ "id"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "schema":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "schema"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "strategy":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "strategy"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "subject":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ }
+ },
+ "required":
+ [
+ "subject"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ }
+ },
+ "maxProperties": 1
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+]
diff --git a/incubator/model-json.spec/src/test/java/io/aklivity/zilla/specs/model/json/config/SchemaTest.java b/incubator/model-json.spec/src/test/java/io/aklivity/zilla/specs/model/json/config/SchemaTest.java
new file mode 100644
index 0000000000..2d0ad426ba
--- /dev/null
+++ b/incubator/model-json.spec/src/test/java/io/aklivity/zilla/specs/model/json/config/SchemaTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.specs.model.json.config;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import jakarta.json.JsonObject;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import io.aklivity.zilla.specs.engine.config.ConfigSchemaRule;
+
+public class SchemaTest
+{
+ @Rule
+ public final ConfigSchemaRule schema = new ConfigSchemaRule()
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/catalog/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/model/json/schema/json.schema.patch.json")
+ .configurationRoot("io/aklivity/zilla/specs/model/json/config");
+
+ @Test
+ public void shouldValidateCatalog()
+ {
+ JsonObject config = schema.validate("model.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+}
diff --git a/incubator/validator-json/COPYRIGHT b/incubator/model-json/COPYRIGHT
similarity index 100%
rename from incubator/validator-json/COPYRIGHT
rename to incubator/model-json/COPYRIGHT
diff --git a/incubator/validator-json/LICENSE b/incubator/model-json/LICENSE
similarity index 100%
rename from incubator/validator-json/LICENSE
rename to incubator/model-json/LICENSE
diff --git a/incubator/validator-json/NOTICE b/incubator/model-json/NOTICE
similarity index 100%
rename from incubator/validator-json/NOTICE
rename to incubator/model-json/NOTICE
diff --git a/incubator/validator-json/NOTICE.template b/incubator/model-json/NOTICE.template
similarity index 100%
rename from incubator/validator-json/NOTICE.template
rename to incubator/model-json/NOTICE.template
diff --git a/incubator/validator-json/mvnw b/incubator/model-json/mvnw
similarity index 100%
rename from incubator/validator-json/mvnw
rename to incubator/model-json/mvnw
diff --git a/incubator/validator-json/mvnw.cmd b/incubator/model-json/mvnw.cmd
similarity index 100%
rename from incubator/validator-json/mvnw.cmd
rename to incubator/model-json/mvnw.cmd
diff --git a/incubator/validator-json/pom.xml b/incubator/model-json/pom.xml
similarity index 92%
rename from incubator/validator-json/pom.xml
rename to incubator/model-json/pom.xml
index 903912d79c..089e968930 100644
--- a/incubator/validator-json/pom.xml
+++ b/incubator/model-json/pom.xml
@@ -6,12 +6,12 @@
io.aklivity.zilla
incubator
- 0.9.66
+ 0.9.67
../pom.xml
-validator-json
-zilla::incubator::validator-json
+model-json
+zilla::incubator::model-json
@@ -24,14 +24,14 @@
11
11
- 0.83
+ 0.90
0
${project.groupId}
- validator-json.spec
+ model-json.spec
${project.version}
provided
@@ -98,16 +98,16 @@
${project.groupId}
- validator-json.spec
+ model-json.spec
- ^\Qio/aklivity/zilla/specs/validator/json/\E
- io/aklivity/zilla/runtime/validator/json/
+ ^\Qio/aklivity/zilla/specs/model/json/\E
+ io/aklivity/zilla/runtime/model/json/internal/
- io/aklivity/zilla/specs/validator/json/schema/json.schema.patch.json
+ io/aklivity/zilla/specs/model/json/schema/json.schema.patch.json
${project.build.directory}/classes
diff --git a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfig.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/config/JsonModelConfig.java
similarity index 52%
rename from incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfig.java
rename to incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/config/JsonModelConfig.java
index 97821ad23b..b2dbbcfb23 100644
--- a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfig.java
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/config/JsonModelConfig.java
@@ -12,33 +12,34 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.json.config;
+package io.aklivity.zilla.runtime.model.json.config;
import java.util.List;
import java.util.function.Function;
import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
-public final class JsonValidatorConfig extends ValidatorConfig
+public final class JsonModelConfig extends ModelConfig
{
- public final List catalogs;
+ public final String subject;
- JsonValidatorConfig(
- List catalogs)
+ public JsonModelConfig(
+ List cataloged,
+ String subject)
{
- super("json");
- this.catalogs = catalogs;
+ super("json", cataloged);
+ this.subject = subject;
}
- public static JsonValidatorConfigBuilder builder(
- Function mapper)
+ public static JsonModelConfigBuilder builder(
+ Function mapper)
{
- return new JsonValidatorConfigBuilder<>(mapper::apply);
+ return new JsonModelConfigBuilder<>(mapper::apply);
}
- public static JsonValidatorConfigBuilder builder()
+ public static JsonModelConfigBuilder builder()
{
- return new JsonValidatorConfigBuilder<>(JsonValidatorConfig.class::cast);
+ return new JsonModelConfigBuilder<>(JsonModelConfig.class::cast);
}
}
diff --git a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigBuilder.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/config/JsonModelConfigBuilder.java
similarity index 68%
rename from incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigBuilder.java
rename to incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/config/JsonModelConfigBuilder.java
index 5951a68d7b..ea7e7bc99c 100644
--- a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigBuilder.java
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/config/JsonModelConfigBuilder.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.avro.config;
+package io.aklivity.zilla.runtime.model.json.config;
import java.util.LinkedList;
import java.util.List;
@@ -22,39 +22,39 @@
import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder;
import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
-public class AvroValidatorConfigBuilder extends ConfigBuilder>
+public class JsonModelConfigBuilder extends ConfigBuilder>
{
- private final Function mapper;
+ private final Function mapper;
private List catalogs;
private String subject;
- AvroValidatorConfigBuilder(
- Function mapper)
+ JsonModelConfigBuilder(
+ Function mapper)
{
this.mapper = mapper;
}
@Override
@SuppressWarnings("unchecked")
- protected Class> thisType()
+ protected Class> thisType()
{
- return (Class>) getClass();
+ return (Class>) getClass();
}
- public AvroValidatorConfigBuilder subject(
- String subject)
+ public CatalogedConfigBuilder> catalog()
{
- this.subject = subject;
- return this;
+ return CatalogedConfig.builder(this::catalog);
}
- public CatalogedConfigBuilder> catalog()
+ public JsonModelConfigBuilder subject(
+ String subject)
{
- return CatalogedConfig.builder(this::catalog);
+ this.subject = subject;
+ return this;
}
- public AvroValidatorConfigBuilder catalog(
+ public JsonModelConfigBuilder catalog(
CatalogedConfig catalog)
{
if (catalogs == null)
@@ -68,6 +68,6 @@ public AvroValidatorConfigBuilder catalog(
@Override
public T build()
{
- return mapper.apply(new AvroValidatorConfig(catalogs, subject));
+ return mapper.apply(new JsonModelConfig(catalogs, subject));
}
}
diff --git a/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModel.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModel.java
new file mode 100644
index 0000000000..4d0ac6d9a8
--- /dev/null
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import java.net.URL;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+
+public class JsonModel implements Model
+{
+ public static final String NAME = "json";
+
+ @Override
+ public String name()
+ {
+ return NAME;
+ }
+
+ @Override
+ public ModelContext supply(
+ EngineContext context)
+ {
+ return new JsonModelContext(context);
+ }
+
+ @Override
+ public URL type()
+ {
+ return getClass().getResource("schema/json.schema.patch.json");
+ }
+}
diff --git a/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelContext.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelContext.java
new file mode 100644
index 0000000000..ac77d3e9b7
--- /dev/null
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelContext.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import java.util.function.LongFunction;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonModelContext implements ModelContext
+{
+ private final LongFunction supplyCatalog;
+
+ public JsonModelContext(EngineContext context)
+ {
+ this.supplyCatalog = context::supplyCatalog;
+ }
+
+ @Override
+ public ConverterHandler supplyReadConverterHandler(
+ ModelConfig config)
+ {
+ return new JsonReadConverterHandler(JsonModelConfig.class.cast(config), supplyCatalog);
+ }
+
+ @Override
+ public ConverterHandler supplyWriteConverterHandler(
+ ModelConfig config)
+ {
+ return new JsonWriteConverterHandler(JsonModelConfig.class.cast(config), supplyCatalog);
+ }
+
+ @Override
+ public ValidatorHandler supplyValidatorHandler(
+ ModelConfig config)
+ {
+ return new JsonValidatorHandler(JsonModelConfig.class.cast(config), supplyCatalog);
+ }
+}
diff --git a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorFactory.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelFactorySpi.java
similarity index 51%
rename from incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorFactory.java
rename to incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelFactorySpi.java
index 9d8372b195..86795f2064 100644
--- a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorFactory.java
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelFactorySpi.java
@@ -12,26 +12,22 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.json;
+package io.aklivity.zilla.runtime.model.json.internal;
import java.net.URL;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
import io.aklivity.zilla.runtime.common.feature.Incubating;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelFactorySpi;
@Incubating
-public final class JsonValidatorFactory implements ValidatorFactorySpi
+public final class JsonModelFactorySpi implements ModelFactorySpi
{
@Override
public String type()
{
- return "json";
+ return JsonModel.NAME;
}
public URL schema()
@@ -40,11 +36,9 @@ public URL schema()
}
@Override
- public Validator create(
- ValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
+ public Model create(
+ Configuration config)
{
- return new JsonValidator(JsonValidatorConfig.class.cast(config), resolveId, supplyCatalog);
+ return new JsonModel();
}
}
diff --git a/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelHandler.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelHandler.java
new file mode 100644
index 0000000000..e86b7dfb3c
--- /dev/null
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelHandler.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import java.io.StringReader;
+import java.util.function.LongFunction;
+
+import jakarta.json.spi.JsonProvider;
+import jakarta.json.stream.JsonParser;
+import jakarta.json.stream.JsonParserFactory;
+
+import org.agrona.DirectBuffer;
+import org.agrona.collections.Int2ObjectCache;
+import org.agrona.io.DirectBufferInputStream;
+import org.leadpony.justify.api.JsonSchema;
+import org.leadpony.justify.api.JsonSchemaReader;
+import org.leadpony.justify.api.JsonValidatingException;
+import org.leadpony.justify.api.JsonValidationService;
+import org.leadpony.justify.api.ProblemHandler;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public abstract class JsonModelHandler
+{
+ protected final SchemaConfig catalog;
+ protected final CatalogHandler handler;
+ protected final String subject;
+
+ private final Int2ObjectCache schemas;
+ private final Int2ObjectCache providers;
+ private final JsonProvider schemaProvider;
+ private final JsonValidationService service;
+ private final JsonParserFactory factory;
+ private DirectBufferInputStream in;
+
+ public JsonModelHandler(
+ JsonModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ this.schemaProvider = JsonProvider.provider();
+ this.service = JsonValidationService.newInstance();
+ this.factory = schemaProvider.createParserFactory(null);
+ CatalogedConfig cataloged = config.cataloged.get(0);
+ this.catalog = cataloged.schemas.size() != 0 ? cataloged.schemas.get(0) : null;
+ this.handler = supplyCatalog.apply(cataloged.id);
+ this.subject = catalog != null && catalog.subject != null
+ ? catalog.subject
+ : config.subject;
+ this.schemas = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.providers = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.in = new DirectBufferInputStream();
+ }
+
+ protected final boolean validate(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ boolean status = false;
+ try
+ {
+ JsonProvider provider = supplyProvider(schemaId);
+ in.wrap(buffer, index, length);
+ provider.createReader(in).readValue();
+ status = true;
+ }
+ catch (JsonValidatingException ex)
+ {
+ ex.printStackTrace();
+ }
+ return status;
+ }
+
+ protected JsonProvider supplyProvider(
+ int schemaId)
+ {
+ return providers.computeIfAbsent(schemaId, this::createProvider);
+ }
+
+ private JsonSchema supplySchema(
+ int schemaId)
+ {
+ return schemas.computeIfAbsent(schemaId, this::resolveSchema);
+ }
+
+ private JsonSchema resolveSchema(
+ int schemaId)
+ {
+ JsonSchema schema = null;
+ String schemaText = handler.resolve(schemaId);
+ if (schemaText != null)
+ {
+ JsonParser schemaParser = factory.createParser(new StringReader(schemaText));
+ JsonSchemaReader reader = service.createSchemaReader(schemaParser);
+ schema = reader.read();
+ }
+
+ return schema;
+ }
+
+ private JsonProvider createProvider(
+ int schemaId)
+ {
+ JsonSchema schema = supplySchema(schemaId);
+ JsonProvider provider = null;
+ if (schema != null)
+ {
+ provider = service.createJsonProvider(schema, parser -> ProblemHandler.throwing());
+ }
+ return provider;
+ }
+}
diff --git a/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonReadConverterHandler.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonReadConverterHandler.java
new file mode 100644
index 0000000000..ad62353542
--- /dev/null
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonReadConverterHandler.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import static io.aklivity.zilla.runtime.engine.catalog.CatalogHandler.NO_SCHEMA_ID;
+
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonReadConverterHandler extends JsonModelHandler implements ConverterHandler
+{
+ public JsonReadConverterHandler(
+ JsonModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ return handler.decode(data, index, length, next, this::decodePayload);
+ }
+
+ private int decodePayload(
+ int schemaId,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+
+ if (schemaId == NO_SCHEMA_ID)
+ {
+ if (catalog.id != NO_SCHEMA_ID)
+ {
+ schemaId = catalog.id;
+ }
+ else
+ {
+ schemaId = handler.resolve(subject, catalog.version);
+ }
+ }
+
+ if (validate(schemaId, data, index, length))
+ {
+ next.accept(data, index, length);
+ valLength = length;
+ }
+ return valLength;
+ }
+}
diff --git a/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonValidatorHandler.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonValidatorHandler.java
new file mode 100644
index 0000000000..994601abc4
--- /dev/null
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonValidatorHandler.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import java.util.function.LongFunction;
+
+import jakarta.json.spi.JsonProvider;
+import jakarta.json.stream.JsonParser;
+import jakarta.json.stream.JsonParsingException;
+
+import org.agrona.DirectBuffer;
+import org.agrona.ExpandableDirectByteBuffer;
+import org.agrona.io.DirectBufferInputStream;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ValidatorHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonValidatorHandler extends JsonModelHandler implements ValidatorHandler
+{
+ private final DirectBufferInputStream in;
+ private final ExpandableDirectByteBuffer buffer;
+
+ private JsonParser parser;
+ private int progress;
+
+ public JsonValidatorHandler(
+ JsonModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ this.buffer = new ExpandableDirectByteBuffer();
+ this.in = new DirectBufferInputStream(buffer);
+ }
+
+ @Override
+ public boolean validate(
+ int flags,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ boolean status = true;
+
+ try
+ {
+ if ((flags & FLAGS_INIT) != 0x00)
+ {
+ this.progress = 0;
+ }
+
+ buffer.putBytes(progress, data, index, length);
+ progress += length;
+
+ if ((flags & FLAGS_FIN) != 0x00)
+ {
+ in.wrap(buffer, 0, progress);
+
+ int schemaId = catalog != null && catalog.id > 0
+ ? catalog.id
+ : handler.resolve(subject, catalog.version);
+
+ JsonProvider provider = supplyProvider(schemaId);
+ parser = provider.createParser(in);
+ while (parser.hasNext())
+ {
+ parser.next();
+ }
+ }
+ }
+ catch (JsonParsingException ex)
+ {
+ status = false;
+ ex.printStackTrace();
+ }
+
+ return status;
+ }
+}
diff --git a/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonWriteConverterHandler.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonWriteConverterHandler.java
new file mode 100644
index 0000000000..9286f1eba2
--- /dev/null
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/JsonWriteConverterHandler.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonWriteConverterHandler extends JsonModelHandler implements ConverterHandler
+{
+ public JsonWriteConverterHandler(
+ JsonModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ }
+
+ @Override
+ public int padding(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ return handler.encodePadding();
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+
+ int schemaId = catalog != null && catalog.id > 0
+ ? catalog.id
+ : handler.resolve(subject, catalog.version);
+
+ if (validate(schemaId, data, index, length))
+ {
+ valLength = handler.encode(schemaId, data, index, length, next, CatalogHandler.Encoder.IDENTITY);
+ }
+ return valLength;
+ }
+}
diff --git a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigAdapter.java b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/config/JsonModelConfigAdapter.java
similarity index 51%
rename from incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigAdapter.java
rename to incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/config/JsonModelConfigAdapter.java
index 24ffeabdec..fd38445239 100644
--- a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigAdapter.java
+++ b/incubator/model-json/src/main/java/io/aklivity/zilla/runtime/model/json/internal/config/JsonModelConfigAdapter.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.json.config;
+package io.aklivity.zilla.runtime.model.json.internal.config;
import java.util.LinkedList;
import java.util.List;
@@ -26,16 +26,18 @@
import jakarta.json.bind.adapter.JsonbAdapter;
import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi;
import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
import io.aklivity.zilla.runtime.engine.config.SchemaConfigAdapter;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
-public final class JsonValidatorConfigAdapter implements ValidatorConfigAdapterSpi, JsonbAdapter
+public final class JsonModelConfigAdapter implements ModelConfigAdapterSpi, JsonbAdapter
{
private static final String JSON = "json";
- private static final String TYPE_NAME = "type";
+ private static final String MODEL_NAME = "model";
private static final String CATALOG_NAME = "catalog";
+ private static final String SUBJECT_NAME = "subject";
private final SchemaConfigAdapter schema = new SchemaConfigAdapter();
@@ -47,15 +49,15 @@ public String type()
@Override
public JsonValue adaptToJson(
- ValidatorConfig config)
+ ModelConfig config)
{
- JsonValidatorConfig validatorConfig = (JsonValidatorConfig) config;
- JsonObjectBuilder validator = Json.createObjectBuilder();
- validator.add(TYPE_NAME, JSON);
- if (validatorConfig.catalogs != null && !validatorConfig.catalogs.isEmpty())
+ JsonModelConfig jsonConfig = (JsonModelConfig) config;
+ JsonObjectBuilder converter = Json.createObjectBuilder();
+ converter.add(MODEL_NAME, JSON);
+ if (jsonConfig.cataloged != null && !jsonConfig.cataloged.isEmpty())
{
JsonObjectBuilder catalogs = Json.createObjectBuilder();
- for (CatalogedConfig catalog : validatorConfig.catalogs)
+ for (CatalogedConfig catalog : jsonConfig.cataloged)
{
JsonArrayBuilder array = Json.createArrayBuilder();
for (SchemaConfig schemaItem: catalog.schemas)
@@ -64,36 +66,38 @@ public JsonValue adaptToJson(
}
catalogs.add(catalog.name, array);
}
- validator.add(CATALOG_NAME, catalogs);
+ converter.add(CATALOG_NAME, catalogs);
}
- return validator.build();
+ return converter.build();
}
@Override
- public ValidatorConfig adaptFromJson(
+ public ModelConfig adaptFromJson(
JsonValue value)
{
JsonObject object = (JsonObject) value;
- ValidatorConfig result = null;
- if (object.containsKey(CATALOG_NAME))
+
+ assert object.containsKey(CATALOG_NAME);
+
+ JsonObject catalogsJson = object.getJsonObject(CATALOG_NAME);
+ List catalogs = new LinkedList<>();
+ for (String catalogName: catalogsJson.keySet())
{
- JsonObject catalogsJson = object.getJsonObject(CATALOG_NAME);
- List catalogs = new LinkedList<>();
- for (String catalogName: catalogsJson.keySet())
+ JsonArray schemasJson = catalogsJson.getJsonArray(catalogName);
+ List schemas = new LinkedList<>();
+ for (JsonValue item : schemasJson)
{
- JsonArray schemasJson = catalogsJson.getJsonArray(catalogName);
- List schemas = new LinkedList<>();
- for (JsonValue item : schemasJson)
- {
- JsonObject schemaJson = (JsonObject) item;
- SchemaConfig schemaElement = schema.adaptFromJson(schemaJson);
- schemas.add(schemaElement);
- }
- catalogs.add(new CatalogedConfig(catalogName, schemas));
+ JsonObject schemaJson = (JsonObject) item;
+ SchemaConfig schemaElement = schema.adaptFromJson(schemaJson);
+ schemas.add(schemaElement);
}
-
- result = new JsonValidatorConfig(catalogs);
+ catalogs.add(new CatalogedConfig(catalogName, schemas));
}
- return result;
+
+ String subject = object.containsKey(SUBJECT_NAME)
+ ? object.getString(SUBJECT_NAME)
+ : null;
+
+ return new JsonModelConfig(catalogs, subject);
}
}
diff --git a/incubator/validator-json/src/main/moditect/module-info.java b/incubator/model-json/src/main/moditect/module-info.java
similarity index 61%
rename from incubator/validator-json/src/main/moditect/module-info.java
rename to incubator/model-json/src/main/moditect/module-info.java
index 3931d8cd17..3e7d30ffb7 100644
--- a/incubator/validator-json/src/main/moditect/module-info.java
+++ b/incubator/model-json/src/main/moditect/module-info.java
@@ -12,17 +12,17 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-module io.aklivity.zilla.runtime.validator.json
+module io.aklivity.zilla.runtime.model.json
{
requires io.aklivity.zilla.runtime.engine;
requires org.leadpony.justify;
- exports io.aklivity.zilla.runtime.validator.json.config;
+ exports io.aklivity.zilla.runtime.model.json.config;
- provides io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
- with io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfigAdapter;
+ provides io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
+ with io.aklivity.zilla.runtime.model.json.internal.config.JsonModelConfigAdapter;
- provides io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
- with io.aklivity.zilla.runtime.validator.json.JsonValidatorFactory;
+ provides io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
+ with io.aklivity.zilla.runtime.model.json.internal.JsonModelFactorySpi;
}
diff --git a/incubator/model-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi b/incubator/model-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
new file mode 100644
index 0000000000..5e6f55c3ba
--- /dev/null
+++ b/incubator/model-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
@@ -0,0 +1 @@
+io.aklivity.zilla.runtime.model.json.internal.config.JsonModelConfigAdapter
diff --git a/incubator/model-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi b/incubator/model-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
new file mode 100644
index 0000000000..816e864ae6
--- /dev/null
+++ b/incubator/model-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
@@ -0,0 +1 @@
+io.aklivity.zilla.runtime.model.json.internal.JsonModelFactorySpi
diff --git a/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorTest.java b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonConverterTest.java
similarity index 61%
rename from incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorTest.java
rename to incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonConverterTest.java
index b19be65beb..a5729989bd 100644
--- a/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorTest.java
+++ b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonConverterTest.java
@@ -12,18 +12,17 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.json;
+package io.aklivity.zilla.runtime.model.json.internal;
import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_DIRECTORY;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import java.util.Properties;
import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
import org.agrona.DirectBuffer;
+import org.agrona.MutableDirectBuffer;
import org.agrona.concurrent.UnsafeBuffer;
import org.junit.Before;
import org.junit.Test;
@@ -34,13 +33,12 @@
import io.aklivity.zilla.runtime.engine.catalog.CatalogContext;
import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
import io.aklivity.zilla.runtime.engine.config.CatalogConfig;
-import io.aklivity.zilla.runtime.engine.internal.LabelManager;
-import io.aklivity.zilla.runtime.engine.internal.stream.NamespacedId;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalog;
import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
-public class JsonValidatorTest
+public class JsonConverterTest
{
private static final String OBJECT_SCHEMA = "{" +
"\"type\": \"object\"," +
@@ -65,7 +63,7 @@ public class JsonValidatorTest
OBJECT_SCHEMA +
"}";
- private final JsonValidatorConfig config = JsonValidatorConfig.builder()
+ private final JsonModelConfig config = JsonModelConfig.builder()
.catalog()
.name("test0")
.schema()
@@ -76,8 +74,6 @@ public class JsonValidatorTest
.build()
.build()
.build();
- private LabelManager labels;
- private ToLongFunction resolveId;
private CatalogContext context;
@Before
@@ -86,8 +82,6 @@ public void init()
Properties properties = new Properties();
properties.setProperty(ENGINE_DIRECTORY.name(), "target/zilla-itests");
EngineConfiguration config = new EngineConfiguration(properties);
- labels = new LabelManager(config.directory());
- resolveId = name -> name != null ? NamespacedId.id(1, labels.supplyLabelId(name)) : 0L;
Catalog catalog = new TestCatalog(config);
context = catalog.supply(mock(EngineContext.class));
}
@@ -95,27 +89,36 @@ public void init()
@Test
public void shouldVerifyValidJsonObject()
{
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(OBJECT_SCHEMA));
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(OBJECT_SCHEMA)
+ .build());
LongFunction handler = value -> context.attach(catalogConfig);
- JsonValidator validator = new JsonValidator(config, resolveId, handler);
+ JsonReadConverterHandler converter = new JsonReadConverterHandler(config, handler);
DirectBuffer data = new UnsafeBuffer();
- String payload = "{" +
- "\"id\": \"123\"," +
- "\"status\": \"OK\"" +
+ String payload =
+ "{" +
+ "\"id\": \"123\"," +
+ "\"status\": \"OK\"" +
"}";
byte[] bytes = payload.getBytes();
data.wrap(bytes, 0, bytes.length);
- assertTrue(validator.write(data, 0, data.capacity()));
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
}
@Test
public void shouldVerifyValidJsonArray()
{
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(ARRAY_SCHEMA));
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(ARRAY_SCHEMA)
+ .build());
LongFunction handler = value -> context.attach(catalogConfig);
- JsonValidator validator = new JsonValidator(config, resolveId, handler);
+ JsonWriteConverterHandler converter = new JsonWriteConverterHandler(config, handler);
DirectBuffer data = new UnsafeBuffer();
@@ -128,33 +131,72 @@ public void shouldVerifyValidJsonArray()
"]";
byte[] bytes = payload.getBytes();
data.wrap(bytes, 0, bytes.length);
- assertTrue(validator.write(data, 0, data.capacity()));
+
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
}
@Test
public void shouldVerifyInvalidJsonObject()
{
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(OBJECT_SCHEMA));
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(OBJECT_SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ JsonReadConverterHandler converter = new JsonReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "{" +
+ "\"id\": 123," +
+ "\"status\": \"OK\"" +
+ "}";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ MutableDirectBuffer value = new UnsafeBuffer(new byte[data.capacity() + 5]);
+ value.putBytes(0, new byte[]{0x00, 0x00, 0x00, 0x00, 0x01});
+ value.putBytes(5, bytes);
+
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldWriteValidJsonData()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(OBJECT_SCHEMA)
+ .build());
LongFunction handler = value -> context.attach(catalogConfig);
- JsonValidator validator = new JsonValidator(config, resolveId, handler);
+ JsonWriteConverterHandler converter = new JsonWriteConverterHandler(config, handler);
DirectBuffer data = new UnsafeBuffer();
- String payload = "{" +
- "\"id\": 123," +
- "\"status\": \"OK\"" +
+ String payload =
+ "{" +
+ "\"id\": \"123\"," +
+ "\"status\": \"OK\"" +
"}";
byte[] bytes = payload.getBytes();
data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.write(data, 0, data.capacity()));
+
+ assertEquals(data.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
}
@Test
public void shouldVerifyInvalidJsonArray()
{
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(ARRAY_SCHEMA));
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(ARRAY_SCHEMA)
+ .build());
LongFunction handler = value -> context.attach(catalogConfig);
- JsonValidator validator = new JsonValidator(config, resolveId, handler);
+ JsonWriteConverterHandler converter = new JsonWriteConverterHandler(config, handler);
DirectBuffer data = new UnsafeBuffer();
@@ -167,6 +209,7 @@ public void shouldVerifyInvalidJsonArray()
"]";
byte[] bytes = payload.getBytes();
data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.write(data, 0, data.capacity()));
+
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
}
}
diff --git a/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelFactorySpiTest.java b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelFactorySpiTest.java
new file mode 100644
index 0000000000..5aa0afa399
--- /dev/null
+++ b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonModelFactorySpiTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ModelFactory;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonModelFactorySpiTest
+{
+ @Test
+ public void shouldLoadAndCreate()
+ {
+ Configuration config = new Configuration();
+ ModelFactory factory = ModelFactory.instantiate();
+ Model model = factory.create("json", config);
+
+ ModelContext context = model.supply(mock(EngineContext.class));
+
+ ModelConfig modelConfig = JsonModelConfig.builder()
+ .subject("test-value")
+ .catalog()
+ .name("test0")
+ .schema()
+ .subject("subject1")
+ .version("latest")
+ .build()
+ .build()
+ .build();
+
+ assertThat(model, instanceOf(JsonModel.class));
+ assertEquals(model.name(), "json");
+ assertThat(context.supplyReadConverterHandler(modelConfig), instanceOf(JsonReadConverterHandler.class));
+ assertThat(context.supplyWriteConverterHandler(modelConfig), instanceOf(JsonWriteConverterHandler.class));
+ assertThat(context.supplyValidatorHandler(modelConfig), instanceOf(JsonValidatorHandler.class));
+ }
+}
diff --git a/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonValidatorTest.java b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonValidatorTest.java
new file mode 100644
index 0000000000..12b3fd7aa9
--- /dev/null
+++ b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/JsonValidatorTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.json.internal;
+
+import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_DIRECTORY;
+import static io.aklivity.zilla.runtime.engine.model.ValidatorHandler.FLAGS_FIN;
+import static io.aklivity.zilla.runtime.engine.model.ValidatorHandler.FLAGS_INIT;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.util.Properties;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.catalog.Catalog;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogContext;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.CatalogConfig;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalog;
+import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonValidatorTest
+{
+ private static final String OBJECT_SCHEMA = "{" +
+ "\"type\": \"object\"," +
+ "\"properties\": " +
+ "{" +
+ "\"id\": {" +
+ "\"type\": \"string\"" +
+ "}," +
+ "\"status\": {" +
+ "\"type\": \"string\"" +
+ "}" +
+ "}," +
+ "\"required\": [" +
+ "\"id\"," +
+ "\"status\"" +
+ "]" +
+ "}";
+
+ private static final String ARRAY_SCHEMA = "{" +
+ "\"type\": \"array\"," +
+ "\"items\": " +
+ OBJECT_SCHEMA +
+ "}";
+
+ private final JsonModelConfig config = JsonModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .subject(null)
+ .version("latest")
+ .id(1)
+ .build()
+ .build()
+ .build();
+ private CatalogContext context;
+
+ @Before
+ public void init()
+ {
+ Properties properties = new Properties();
+ properties.setProperty(ENGINE_DIRECTORY.name(), "target/zilla-itests");
+ Configuration config = new Configuration(properties);
+ Catalog catalog = new TestCatalog(config);
+ context = catalog.supply(mock(EngineContext.class));
+ }
+
+ @Test
+ public void shouldVerifyValidCompleteJsonObject()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(OBJECT_SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ JsonValidatorHandler validator = new JsonValidatorHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "{" +
+ "\"id\": \"123\"," +
+ "\"status\": \"OK\"" +
+ "}";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ assertTrue(validator.validate(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInvalidCompleteJsonObject()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(OBJECT_SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ JsonValidatorHandler validator = new JsonValidatorHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "{" +
+ "\"id\": 123," +
+ "\"status\": \"OK\"" +
+ "}";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ assertFalse(validator.validate(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyValidFragmentedJsonObject()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(OBJECT_SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ JsonValidatorHandler validator = new JsonValidatorHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "{" +
+ "\"id\": \"123\"," +
+ "\"status\": \"OK\"" +
+ "}";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ assertTrue(validator.validate(FLAGS_INIT, data, 0, 12, ValueConsumer.NOP));
+ assertTrue(validator.validate(FLAGS_FIN, data, 12, data.capacity() - 12, ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyInvalidFragmentedJsonObject()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(OBJECT_SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ JsonValidatorHandler validator = new JsonValidatorHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "{" +
+ "\"id\": 123," +
+ "\"status\": \"OK\"" +
+ "}";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ assertTrue(validator.validate(FLAGS_INIT, data, 0, 12, ValueConsumer.NOP));
+ assertFalse(validator.validate(FLAGS_FIN, data, 12, data.capacity() - 12, ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyValidJsonArray()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(ARRAY_SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ JsonValidatorHandler validator = new JsonValidatorHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String payload =
+ "[" +
+ "{" +
+ "\"id\": \"123\"," +
+ "\"status\": \"OK\"" +
+ "}" +
+ "]";
+ byte[] bytes = payload.getBytes();
+ data.wrap(bytes, 0, bytes.length);
+
+ assertTrue(validator.validate(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+}
diff --git a/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigAdapterTest.java b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/config/JsonModelConfigAdapterTest.java
similarity index 67%
rename from incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigAdapterTest.java
rename to incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/config/JsonModelConfigAdapterTest.java
index 2c764b0e40..670b7748e2 100644
--- a/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/config/JsonValidatorConfigAdapterTest.java
+++ b/incubator/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/config/JsonModelConfigAdapterTest.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.json.config;
+package io.aklivity.zilla.runtime.model.json.internal.config;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@@ -26,7 +26,9 @@
import org.junit.Before;
import org.junit.Test;
-public class JsonValidatorConfigAdapterTest
+import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig;
+
+public class JsonModelConfigAdapterTest
{
private Jsonb jsonb;
@@ -34,17 +36,17 @@ public class JsonValidatorConfigAdapterTest
public void initJson()
{
JsonbConfig config = new JsonbConfig()
- .withAdapters(new JsonValidatorConfigAdapter());
+ .withAdapters(new JsonModelConfigAdapter());
jsonb = JsonbBuilder.create(config);
}
@Test
- public void shouldReadJsonValidator()
+ public void shouldReadJsonConverter()
{
// GIVEN
String json =
"{" +
- "\"type\": \"json\"," +
+ "\"model\": \"json\"," +
"\"catalog\":" +
"{" +
"\"test0\":" +
@@ -65,31 +67,31 @@ public void shouldReadJsonValidator()
"}";
// WHEN
- JsonValidatorConfig validator = jsonb.fromJson(json, JsonValidatorConfig.class);
+ JsonModelConfig config = jsonb.fromJson(json, JsonModelConfig.class);
// THEN
- assertThat(validator, not(nullValue()));
- assertThat(validator.type, equalTo("json"));
- assertThat(validator.catalogs.size(), equalTo(1));
- assertThat(validator.catalogs.get(0).name, equalTo("test0"));
- assertThat(validator.catalogs.get(0).schemas.get(0).subject, equalTo("subject1"));
- assertThat(validator.catalogs.get(0).schemas.get(0).version, equalTo("latest"));
- assertThat(validator.catalogs.get(0).schemas.get(0).id, equalTo(0));
- assertThat(validator.catalogs.get(0).schemas.get(1).strategy, equalTo("topic"));
- assertThat(validator.catalogs.get(0).schemas.get(1).version, equalTo("latest"));
- assertThat(validator.catalogs.get(0).schemas.get(1).id, equalTo(0));
- assertThat(validator.catalogs.get(0).schemas.get(2).strategy, nullValue());
- assertThat(validator.catalogs.get(0).schemas.get(2).version, nullValue());
- assertThat(validator.catalogs.get(0).schemas.get(2).id, equalTo(42));
+ assertThat(config, not(nullValue()));
+ assertThat(config.model, equalTo("json"));
+ assertThat(config.cataloged.size(), equalTo(1));
+ assertThat(config.cataloged.get(0).name, equalTo("test0"));
+ assertThat(config.cataloged.get(0).schemas.get(0).subject, equalTo("subject1"));
+ assertThat(config.cataloged.get(0).schemas.get(0).version, equalTo("latest"));
+ assertThat(config.cataloged.get(0).schemas.get(0).id, equalTo(0));
+ assertThat(config.cataloged.get(0).schemas.get(1).strategy, equalTo("topic"));
+ assertThat(config.cataloged.get(0).schemas.get(1).version, equalTo("latest"));
+ assertThat(config.cataloged.get(0).schemas.get(1).id, equalTo(0));
+ assertThat(config.cataloged.get(0).schemas.get(2).strategy, nullValue());
+ assertThat(config.cataloged.get(0).schemas.get(2).version, nullValue());
+ assertThat(config.cataloged.get(0).schemas.get(2).id, equalTo(42));
}
@Test
- public void shouldWriteJsonValidator()
+ public void shouldWriteJsonConverter()
{
// GIVEN
String expectedJson =
"{" +
- "\"type\":\"json\"," +
+ "\"model\":\"json\"," +
"\"catalog\":" +
"{" +
"\"test0\":" +
@@ -108,7 +110,7 @@ public void shouldWriteJsonValidator()
"]" +
"}" +
"}";
- JsonValidatorConfig validator = JsonValidatorConfig.builder()
+ JsonModelConfig config = JsonModelConfig.builder()
.catalog()
.name("test0")
.schema()
@@ -126,7 +128,7 @@ public void shouldWriteJsonValidator()
.build();
// WHEN
- String json = jsonb.toJson(validator);
+ String json = jsonb.toJson(config);
// THEN
assertThat(json, not(nullValue()));
diff --git a/incubator/model-protobuf.spec/COPYRIGHT b/incubator/model-protobuf.spec/COPYRIGHT
new file mode 100644
index 0000000000..0cb10b6f62
--- /dev/null
+++ b/incubator/model-protobuf.spec/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyright ${copyrightYears} Aklivity Inc
+
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
diff --git a/incubator/model-protobuf.spec/LICENSE b/incubator/model-protobuf.spec/LICENSE
new file mode 100644
index 0000000000..f6abb6327b
--- /dev/null
+++ b/incubator/model-protobuf.spec/LICENSE
@@ -0,0 +1,114 @@
+ Aklivity Community License Agreement
+ Version 1.0
+
+This Aklivity Community License Agreement Version 1.0 (the “Agreement”) sets
+forth the terms on which Aklivity, Inc. (“Aklivity”) makes available certain
+software made available by Aklivity under this Agreement (the “Software”). BY
+INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF THE SOFTWARE,
+YOU AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO
+SUCH TERMS AND CONDITIONS, YOU MUST NOT USE THE SOFTWARE. IF YOU ARE RECEIVING
+THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU
+HAVE THE ACTUAL AUTHORITY TO AGREE TO THE TERMS AND CONDITIONS OF THIS
+AGREEMENT ON BEHALF OF SUCH ENTITY. “Licensee” means you, an individual, or
+the entity on whose behalf you are receiving the Software.
+
+ 1. LICENSE GRANT AND CONDITIONS.
+
+ 1.1 License. Subject to the terms and conditions of this Agreement,
+ Aklivity hereby grants to Licensee a non-exclusive, royalty-free,
+ worldwide, non-transferable, non-sublicenseable license during the term
+ of this Agreement to: (a) use the Software; (b) prepare modifications and
+ derivative works of the Software; (c) distribute the Software (including
+ without limitation in source code or object code form); and (d) reproduce
+ copies of the Software (the “License”). Licensee is not granted the
+ right to, and Licensee shall not, exercise the License for an Excluded
+ Purpose. For purposes of this Agreement, “Excluded Purpose” means making
+ available any software-as-a-service, platform-as-a-service,
+ infrastructure-as-a-service or other similar online service that competes
+ with Aklivity products or services that provide the Software.
+
+ 1.2 Conditions. In consideration of the License, Licensee’s distribution
+ of the Software is subject to the following conditions:
+
+ (a) Licensee must cause any Software modified by Licensee to carry
+ prominent notices stating that Licensee modified the Software.
+
+ (b) On each Software copy, Licensee shall reproduce and not remove or
+ alter all Aklivity or third party copyright or other proprietary
+ notices contained in the Software, and Licensee must provide the
+ notice below with each copy.
+
+ “This software is made available by Aklivity, Inc., under the
+ terms of the Aklivity Community License Agreement, Version 1.0
+ located at http://www.Aklivity.io/Aklivity-community-license. BY
+ INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF
+ THE SOFTWARE, YOU AGREE TO THE TERMS OF SUCH LICENSE AGREEMENT.”
+
+ 1.3 Licensee Modifications. Licensee may add its own copyright notices
+ to modifications made by Licensee and may provide additional or different
+ license terms and conditions for use, reproduction, or distribution of
+ Licensee’s modifications. While redistributing the Software or
+ modifications thereof, Licensee may choose to offer, for a fee or free of
+ charge, support, warranty, indemnity, or other obligations. Licensee, and
+ not Aklivity, will be responsible for any such obligations.
+
+ 1.4 No Sublicensing. The License does not include the right to
+ sublicense the Software, however, each recipient to which Licensee
+ provides the Software may exercise the Licenses so long as such recipient
+ agrees to the terms and conditions of this Agreement.
+
+ 2. TERM AND TERMINATION. This Agreement will continue unless and until
+ earlier terminated as set forth herein. If Licensee breaches any of its
+ conditions or obligations under this Agreement, this Agreement will
+ terminate automatically and the License will terminate automatically and
+ permanently.
+
+ 3. INTELLECTUAL PROPERTY. As between the parties, Aklivity will retain all
+ right, title, and interest in the Software, and all intellectual property
+ rights therein. Aklivity hereby reserves all rights not expressly granted
+ to Licensee in this Agreement. Aklivity hereby reserves all rights in its
+ trademarks and service marks, and no licenses therein are granted in this
+ Agreement.
+
+ 4. DISCLAIMER. Aklivity HEREBY DISCLAIMS ANY AND ALL WARRANTIES AND
+ CONDITIONS, EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, AND SPECIFICALLY
+ DISCLAIMS ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+ PURPOSE, WITH RESPECT TO THE SOFTWARE.
+
+ 5. LIMITATION OF LIABILITY. Aklivity WILL NOT BE LIABLE FOR ANY DAMAGES OF
+ ANY KIND, INCLUDING BUT NOT LIMITED TO, LOST PROFITS OR ANY CONSEQUENTIAL,
+ SPECIAL, INCIDENTAL, INDIRECT, OR DIRECT DAMAGES, HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, ARISING OUT OF THIS AGREEMENT. THE FOREGOING SHALL
+ APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+
+ 6.GENERAL.
+
+ 6.1 Governing Law. This Agreement will be governed by and interpreted in
+ accordance with the laws of the state of California, without reference to
+ its conflict of laws principles. If Licensee is located within the
+ United States, all disputes arising out of this Agreement are subject to
+ the exclusive jurisdiction of courts located in Santa Clara County,
+ California. USA. If Licensee is located outside of the United States,
+ any dispute, controversy or claim arising out of or relating to this
+ Agreement will be referred to and finally determined by arbitration in
+ accordance with the JAMS International Arbitration Rules. The tribunal
+ will consist of one arbitrator. The place of arbitration will be Palo
+ Alto, California. The language to be used in the arbitral proceedings
+ will be English. Judgment upon the award rendered by the arbitrator may
+ be entered in any court having jurisdiction thereof.
+
+ 6.2 Assignment. Licensee is not authorized to assign its rights under
+ this Agreement to any third party. Aklivity may freely assign its rights
+ under this Agreement to any third party.
+
+ 6.3 Other. This Agreement is the entire agreement between the parties
+ regarding the subject matter hereof. No amendment or modification of
+ this Agreement will be valid or binding upon the parties unless made in
+ writing and signed by the duly authorized representatives of both
+ parties. In the event that any provision, including without limitation
+ any condition, of this Agreement is held to be unenforceable, this
+ Agreement and all licenses and rights granted hereunder will immediately
+ terminate. Waiver by Aklivity of a breach of any provision of this
+ Agreement or the failure by Aklivity to exercise any right hereunder
+ will not be construed as a waiver of any subsequent breach of that right
+ or as a waiver of any other right.
\ No newline at end of file
diff --git a/incubator/model-protobuf.spec/NOTICE b/incubator/model-protobuf.spec/NOTICE
new file mode 100644
index 0000000000..ed4c502c75
--- /dev/null
+++ b/incubator/model-protobuf.spec/NOTICE
@@ -0,0 +1,23 @@
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+This project includes:
+ agrona under The Apache License, Version 2.0
+ ANTLR 4 Runtime under BSD-3-Clause
+ ICU4J under Unicode/ICU License
+ Jakarta JSON Processing API under Eclipse Public License 2.0 or GNU General Public License, version 2 with the GNU Classpath Exception
+ Java Unified Expression Language API under The Apache Software License, Version 2.0
+ Java Unified Expression Language Implementation under The Apache Software License, Version 2.0
+ k3po/lang under The Apache Software License, Version 2.0
+ Kaazing Corporation License under The Apache Software License, Version 2.0
+ org.leadpony.justify under The Apache Software License, Version 2.0
+ zilla::specs::engine.spec under The Apache Software License, Version 2.0
+
diff --git a/incubator/model-protobuf.spec/NOTICE.template b/incubator/model-protobuf.spec/NOTICE.template
new file mode 100644
index 0000000000..209ca12f74
--- /dev/null
+++ b/incubator/model-protobuf.spec/NOTICE.template
@@ -0,0 +1,13 @@
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+This project includes:
+#GENERATED_NOTICES#
diff --git a/incubator/model-protobuf.spec/mvnw b/incubator/model-protobuf.spec/mvnw
new file mode 100755
index 0000000000..d2f0ea3808
--- /dev/null
+++ b/incubator/model-protobuf.spec/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/incubator/model-protobuf.spec/mvnw.cmd b/incubator/model-protobuf.spec/mvnw.cmd
new file mode 100644
index 0000000000..b26ab24f03
--- /dev/null
+++ b/incubator/model-protobuf.spec/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/incubator/model-protobuf.spec/pom.xml b/incubator/model-protobuf.spec/pom.xml
new file mode 100644
index 0000000000..6fed03b03c
--- /dev/null
+++ b/incubator/model-protobuf.spec/pom.xml
@@ -0,0 +1,111 @@
+
+
+
+4.0.0
+
+ io.aklivity.zilla
+ incubator
+ 0.9.67
+ ../pom.xml
+
+
+model-protobuf.spec
+zilla::incubator::model-protobuf.spec
+
+
+
+ Aklivity Community License Agreement
+ https://www.aklivity.io/aklivity-community-license/
+ repo
+
+
+
+
+ 11
+ 11
+ 0.98
+ 0
+
+
+
+
+ ${project.groupId}
+ engine.spec
+ ${project.version}
+
+
+ junit
+ junit
+ test
+
+
+ org.hamcrest
+ hamcrest-library
+ test
+
+
+
+
+
+
+ src/main/resources
+
+
+ src/main/scripts
+
+
+
+
+
+ org.jasig.maven
+ maven-notice-plugin
+
+
+ com.mycila
+ license-maven-plugin
+
+
+ maven-checkstyle-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.moditect
+ moditect-maven-plugin
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+ BUNDLE
+
+
+ INSTRUCTION
+ COVEREDRATIO
+ ${jacoco.coverage.ratio}
+
+
+ CLASS
+ MISSEDCOUNT
+ ${jacoco.missed.count}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/incubator/model-protobuf.spec/src/main/moditect/module-info.java b/incubator/model-protobuf.spec/src/main/moditect/module-info.java
new file mode 100644
index 0000000000..92a482d255
--- /dev/null
+++ b/incubator/model-protobuf.spec/src/main/moditect/module-info.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+open module io.aklivity.zilla.specs.model.protobuf
+{
+ requires transitive io.aklivity.zilla.specs.engine;
+}
diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.retained.server.sent.flush/server.rpt b/incubator/model-protobuf.spec/src/main/scripts/io/aklivity/zilla/specs/model/protobuf/config/model.yaml
similarity index 52%
rename from specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.retained.server.sent.flush/server.rpt
rename to incubator/model-protobuf.spec/src/main/scripts/io/aklivity/zilla/specs/model/protobuf/config/model.yaml
index 0d654c898a..cb958f494c 100644
--- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.retained.server.sent.flush/server.rpt
+++ b/incubator/model-protobuf.spec/src/main/scripts/io/aklivity/zilla/specs/model/protobuf/config/model.yaml
@@ -13,20 +13,30 @@
# specific language governing permissions and limitations under the License.
#
-accept "zilla://streams/mqtt0"
- option zilla:window 8192
- option zilla:transmission "duplex"
-accepted
-
-read zilla:begin.ext ${mqtt:matchBeginEx()
- .typeId(zilla:id("mqtt"))
- .publish()
- .clientId("client")
- .topic("sensor/one")
- .flags("RETAIN")
- .build()
- .build()}
-
-connected
-
-write advise zilla:flush
+---
+name: test
+catalogs:
+ test0:
+ type: test
+ options:
+ schema: |
+ syntax = "proto3";
+ message example
+ {
+ string id = 1;
+ string status = 2;
+ }
+bindings:
+ test:
+ kind: server
+ type: test
+ options:
+ value:
+ model: protobuf
+ view: json
+ catalog:
+ catalog0:
+ - subject: test0
+ version: latest
+ record: example
+ exit: test
diff --git a/incubator/model-protobuf.spec/src/main/scripts/io/aklivity/zilla/specs/model/protobuf/schema/protobuf.schema.patch.json b/incubator/model-protobuf.spec/src/main/scripts/io/aklivity/zilla/specs/model/protobuf/schema/protobuf.schema.patch.json
new file mode 100644
index 0000000000..578800f5d2
--- /dev/null
+++ b/incubator/model-protobuf.spec/src/main/scripts/io/aklivity/zilla/specs/model/protobuf/schema/protobuf.schema.patch.json
@@ -0,0 +1,152 @@
+[
+ {
+ "op": "add",
+ "path": "/$defs/converter/types/enum/-",
+ "value": "protobuf"
+ },
+ {
+ "op": "add",
+ "path": "/$defs/converter/allOf/-",
+ "value":
+ {
+ "if":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "protobuf"
+ }
+ }
+ },
+ "then":
+ {
+ "properties":
+ {
+ "model":
+ {
+ "const": "protobuf"
+ },
+ "view":
+ {
+ "type": "string",
+ "enum":
+ [
+ "json"
+ ]
+ },
+ "catalog":
+ {
+ "type": "object",
+ "patternProperties":
+ {
+ "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$":
+ {
+ "type": "array",
+ "items":
+ {
+ "oneOf":
+ [
+ {
+ "type": "object",
+ "properties":
+ {
+ "id":
+ {
+ "type": "integer"
+ },
+ "record":
+ {
+ "type": "string"
+ }
+ },
+ "required":
+ [
+ "id"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "schema":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ },
+ "record":
+ {
+ "type": "string"
+ }
+ },
+ "required":
+ [
+ "schema"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "strategy":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ },
+ "record":
+ {
+ "type": "string"
+ }
+ },
+ "required":
+ [
+ "strategy"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties":
+ {
+ "subject":
+ {
+ "type": "string"
+ },
+ "version":
+ {
+ "type": "string",
+ "default": "latest"
+ },
+ "record":
+ {
+ "type": "string"
+ }
+ },
+ "required":
+ [
+ "subject"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ }
+ }
+ },
+ "maxProperties": 1
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+]
diff --git a/incubator/model-protobuf.spec/src/test/java/io/aklivity/zilla/specs/model/protobuf/config/SchemaTest.java b/incubator/model-protobuf.spec/src/test/java/io/aklivity/zilla/specs/model/protobuf/config/SchemaTest.java
new file mode 100644
index 0000000000..53b15a4b87
--- /dev/null
+++ b/incubator/model-protobuf.spec/src/test/java/io/aklivity/zilla/specs/model/protobuf/config/SchemaTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.specs.model.protobuf.config;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+
+import jakarta.json.JsonObject;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import io.aklivity.zilla.specs.engine.config.ConfigSchemaRule;
+
+public class SchemaTest
+{
+ @Rule
+ public final ConfigSchemaRule schema = new ConfigSchemaRule()
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/engine/schema/catalog/test.schema.patch.json")
+ .schemaPatch("io/aklivity/zilla/specs/model/protobuf/schema/protobuf.schema.patch.json")
+ .configurationRoot("io/aklivity/zilla/specs/model/protobuf/config");
+
+ @Test
+ public void shouldValidateCatalog()
+ {
+ JsonObject config = schema.validate("model.yaml");
+
+ assertThat(config, not(nullValue()));
+ }
+}
diff --git a/incubator/model-protobuf/COPYRIGHT b/incubator/model-protobuf/COPYRIGHT
new file mode 100644
index 0000000000..0cb10b6f62
--- /dev/null
+++ b/incubator/model-protobuf/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyright ${copyrightYears} Aklivity Inc
+
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
diff --git a/incubator/model-protobuf/LICENSE b/incubator/model-protobuf/LICENSE
new file mode 100644
index 0000000000..f6abb6327b
--- /dev/null
+++ b/incubator/model-protobuf/LICENSE
@@ -0,0 +1,114 @@
+ Aklivity Community License Agreement
+ Version 1.0
+
+This Aklivity Community License Agreement Version 1.0 (the “Agreement”) sets
+forth the terms on which Aklivity, Inc. (“Aklivity”) makes available certain
+software made available by Aklivity under this Agreement (the “Software”). BY
+INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF THE SOFTWARE,
+YOU AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO
+SUCH TERMS AND CONDITIONS, YOU MUST NOT USE THE SOFTWARE. IF YOU ARE RECEIVING
+THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU
+HAVE THE ACTUAL AUTHORITY TO AGREE TO THE TERMS AND CONDITIONS OF THIS
+AGREEMENT ON BEHALF OF SUCH ENTITY. “Licensee” means you, an individual, or
+the entity on whose behalf you are receiving the Software.
+
+ 1. LICENSE GRANT AND CONDITIONS.
+
+ 1.1 License. Subject to the terms and conditions of this Agreement,
+ Aklivity hereby grants to Licensee a non-exclusive, royalty-free,
+ worldwide, non-transferable, non-sublicenseable license during the term
+ of this Agreement to: (a) use the Software; (b) prepare modifications and
+ derivative works of the Software; (c) distribute the Software (including
+ without limitation in source code or object code form); and (d) reproduce
+ copies of the Software (the “License”). Licensee is not granted the
+ right to, and Licensee shall not, exercise the License for an Excluded
+ Purpose. For purposes of this Agreement, “Excluded Purpose” means making
+ available any software-as-a-service, platform-as-a-service,
+ infrastructure-as-a-service or other similar online service that competes
+ with Aklivity products or services that provide the Software.
+
+ 1.2 Conditions. In consideration of the License, Licensee’s distribution
+ of the Software is subject to the following conditions:
+
+ (a) Licensee must cause any Software modified by Licensee to carry
+ prominent notices stating that Licensee modified the Software.
+
+ (b) On each Software copy, Licensee shall reproduce and not remove or
+ alter all Aklivity or third party copyright or other proprietary
+ notices contained in the Software, and Licensee must provide the
+ notice below with each copy.
+
+ “This software is made available by Aklivity, Inc., under the
+ terms of the Aklivity Community License Agreement, Version 1.0
+ located at http://www.Aklivity.io/Aklivity-community-license. BY
+ INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF
+ THE SOFTWARE, YOU AGREE TO THE TERMS OF SUCH LICENSE AGREEMENT.”
+
+ 1.3 Licensee Modifications. Licensee may add its own copyright notices
+ to modifications made by Licensee and may provide additional or different
+ license terms and conditions for use, reproduction, or distribution of
+ Licensee’s modifications. While redistributing the Software or
+ modifications thereof, Licensee may choose to offer, for a fee or free of
+ charge, support, warranty, indemnity, or other obligations. Licensee, and
+ not Aklivity, will be responsible for any such obligations.
+
+ 1.4 No Sublicensing. The License does not include the right to
+ sublicense the Software, however, each recipient to which Licensee
+ provides the Software may exercise the Licenses so long as such recipient
+ agrees to the terms and conditions of this Agreement.
+
+ 2. TERM AND TERMINATION. This Agreement will continue unless and until
+ earlier terminated as set forth herein. If Licensee breaches any of its
+ conditions or obligations under this Agreement, this Agreement will
+ terminate automatically and the License will terminate automatically and
+ permanently.
+
+ 3. INTELLECTUAL PROPERTY. As between the parties, Aklivity will retain all
+ right, title, and interest in the Software, and all intellectual property
+ rights therein. Aklivity hereby reserves all rights not expressly granted
+ to Licensee in this Agreement. Aklivity hereby reserves all rights in its
+ trademarks and service marks, and no licenses therein are granted in this
+ Agreement.
+
+ 4. DISCLAIMER. Aklivity HEREBY DISCLAIMS ANY AND ALL WARRANTIES AND
+ CONDITIONS, EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, AND SPECIFICALLY
+ DISCLAIMS ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+ PURPOSE, WITH RESPECT TO THE SOFTWARE.
+
+ 5. LIMITATION OF LIABILITY. Aklivity WILL NOT BE LIABLE FOR ANY DAMAGES OF
+ ANY KIND, INCLUDING BUT NOT LIMITED TO, LOST PROFITS OR ANY CONSEQUENTIAL,
+ SPECIAL, INCIDENTAL, INDIRECT, OR DIRECT DAMAGES, HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, ARISING OUT OF THIS AGREEMENT. THE FOREGOING SHALL
+ APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+
+ 6.GENERAL.
+
+ 6.1 Governing Law. This Agreement will be governed by and interpreted in
+ accordance with the laws of the state of California, without reference to
+ its conflict of laws principles. If Licensee is located within the
+ United States, all disputes arising out of this Agreement are subject to
+ the exclusive jurisdiction of courts located in Santa Clara County,
+ California. USA. If Licensee is located outside of the United States,
+ any dispute, controversy or claim arising out of or relating to this
+ Agreement will be referred to and finally determined by arbitration in
+ accordance with the JAMS International Arbitration Rules. The tribunal
+ will consist of one arbitrator. The place of arbitration will be Palo
+ Alto, California. The language to be used in the arbitral proceedings
+ will be English. Judgment upon the award rendered by the arbitrator may
+ be entered in any court having jurisdiction thereof.
+
+ 6.2 Assignment. Licensee is not authorized to assign its rights under
+ this Agreement to any third party. Aklivity may freely assign its rights
+ under this Agreement to any third party.
+
+ 6.3 Other. This Agreement is the entire agreement between the parties
+ regarding the subject matter hereof. No amendment or modification of
+ this Agreement will be valid or binding upon the parties unless made in
+ writing and signed by the duly authorized representatives of both
+ parties. In the event that any provision, including without limitation
+ any condition, of this Agreement is held to be unenforceable, this
+ Agreement and all licenses and rights granted hereunder will immediately
+ terminate. Waiver by Aklivity of a breach of any provision of this
+ Agreement or the failure by Aklivity to exercise any right hereunder
+ will not be construed as a waiver of any subsequent breach of that right
+ or as a waiver of any other right.
\ No newline at end of file
diff --git a/incubator/model-protobuf/NOTICE b/incubator/model-protobuf/NOTICE
new file mode 100644
index 0000000000..aa95b451ff
--- /dev/null
+++ b/incubator/model-protobuf/NOTICE
@@ -0,0 +1,23 @@
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+This project includes:
+ error-prone annotations under Apache 2.0
+ FindBugs-jsr305 under The Apache Software License, Version 2.0
+ Gson under Apache-2.0
+ Guava: Google Core Libraries for Java under Apache License, Version 2.0
+ J2ObjC Annotations under Apache License, Version 2.0
+ Protocol Buffers [Core] under BSD-3-Clause
+ Protocol Buffers [Util] under BSD-3-Clause
+
+
+This project also includes code under copyright of the following entities:
+ https://github.com/reaktivity/
diff --git a/incubator/model-protobuf/NOTICE.template b/incubator/model-protobuf/NOTICE.template
new file mode 100644
index 0000000000..ff901de01b
--- /dev/null
+++ b/incubator/model-protobuf/NOTICE.template
@@ -0,0 +1,16 @@
+Licensed under the Aklivity Community License (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at
+
+ https://www.aklivity.io/aklivity-community-license/
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+
+This project includes:
+#GENERATED_NOTICES#
+
+This project also includes code under copyright of the following entities:
+ https://github.com/reaktivity/
\ No newline at end of file
diff --git a/incubator/model-protobuf/mvnw b/incubator/model-protobuf/mvnw
new file mode 100755
index 0000000000..d2f0ea3808
--- /dev/null
+++ b/incubator/model-protobuf/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/incubator/model-protobuf/mvnw.cmd b/incubator/model-protobuf/mvnw.cmd
new file mode 100644
index 0000000000..b26ab24f03
--- /dev/null
+++ b/incubator/model-protobuf/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/incubator/model-protobuf/pom.xml b/incubator/model-protobuf/pom.xml
new file mode 100644
index 0000000000..042d5e6727
--- /dev/null
+++ b/incubator/model-protobuf/pom.xml
@@ -0,0 +1,209 @@
+
+
+
+4.0.0
+
+ io.aklivity.zilla
+ incubator
+ 0.9.67
+ ../pom.xml
+
+
+model-protobuf
+zilla::incubator::model-protobuf
+
+
+
+ Aklivity Community License Agreement
+ https://www.aklivity.io/aklivity-community-license/
+ repo
+
+
+
+
+ 11
+ 11
+ 0.90
+ 0
+
+
+
+
+ ${project.groupId}
+ model-protobuf.spec
+ ${project.version}
+ provided
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+ provided
+
+
+ com.google.protobuf
+ protobuf-java
+ 3.24.4
+
+
+ com.google.protobuf
+ protobuf-java-util
+ 3.24.4
+
+
+ org.antlr
+ antlr4-runtime
+ provided
+
+
+ ${project.groupId}
+ engine
+ test-jar
+ ${project.version}
+ test
+
+
+ org.kaazing
+ k3po.junit
+ test
+
+
+ org.kaazing
+ k3po.lang
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+
+ org.jasig.maven
+ maven-notice-plugin
+
+
+ com.mycila
+ license-maven-plugin
+
+
+ maven-checkstyle-plugin
+
+
+ org.antlr
+ antlr4-maven-plugin
+
+
+ maven-dependency-plugin
+
+
+ process-resources
+
+ unpack
+
+
+
+
+ ${project.groupId}
+ model-protobuf.spec
+
+
+ ^\Qio/aklivity/zilla/specs/model/protobuf/\E
+ io/aklivity/zilla/runtime/model/protobuf/internal/
+
+
+
+
+ io/aklivity/zilla/specs/model/protobuf/schema/protobuf.schema.patch.json
+ ${project.build.directory}/classes
+
+
+
+ unpack-proto
+ generate-sources
+
+ unpack
+
+
+
+
+ ${project.groupId}
+ model-protobuf.spec
+ ${project.version}
+ ${basedir}/target/test-classes
+ **\/*.proto
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.moditect
+ moditect-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+ io/aklivity/zilla/runtime/model/protobuf/internal/parser/**/*.class
+
+
+
+ BUNDLE
+
+
+ INSTRUCTION
+ COVEREDRATIO
+ ${jacoco.coverage.ratio}
+
+
+ CLASS
+ MISSEDCOUNT
+ ${jacoco.missed.count}
+
+
+
+
+
+
+
+ org.kaazing
+ k3po-maven-plugin
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+ test-jar
+
+
+ ${project.groupId}
+ engine
+ ${project.version}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/incubator/model-protobuf/src/main/antlr4/io/aklivity/zilla/runtime/model/protobuf/internal/parser/Protobuf3.g4 b/incubator/model-protobuf/src/main/antlr4/io/aklivity/zilla/runtime/model/protobuf/internal/parser/Protobuf3.g4
new file mode 100644
index 0000000000..ce9835dbee
--- /dev/null
+++ b/incubator/model-protobuf/src/main/antlr4/io/aklivity/zilla/runtime/model/protobuf/internal/parser/Protobuf3.g4
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+grammar Protobuf3;
+
+proto
+ : syntax
+ (
+ importStatement
+ | packageStatement
+ | optionStatement
+ | topLevelDef
+ | emptyStatement_
+ )* EOF
+ ;
+
+// Syntax
+
+syntax
+ : SYNTAX EQ (PROTO3_LIT_SINGLE | PROTO3_LIT_DOUBLE) SEMI
+ ;
+
+// Import Statement
+
+importStatement
+ : IMPORT ( WEAK | PUBLIC )? strLit SEMI
+ ;
+
+// Package
+
+packageStatement
+ : PACKAGE fullIdent SEMI
+ ;
+
+// Option
+
+optionStatement
+ : OPTION optionName EQ constant SEMI
+ ;
+
+optionName
+ : fullIdent
+ | LP fullIdent RP ( DOT fullIdent )?
+ ;
+
+// Normal Field
+fieldLabel
+ : OPTIONAL | REPEATED
+ ;
+
+field
+ : fieldLabel? type_ fieldName EQ fieldNumber ( LB fieldOptions RB )? SEMI
+ ;
+
+fieldOptions
+ : fieldOption ( COMMA fieldOption )*
+ ;
+
+fieldOption
+ : optionName EQ constant
+ ;
+
+fieldNumber
+ : intLit
+ ;
+
+// Oneof and oneof field
+
+oneof
+ : ONEOF oneofName LC ( optionStatement | oneofField | emptyStatement_ )* RC
+ ;
+
+oneofField
+ : type_ fieldName EQ fieldNumber ( LB fieldOptions RB )? SEMI
+ ;
+
+// Map field
+
+mapField
+ : MAP LT keyType COMMA type_ GT mapName
+ EQ fieldNumber ( LB fieldOptions RB )? SEMI
+ ;
+keyType
+ : INT32
+ | INT64
+ | UINT32
+ | UINT64
+ | SINT32
+ | SINT64
+ | FIXED32
+ | FIXED64
+ | SFIXED32
+ | SFIXED64
+ | BOOL
+ | STRING
+ ;
+
+// field types
+
+type_
+ : DOUBLE
+ | FLOAT
+ | INT32
+ | INT64
+ | UINT32
+ | UINT64
+ | SINT32
+ | SINT64
+ | FIXED32
+ | FIXED64
+ | SFIXED32
+ | SFIXED64
+ | BOOL
+ | STRING
+ | BYTES
+ | messageType
+ | enumType
+ ;
+
+// Reserved
+
+reserved
+ : RESERVED ( ranges | reservedFieldNames ) SEMI
+ ;
+
+ranges
+ : range_ ( COMMA range_ )*
+ ;
+
+range_
+ : intLit ( TO ( intLit | MAX ) )?
+ ;
+
+reservedFieldNames
+ : strLit ( COMMA strLit )*
+ ;
+
+// Top Level definitions
+
+topLevelDef
+ : messageDef
+ | enumDef
+ | extendDef
+ | serviceDef
+ ;
+
+// enum
+
+enumDef
+ : ENUM enumName enumBody
+ ;
+
+enumBody
+ : LC enumElement* RC
+ ;
+
+enumElement
+ : optionStatement
+ | enumField
+ | emptyStatement_
+ ;
+
+enumField
+ : ident EQ ( MINUS )? intLit enumValueOptions?SEMI
+ ;
+
+enumValueOptions
+ : LB enumValueOption ( COMMA enumValueOption )* RB
+ ;
+
+enumValueOption
+ : optionName EQ constant
+ ;
+
+// message
+
+messageDef
+ : MESSAGE messageName messageBody
+ ;
+
+messageBody
+ : LC messageElement* RC
+ ;
+
+messageElement
+ : field
+ | enumDef
+ | messageDef
+ | extendDef
+ | optionStatement
+ | oneof
+ | mapField
+ | reserved
+ | emptyStatement_
+ ;
+
+// Extend definition
+//
+// NB: not defined in the spec but supported by protoc and covered by protobuf3 tests
+// see e.g. php/tests/proto/test_import_descriptor_proto.proto
+// of https://github.com/protocolbuffers/protobuf
+// it also was discussed here: https://github.com/protocolbuffers/protobuf/issues/4610
+
+extendDef
+ : EXTEND messageType LC ( field
+ | emptyStatement_
+ )* RC
+ ;
+
+// service
+
+serviceDef
+ : SERVICE serviceName LC serviceElement* RC
+ ;
+
+serviceElement
+ : optionStatement
+ | rpc
+ | emptyStatement_
+ ;
+
+rpc
+ : RPC rpcName LP ( clientStreaming=STREAM )? messageType RP
+ RETURNS LP ( serverStreaming=STREAM )? messageType RP
+ (LC ( optionStatement | emptyStatement_ )* RC | SEMI)
+ ;
+
+// lexical
+
+constant
+ : fullIdent
+ | (MINUS | PLUS )? intLit
+ | ( MINUS | PLUS )? floatLit
+ | strLit
+ | boolLit
+ | blockLit
+ ;
+
+// not specified in specification but used in tests
+blockLit
+ : LC ( ident COLON constant )* RC
+ ;
+
+emptyStatement_: SEMI;
+
+// Lexical elements
+
+ident: IDENTIFIER | keywords;
+fullIdent: ident ( DOT ident )*;
+messageName: ident;
+enumName: ident;
+fieldName: ident;
+oneofName: ident;
+mapName: ident;
+serviceName: ident;
+rpcName: ident;
+messageType: ( DOT )? ( ident DOT )* messageName;
+enumType: ( DOT )? ( ident DOT )* enumName;
+
+intLit: INT_LIT;
+strLit: STR_LIT | PROTO3_LIT_SINGLE | PROTO3_LIT_DOBULE;
+boolLit: BOOL_LIT;
+floatLit: FLOAT_LIT;
+
+// keywords
+SYNTAX: 'syntax';
+IMPORT: 'import';
+WEAK: 'weak';
+PUBLIC: 'public';
+PACKAGE: 'package';
+OPTION: 'option';
+OPTIONAL: 'optional';
+REPEATED: 'repeated';
+ONEOF: 'oneof';
+MAP: 'map';
+INT32: 'int32';
+INT64: 'int64';
+UINT32: 'uint32';
+UINT64: 'uint64';
+SINT32: 'sint32';
+SINT64: 'sint64';
+FIXED32: 'fixed32';
+FIXED64: 'fixed64';
+SFIXED32: 'sfixed32';
+SFIXED64: 'sfixed64';
+BOOL: 'bool';
+STRING: 'string';
+DOUBLE: 'double';
+FLOAT: 'float';
+BYTES: 'bytes';
+RESERVED: 'reserved';
+TO: 'to';
+MAX: 'max';
+ENUM: 'enum';
+MESSAGE: 'message';
+SERVICE: 'service';
+EXTEND: 'extend';
+RPC: 'rpc';
+STREAM: 'stream';
+RETURNS: 'returns';
+
+PROTO3_LIT_SINGLE: '"proto3"';
+PROTO3_LIT_DOBULE: '\'proto3\'';
+
+// symbols
+
+SEMI: ';';
+EQ: '=';
+LP: '(';
+RP: ')';
+LB: '[';
+RB: ']';
+LC: '{';
+RC: '}';
+LT: '<';
+GT: '>';
+DOT: '.';
+COMMA: ',';
+COLON: ':';
+PLUS: '+';
+MINUS: '-';
+
+STR_LIT: ( '\'' ( CHAR_VALUE )*? '\'' ) | ( '"' ( CHAR_VALUE )*? '"' );
+fragment CHAR_VALUE: HEX_ESCAPE | OCT_ESCAPE | CHAR_ESCAPE | ~[\u0000\n\\];
+fragment HEX_ESCAPE: '\\' ( 'x' | 'X' ) HEX_DIGIT HEX_DIGIT;
+fragment OCT_ESCAPE: '\\' OCTAL_DIGIT OCTAL_DIGIT OCTAL_DIGIT;
+fragment CHAR_ESCAPE: '\\' ( 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v' | '\\' | '\'' | '"' );
+
+BOOL_LIT: 'true' | 'false';
+
+FLOAT_LIT : ( DECIMALS DOT DECIMALS? EXPONENT? | DECIMALS EXPONENT | DOT DECIMALS EXPONENT? ) | 'inf' | 'nan';
+fragment EXPONENT : ( 'e' | 'E' ) (PLUS | MINUS)? DECIMALS;
+fragment DECIMALS : DECIMAL_DIGIT+;
+
+INT_LIT : DECIMAL_LIT | OCTAL_LIT | HEX_LIT;
+fragment DECIMAL_LIT : ( [1-9] ) DECIMAL_DIGIT*;
+fragment OCTAL_LIT : '0' OCTAL_DIGIT*;
+fragment HEX_LIT : '0' ( 'x' | 'X' ) HEX_DIGIT+ ;
+
+IDENTIFIER: LETTER ( LETTER | DECIMAL_DIGIT )*;
+
+fragment LETTER: [A-Za-z_];
+fragment DECIMAL_DIGIT: [0-9];
+fragment OCTAL_DIGIT: [0-7];
+fragment HEX_DIGIT: [0-9A-Fa-f];
+
+// comments
+WS : [ \t\r\n\u000C]+ -> skip;
+LINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN);
+COMMENT: '/*' .*? '*/' -> channel(HIDDEN);
+
+keywords
+ : SYNTAX
+ | IMPORT
+ | WEAK
+ | PUBLIC
+ | PACKAGE
+ | OPTION
+ | OPTIONAL
+ | REPEATED
+ | ONEOF
+ | MAP
+ | INT32
+ | INT64
+ | UINT32
+ | UINT64
+ | SINT32
+ | SINT64
+ | FIXED32
+ | FIXED64
+ | SFIXED32
+ | SFIXED64
+ | BOOL
+ | STRING
+ | DOUBLE
+ | FLOAT
+ | BYTES
+ | RESERVED
+ | TO
+ | MAX
+ | ENUM
+ | MESSAGE
+ | SERVICE
+ | EXTEND
+ | RPC
+ | STREAM
+ | RETURNS
+ | BOOL_LIT
+ ;
diff --git a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfig.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/config/ProtobufModelConfig.java
similarity index 55%
rename from incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfig.java
rename to incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/config/ProtobufModelConfig.java
index 54ced3bb20..35da0ec2b4 100644
--- a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfig.java
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/config/ProtobufModelConfig.java
@@ -12,36 +12,37 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.avro.config;
+package io.aklivity.zilla.runtime.model.protobuf.config;
import java.util.List;
import java.util.function.Function;
import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
-public final class AvroValidatorConfig extends ValidatorConfig
+public final class ProtobufModelConfig extends ModelConfig
{
- public final List catalogs;
public final String subject;
+ public final String view;
- public AvroValidatorConfig(
- List catalogs,
- String subject)
+ public ProtobufModelConfig(
+ List cataloged,
+ String subject,
+ String view)
{
- super("avro");
- this.catalogs = catalogs;
+ super("protobuf", cataloged);
this.subject = subject;
+ this.view = view;
}
- public static AvroValidatorConfigBuilder builder(
- Function mapper)
+ public static ProtobufModelConfigBuilder builder(
+ Function mapper)
{
- return new AvroValidatorConfigBuilder<>(mapper::apply);
+ return new ProtobufModelConfigBuilder<>(mapper::apply);
}
- public static AvroValidatorConfigBuilder builder()
+ public static ProtobufModelConfigBuilder builder()
{
- return new AvroValidatorConfigBuilder<>(AvroValidatorConfig.class::cast);
+ return new ProtobufModelConfigBuilder<>(ProtobufModelConfig.class::cast);
}
}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/config/ProtobufModelConfigBuilder.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/config/ProtobufModelConfigBuilder.java
new file mode 100644
index 0000000000..86a17c2ac7
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/config/ProtobufModelConfigBuilder.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.config;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Function;
+
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder;
+import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
+
+public class ProtobufModelConfigBuilder extends ConfigBuilder>
+{
+ private final Function mapper;
+
+ private List catalogs;
+ private String subject;
+ private String view;
+
+ ProtobufModelConfigBuilder(
+ Function mapper)
+ {
+ this.mapper = mapper;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Class> thisType()
+ {
+ return (Class>) getClass();
+ }
+
+ public CatalogedConfigBuilder> catalog()
+ {
+ return CatalogedConfig.builder(this::catalog);
+ }
+
+ public ProtobufModelConfigBuilder subject(
+ String subject)
+ {
+ this.subject = subject;
+ return this;
+ }
+
+ public ProtobufModelConfigBuilder catalog(
+ CatalogedConfig catalog)
+ {
+ if (catalogs == null)
+ {
+ catalogs = new LinkedList<>();
+ }
+ catalogs.add(catalog);
+ return this;
+ }
+
+ public ProtobufModelConfigBuilder view(
+ String view)
+ {
+ this.view = view;
+ return this;
+ }
+
+ @Override
+ public T build()
+ {
+ return mapper.apply(new ProtobufModelConfig(catalogs, subject, view));
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/DescriptorTree.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/DescriptorTree.java
new file mode 100644
index 0000000000..8b7a3cd3b8
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/DescriptorTree.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+
+public class DescriptorTree
+{
+ protected final Map children;
+ protected final List indexes;
+
+ protected Descriptors.Descriptor descriptor;
+ protected String name;
+
+ private DescriptorTree()
+ {
+ this.children = new LinkedHashMap<>();
+ this.indexes = new LinkedList<>();
+ }
+
+ protected DescriptorTree(
+ FileDescriptor fileDescriptors)
+ {
+ this();
+ this.name = fileDescriptors.getPackage();
+ for (Descriptor descriptor : fileDescriptors.getMessageTypes())
+ {
+ addDescriptor(descriptor);
+ addNestedDescriptors(descriptor);
+ }
+ }
+
+ protected DescriptorTree findByName(
+ String path)
+ {
+ DescriptorTree current = this;
+ int start = 0;
+ int end;
+
+ while (start < path.length())
+ {
+ end = path.indexOf('.', start);
+ if (end == -1)
+ {
+ end = path.length();
+ }
+
+ String part = path.substring(start, end);
+ current = current.children.get(part);
+
+ if (current == null)
+ {
+ break;
+ }
+ start = end + 1;
+ }
+ return current;
+ }
+
+ protected Descriptor findByIndexes(
+ List indexes)
+ {
+ DescriptorTree current = this;
+
+ for (Integer index : indexes)
+ {
+ current = current.findChild(index);
+ if (current == null)
+ {
+ break;
+ }
+ }
+ return current != null ? current.descriptor : null;
+ }
+
+ private DescriptorTree findParent(
+ String path)
+ {
+ int index = path.lastIndexOf('.');
+ String part = index >= 0 ? path.substring(index + 1) : path;
+ return this.children.getOrDefault(part, null);
+ }
+
+ private DescriptorTree findChild(
+ int index)
+ {
+ DescriptorTree tree = this;
+ int currentIndex = 0;
+ for (Map.Entry entry : children.entrySet())
+ {
+ if (currentIndex == index)
+ {
+ tree = entry.getValue();
+ break;
+ }
+ currentIndex++;
+ }
+ return tree;
+ }
+
+ private void addNestedDescriptor(
+ Descriptor parent,
+ int index)
+ {
+ DescriptorTree parentNode = findParent(parent.getFullName());
+ if (parentNode != null)
+ {
+ Descriptors.Descriptor nestedDescriptor = parent.getNestedTypes().get(index);
+ parentNode.addDescriptor(nestedDescriptor);
+ parentNode.addNestedDescriptors(nestedDescriptor);
+ }
+ }
+
+ private void addDescriptor(
+ Descriptor descriptor)
+ {
+ DescriptorTree node = new DescriptorTree();
+ node.descriptor = descriptor;
+ node.name = name;
+ node.indexes.addAll(this.indexes);
+ node.indexes.add(this.children.size());
+ this.children.put(descriptor.getName(), node);
+ }
+
+ private void addNestedDescriptors(Descriptor descriptor)
+ {
+ for (int i = 0; i < descriptor.getNestedTypes().size(); i++)
+ {
+ addNestedDescriptor(descriptor, i);
+ }
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtoListener.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtoListener.java
new file mode 100644
index 0000000000..420278e4fd
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtoListener.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import static java.util.Map.entry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import com.google.protobuf.DescriptorProtos;
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Label;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type;
+import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
+
+import io.aklivity.zilla.runtime.model.protobuf.internal.parser.Protobuf3BaseListener;
+import io.aklivity.zilla.runtime.model.protobuf.internal.parser.Protobuf3Parser;
+
+public class ProtoListener extends Protobuf3BaseListener
+{
+ private static final Map TYPES = Map.ofEntries(
+ entry("double", Type.TYPE_DOUBLE),
+ entry("float", Type.TYPE_FLOAT),
+ entry("int32", Type.TYPE_INT32),
+ entry("int64", Type.TYPE_INT64),
+ entry("uint32", Type.TYPE_UINT32),
+ entry("uint64", Type.TYPE_UINT64),
+ entry("sint32", Type.TYPE_SINT32),
+ entry("sint64", Type.TYPE_SINT64),
+ entry("fixed32", Type.TYPE_FIXED32),
+ entry("fixed64", Type.TYPE_FIXED64),
+ entry("sfixed32", Type.TYPE_SFIXED32),
+ entry("sfixed64", Type.TYPE_SFIXED64),
+ entry("bool", Type.TYPE_BOOL),
+ entry("string", Type.TYPE_STRING),
+ entry("bytes", Type.TYPE_BYTES)
+ );
+
+ private static final Map LABELS = Map.ofEntries(
+ entry("optional", Label.LABEL_OPTIONAL),
+ entry("required", Label.LABEL_REQUIRED),
+ entry("repeated", Label.LABEL_REPEATED)
+ );
+
+ private String packageName;
+ private List imports;
+ private final FileDescriptorProto.Builder builder;
+ private Stack messageHierarchy = new Stack<>();
+
+ public ProtoListener()
+ {
+ this.imports = new ArrayList<>();
+ this.builder = FileDescriptorProto.newBuilder();
+ }
+
+ @Override
+ public void enterSyntax(
+ Protobuf3Parser.SyntaxContext ctx)
+ {
+ builder.setSyntax(ctx.getChild(2).getText());
+ }
+
+ @Override
+ public void enterPackageStatement(
+ Protobuf3Parser.PackageStatementContext ctx)
+ {
+ packageName = ctx.fullIdent().getText();
+ builder.setPackage(packageName);
+ }
+
+ @Override
+ public void enterImportStatement(
+ Protobuf3Parser.ImportStatementContext ctx)
+ {
+ String importStatement = ctx.strLit().getText();
+ imports.add(importStatement);
+ System.out.println("Import statements are currently not supported");
+ }
+
+ @Override
+ public void enterMessageDef(
+ Protobuf3Parser.MessageDefContext ctx)
+ {
+ DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+ String name = ctx.messageName().getText();
+ builder.setName(name);
+ messageHierarchy.push(name);
+
+ for (Protobuf3Parser.MessageElementContext element : ctx.messageBody().messageElement())
+ {
+ if (element.field() != null)
+ {
+ builder.addField(processFieldElement(element.field()));
+ }
+ if (element.messageDef() != null)
+ {
+ builder.addNestedType(processNestedMessage(element.messageDef()));
+ }
+ }
+ if (messageHierarchy.size() == 1)
+ {
+ this.builder.addMessageType(builder.build());
+ builder.clear();
+ }
+ }
+
+ @Override
+ public void exitMessageDef(
+ Protobuf3Parser.MessageDefContext ctx)
+ {
+ messageHierarchy.pop();
+ }
+
+ public DescriptorProtos.FileDescriptorProto build()
+ {
+ return builder.build();
+ }
+
+ private DescriptorProto processNestedMessage(
+ Protobuf3Parser.MessageDefContext ctx)
+ {
+ DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+ String name = ctx.messageName().getText();
+ builder.setName(name);
+
+ for (Protobuf3Parser.MessageElementContext element : ctx.messageBody().messageElement())
+ {
+ if (element.field() != null)
+ {
+ builder.addField(processFieldElement(element.field()));
+ }
+ if (element.messageDef() != null)
+ {
+ builder.addNestedType(processNestedMessage(element.messageDef()));
+ }
+ }
+ return builder.build();
+ }
+
+ private FieldDescriptorProto processFieldElement(
+ Protobuf3Parser.FieldContext ctx)
+ {
+ FieldDescriptorProto.Builder builder = FieldDescriptorProto.newBuilder();
+ String type = ctx.type_().getText();
+ String name = ctx.fieldName().getText();
+ String label = ctx.fieldLabel() != null ? ctx.fieldLabel().getText() : null;
+ int number = Integer.parseInt(ctx.fieldNumber().getText());
+
+ builder.setName(name);
+ builder.setNumber(number);
+ if (label != null)
+ {
+ builder.setLabel(LABELS.get(label));
+ }
+ if (TYPES.containsKey(type))
+ {
+ builder.setType(TYPES.get(type));
+ }
+ else
+ {
+ builder.setTypeName(type);
+ }
+ return builder.build();
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModel.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModel.java
new file mode 100644
index 0000000000..a5648f4288
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import java.net.URL;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+
+public class ProtobufModel implements Model
+{
+ public static final String NAME = "protobuf";
+
+ @Override
+ public String name()
+ {
+ return NAME;
+ }
+
+ @Override
+ public ModelContext supply(
+ EngineContext context)
+ {
+ return new ProtobufModelContext(context);
+ }
+
+ @Override
+ public URL type()
+ {
+ return getClass().getResource("schema/protobuf.schema.patch.json");
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelContext.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelContext.java
new file mode 100644
index 0000000000..6998afb18c
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelContext.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import java.util.function.LongFunction;
+
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public class ProtobufModelContext implements ModelContext
+{
+ private final LongFunction supplyCatalog;
+
+ public ProtobufModelContext(
+ EngineContext context)
+ {
+ this.supplyCatalog = context::supplyCatalog;
+ }
+
+ @Override
+ public ConverterHandler supplyReadConverterHandler(
+ ModelConfig config)
+ {
+ return new ProtobufReadConverterHandler(ProtobufModelConfig.class.cast(config), supplyCatalog);
+ }
+
+ @Override
+ public ConverterHandler supplyWriteConverterHandler(
+ ModelConfig config)
+ {
+ return new ProtobufWriteConverterHandler(ProtobufModelConfig.class.cast(config), supplyCatalog);
+ }
+}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigAdapter.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelFactorySpi.java
similarity index 50%
rename from incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigAdapter.java
rename to incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelFactorySpi.java
index 69f57d0f9b..4804dbef38 100644
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigAdapter.java
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelFactorySpi.java
@@ -12,34 +12,33 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.core.config;
+package io.aklivity.zilla.runtime.model.protobuf.internal;
-import jakarta.json.Json;
-import jakarta.json.JsonValue;
-import jakarta.json.bind.adapter.JsonbAdapter;
+import java.net.URL;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi;
+import io.aklivity.zilla.runtime.common.feature.Incubating;
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelFactorySpi;
-public class LongValidatorConfigAdapter implements ValidatorConfigAdapterSpi, JsonbAdapter
+@Incubating
+public final class ProtobufModelFactorySpi implements ModelFactorySpi
{
@Override
public String type()
{
- return "long";
+ return ProtobufModel.NAME;
}
- @Override
- public JsonValue adaptToJson(
- ValidatorConfig options)
+ public URL schema()
{
- return Json.createValue(type());
+ return getClass().getResource("schema/protobuf.schema.patch.json");
}
@Override
- public ValidatorConfig adaptFromJson(
- JsonValue object)
+ public Model create(
+ Configuration config)
{
- return new LongValidatorConfig();
+ return new ProtobufModel();
}
}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelHandler.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelHandler.java
new file mode 100644
index 0000000000..39dd41e64c
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelHandler.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.LongFunction;
+
+import org.agrona.BitUtil;
+import org.agrona.DirectBuffer;
+import org.agrona.ExpandableDirectByteBuffer;
+import org.agrona.collections.Int2IntHashMap;
+import org.agrona.collections.Int2ObjectCache;
+import org.agrona.collections.Object2ObjectHashMap;
+import org.agrona.io.DirectBufferInputStream;
+import org.agrona.io.ExpandableDirectBufferOutputStream;
+import org.antlr.v4.runtime.BailErrorStrategy;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.Descriptors.DescriptorValidationException;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.DynamicMessage;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+import io.aklivity.zilla.runtime.model.protobuf.internal.parser.Protobuf3Lexer;
+import io.aklivity.zilla.runtime.model.protobuf.internal.parser.Protobuf3Parser;
+
+public class ProtobufModelHandler
+{
+ protected static final byte[] ZERO_INDEX = new byte[]{0x0};
+ protected static final String VIEW_JSON = "json";
+
+ private static final int JSON_FIELD_STRUCTURE_LENGTH = "\"\":\"\",".length();
+ private static final int JSON_OBJECT_CURLY_BRACES = 2;
+
+ protected final SchemaConfig catalog;
+ protected final CatalogHandler handler;
+ protected final String subject;
+ protected final String view;
+ protected final List indexes;
+ protected final DirectBufferInputStream in;
+ protected final ExpandableDirectBufferOutputStream out;
+
+ private final Int2ObjectCache descriptors;
+ private final Int2ObjectCache tree;
+ private final Object2ObjectHashMap builders;
+ private final FileDescriptor[] dependencies;
+ private final Int2IntHashMap paddings;
+
+ protected ProtobufModelHandler(
+ ProtobufModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ CatalogedConfig cataloged = config.cataloged.get(0);
+ this.handler = supplyCatalog.apply(cataloged.id);
+ this.catalog = cataloged.schemas.size() != 0 ? cataloged.schemas.get(0) : null;
+ this.subject = catalog != null && catalog.subject != null
+ ? catalog.subject
+ : config.subject;
+ this.view = config.view;
+ this.descriptors = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.tree = new Int2ObjectCache<>(1, 1024, i -> {});
+ this.builders = new Object2ObjectHashMap<>();
+ this.in = new DirectBufferInputStream();
+ this.dependencies = new FileDescriptor[0];
+ this.indexes = new LinkedList<>();
+ this.paddings = new Int2IntHashMap(-1);
+ this.out = new ExpandableDirectBufferOutputStream(new ExpandableDirectByteBuffer());
+ }
+
+ protected FileDescriptor supplyDescriptor(
+ int schemaId)
+ {
+ return descriptors.computeIfAbsent(schemaId, this::createDescriptors);
+ }
+
+ protected DescriptorTree supplyDescriptorTree(
+ int schemaId)
+ {
+ return tree.computeIfAbsent(schemaId, this::createDescriptorTree);
+ }
+
+ protected byte[] encodeIndexes()
+ {
+ int size = indexes.size();
+
+ byte[] indexes = new byte[size * 5];
+
+ int index = 0;
+ for (int i = 0; i < size; i++)
+ {
+ int entry = this.indexes.get(i);
+ int value = (entry << 1) ^ (entry >> 31);
+ while ((value & ~0x7F) != 0)
+ {
+ indexes[index++] = (byte) ((value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ indexes[index++] = (byte) value;
+ }
+
+ return Arrays.copyOf(indexes, index);
+ }
+
+ protected int decodeIndexes(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ int progress = 0;
+ indexes.clear();
+ int encodedLength = decodeIndex(data.getByte(index));
+ progress += BitUtil.SIZE_OF_BYTE;
+ if (encodedLength == 0)
+ {
+ indexes.add(encodedLength);
+ }
+ for (int i = 0; i < encodedLength; i++)
+ {
+ indexes.add(decodeIndex(data.getByte(index + progress)));
+ progress += BitUtil.SIZE_OF_BYTE;
+ }
+ return progress;
+ }
+
+ protected int supplyIndexPadding(
+ int schemaId)
+ {
+ return paddings.computeIfAbsent(schemaId, this::calculateIndexPadding);
+ }
+
+ protected int supplyJsonFormatPadding(
+ int schemaId)
+ {
+ return paddings.computeIfAbsent(schemaId, id -> calculateJsonFormatPadding(supplyDescriptor(id)));
+ }
+
+ protected DynamicMessage.Builder supplyDynamicMessageBuilder(
+ Descriptors.Descriptor descriptor)
+ {
+ DynamicMessage.Builder builder;
+ if (builders.containsKey(descriptor.getFullName()))
+ {
+ builder = builders.get(descriptor.getFullName());
+ }
+ else
+ {
+ builder = createDynamicMessageBuilder(descriptor);
+ builders.put(descriptor.getFullName(), builder);
+ }
+ return builder;
+ }
+
+ private DynamicMessage.Builder createDynamicMessageBuilder(
+ Descriptors.Descriptor descriptor)
+ {
+ return DynamicMessage.newBuilder(descriptor);
+ }
+
+ private int decodeIndex(
+ byte encodedByte)
+ {
+ int result = 0;
+ int shift = 0;
+ do
+ {
+ result |= (encodedByte & 0x7F) << shift;
+ shift += 7;
+ }
+ while ((encodedByte & 0x80) != 0);
+ return (result >>> 1) ^ -(result & 1);
+ }
+
+ private int calculateIndexPadding(
+ int schemaId)
+ {
+ int padding = 0;
+ DescriptorTree trees = supplyDescriptorTree(schemaId);
+ if (trees != null && catalog.record != null)
+ {
+ DescriptorTree tree = trees.findByName(catalog.record);
+ if (tree != null)
+ {
+ padding = tree.indexes.size() + 1;
+ }
+ }
+ return padding;
+ }
+
+ private int calculateJsonFormatPadding(
+ FileDescriptor descriptor)
+ {
+ int padding = 0;
+
+ if (descriptor != null)
+ {
+ for (Descriptors.Descriptor message : descriptor.getMessageTypes())
+ {
+ padding += JSON_OBJECT_CURLY_BRACES;
+ for (Descriptors.FieldDescriptor field : message.getFields())
+ {
+ padding += field.getName().getBytes().length + JSON_FIELD_STRUCTURE_LENGTH;
+ }
+ }
+
+ }
+ return padding;
+ }
+
+ private FileDescriptor createDescriptors(
+ int schemaId)
+ {
+ FileDescriptor descriptor = null;
+
+ String schemaText = handler.resolve(schemaId);
+ if (schemaText != null)
+ {
+ CharStream input = CharStreams.fromString(schemaText);
+ Protobuf3Lexer lexer = new Protobuf3Lexer(input);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+ Protobuf3Parser parser = new Protobuf3Parser(tokens);
+ parser.setErrorHandler(new BailErrorStrategy());
+ ParseTreeWalker walker = new ParseTreeWalker();
+
+ ProtoListener listener = new ProtoListener();
+ walker.walk(listener, parser.proto());
+
+ try
+ {
+ descriptor = FileDescriptor.buildFrom(listener.build(), dependencies);
+ }
+ catch (DescriptorValidationException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ return descriptor;
+ }
+
+ private DescriptorTree createDescriptorTree(
+ int schemaId)
+ {
+ DescriptorTree tree = null;
+ FileDescriptor descriptor = supplyDescriptor(schemaId);
+
+ if (descriptor != null)
+ {
+ tree = new DescriptorTree(descriptor);
+ }
+ return tree;
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufReadConverterHandler.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufReadConverterHandler.java
new file mode 100644
index 0000000000..495c736f0b
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufReadConverterHandler.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import static io.aklivity.zilla.runtime.engine.catalog.CatalogHandler.NO_SCHEMA_ID;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.util.JsonFormat;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public class ProtobufReadConverterHandler extends ProtobufModelHandler implements ConverterHandler
+{
+ private final JsonFormat.Printer printer;
+ private final OutputStreamWriter output;
+
+ public ProtobufReadConverterHandler(
+ ProtobufModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ this.printer = JsonFormat.printer()
+ .omittingInsignificantWhitespace()
+ .preservingProtoFieldNames()
+ .includingDefaultValueFields();
+ this.output = new OutputStreamWriter(out);
+ }
+
+ @Override
+ public int padding(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ int padding = 0;
+ if (VIEW_JSON.equals(view))
+ {
+ int schemaId = handler.resolve(data, index, length);
+
+ if (schemaId == NO_SCHEMA_ID)
+ {
+ schemaId = catalog.id != NO_SCHEMA_ID
+ ? catalog.id
+ : handler.resolve(subject, catalog.version);
+ }
+ padding = supplyJsonFormatPadding(schemaId);
+ }
+ return padding;
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ return handler.decode(data, index, length, next, this::decodePayload);
+ }
+
+ private int decodePayload(
+ int schemaId,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ if (schemaId == NO_SCHEMA_ID)
+ {
+ if (catalog.id != NO_SCHEMA_ID)
+ {
+ schemaId = catalog.id;
+ }
+ else
+ {
+ schemaId = handler.resolve(subject, catalog.version);
+ }
+ }
+
+ int progress = decodeIndexes(data, index, length);
+
+ return validate(schemaId, data, index + progress, length - progress, next);
+ }
+
+ private int validate(
+ int schemaId,
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+ DescriptorTree tree = supplyDescriptorTree(schemaId);
+ if (tree != null)
+ {
+ Descriptors.Descriptor descriptor = tree.findByIndexes(indexes);
+ if (descriptor != null)
+ {
+ in.wrap(data, index, length);
+ DynamicMessage.Builder builder = supplyDynamicMessageBuilder(descriptor);
+ validate:
+ try
+ {
+ DynamicMessage message = builder.mergeFrom(in).build();
+ builder.clear();
+ if (!message.getUnknownFields().asMap().isEmpty())
+ {
+ break validate;
+ }
+
+ if (VIEW_JSON.equals(view))
+ {
+ out.wrap(out.buffer());
+ printer.appendTo(message, output);
+ output.flush();
+ valLength = out.position();
+ next.accept(out.buffer(), 0, valLength);
+ }
+ else
+ {
+ next.accept(data, index, length);
+ valLength = length;
+ }
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+ return valLength;
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufWriteConverterHandler.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufWriteConverterHandler.java
new file mode 100644
index 0000000000..d711d841ac
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufWriteConverterHandler.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.agrona.io.DirectBufferInputStream;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.util.JsonFormat;
+
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.model.ConverterHandler;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public class ProtobufWriteConverterHandler extends ProtobufModelHandler implements ConverterHandler
+{
+ private final DirectBuffer indexesRO;
+ private final InputStreamReader input;
+ private final DirectBufferInputStream in;
+ private final JsonFormat.Parser parser;
+
+ public ProtobufWriteConverterHandler(
+ ProtobufModelConfig config,
+ LongFunction supplyCatalog)
+ {
+ super(config, supplyCatalog);
+ this.indexesRO = new UnsafeBuffer();
+ this.in = new DirectBufferInputStream();
+ this.input = new InputStreamReader(in);
+ this.parser = JsonFormat.parser();
+ }
+
+ @Override
+ public int padding(
+ DirectBuffer data,
+ int index,
+ int length)
+ {
+ int schemaId = catalog != null && catalog.id > 0
+ ? catalog.id
+ : handler.resolve(subject, catalog.version);
+
+ return handler.encodePadding() + supplyIndexPadding(schemaId);
+ }
+
+ @Override
+ public int convert(
+ DirectBuffer data,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+
+ int schemaId = catalog != null && catalog.id > 0
+ ? catalog.id
+ : handler.resolve(subject, catalog.version);
+
+ if (VIEW_JSON.equals(view))
+ {
+ valLength = handler.encode(schemaId, data, index, length, next, this::serializeJsonRecord);
+ }
+ else if (validate(schemaId, data, index, length))
+ {
+ valLength = handler.encode(schemaId, data, index, length, next, this::encode);
+ }
+ return valLength;
+ }
+
+ private boolean validate(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ boolean status = false;
+ DescriptorTree trees = supplyDescriptorTree(schemaId);
+ if (trees != null && catalog.record != null)
+ {
+ DescriptorTree tree = trees.findByName(catalog.record);
+ if (tree != null)
+ {
+ Descriptors.Descriptor descriptor = tree.descriptor;
+ indexes.clear();
+ indexes.add(tree.indexes.size());
+ indexes.addAll(tree.indexes);
+ in.wrap(buffer, index, length);
+ DynamicMessage.Builder builder = supplyDynamicMessageBuilder(descriptor);
+ try
+ {
+ DynamicMessage message = builder.mergeFrom(in).build();
+ builder.clear();
+ status = message.getUnknownFields().asMap().isEmpty();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+ return status;
+ }
+
+ private int encode(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+ if (indexes.size() == 2 && indexes.get(0) == 1 && indexes.get(1) == 0)
+ {
+ indexesRO.wrap(ZERO_INDEX);
+ valLength = 1;
+ }
+ else
+ {
+ indexesRO.wrap(encodeIndexes());
+ valLength = indexes.size();
+ }
+ indexes.clear();
+ next.accept(indexesRO, 0, valLength);
+ next.accept(buffer, index, length);
+ return valLength + length;
+ }
+
+ private int serializeJsonRecord(
+ int schemaId,
+ DirectBuffer buffer,
+ int index,
+ int length,
+ ValueConsumer next)
+ {
+ int valLength = -1;
+ DescriptorTree tree = supplyDescriptorTree(schemaId);
+ if (tree != null && catalog.record != null)
+ {
+ tree = tree.findByName(catalog.record);
+ if (tree != null)
+ {
+ Descriptors.Descriptor descriptor = tree.descriptor;
+ indexes.clear();
+ indexes.add(tree.indexes.size());
+ indexes.addAll(tree.indexes);
+ DynamicMessage.Builder builder = supplyDynamicMessageBuilder(descriptor);
+ in.wrap(buffer, index, length);
+ try
+ {
+ parser.merge(input, builder);
+ DynamicMessage message = builder.build();
+ builder.clear();
+ if (message.isInitialized() && message.getUnknownFields().asMap().isEmpty())
+ {
+ out.wrap(out.buffer());
+ message.writeTo(out);
+ valLength = encode(schemaId, out.buffer(), 0, out.position(), next);
+ }
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+ return valLength;
+ }
+}
diff --git a/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/config/ProtobufModelConfigAdapter.java b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/config/ProtobufModelConfigAdapter.java
new file mode 100644
index 0000000000..495eff2ca7
--- /dev/null
+++ b/incubator/model-protobuf/src/main/java/io/aklivity/zilla/runtime/model/protobuf/internal/config/ProtobufModelConfigAdapter.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal.config;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonArrayBuilder;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.JsonValue;
+import jakarta.json.bind.adapter.JsonbAdapter;
+
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfigAdapter;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public final class ProtobufModelConfigAdapter implements ModelConfigAdapterSpi, JsonbAdapter
+{
+ private static final String PROTOBUF = "protobuf";
+ private static final String MODEL_NAME = "model";
+ private static final String CATALOG_NAME = "catalog";
+ private static final String SUBJECT_NAME = "subject";
+ private static final String VIEW = "view";
+
+ private final SchemaConfigAdapter schema = new SchemaConfigAdapter();
+
+ @Override
+ public String type()
+ {
+ return PROTOBUF;
+ }
+
+ @Override
+ public JsonValue adaptToJson(
+ ModelConfig config)
+ {
+ ProtobufModelConfig protobufConfig = (ProtobufModelConfig) config;
+ JsonObjectBuilder converter = Json.createObjectBuilder();
+ converter.add(MODEL_NAME, PROTOBUF);
+
+ if (protobufConfig.view != null)
+ {
+ converter.add(VIEW, protobufConfig.view);
+ }
+
+ if (protobufConfig.cataloged != null && !protobufConfig.cataloged.isEmpty())
+ {
+ JsonObjectBuilder catalogs = Json.createObjectBuilder();
+ for (CatalogedConfig catalog : protobufConfig.cataloged)
+ {
+ JsonArrayBuilder array = Json.createArrayBuilder();
+ for (SchemaConfig schemaItem: catalog.schemas)
+ {
+ array.add(schema.adaptToJson(schemaItem));
+ }
+ catalogs.add(catalog.name, array);
+ }
+ converter.add(CATALOG_NAME, catalogs);
+ }
+ return converter.build();
+ }
+
+ @Override
+ public ModelConfig adaptFromJson(
+ JsonValue value)
+ {
+ JsonObject object = (JsonObject) value;
+
+ assert object.containsKey(CATALOG_NAME);
+
+ JsonObject catalogsJson = object.getJsonObject(CATALOG_NAME);
+ List catalogs = new LinkedList<>();
+ for (String catalogName: catalogsJson.keySet())
+ {
+ JsonArray schemasJson = catalogsJson.getJsonArray(catalogName);
+ List schemas = new LinkedList<>();
+ for (JsonValue item : schemasJson)
+ {
+ JsonObject schemaJson = (JsonObject) item;
+ SchemaConfig schemaElement = schema.adaptFromJson(schemaJson);
+ schemas.add(schemaElement);
+ }
+ catalogs.add(new CatalogedConfig(catalogName, schemas));
+ }
+
+ String subject = object.containsKey(SUBJECT_NAME)
+ ? object.getString(SUBJECT_NAME)
+ : null;
+
+ String view = object.containsKey(VIEW)
+ ? object.getString(VIEW)
+ : null;
+
+ return new ProtobufModelConfig(catalogs, subject, view);
+ }
+}
diff --git a/incubator/model-protobuf/src/main/moditect/module-info.java b/incubator/model-protobuf/src/main/moditect/module-info.java
new file mode 100644
index 0000000000..3fc4b59e58
--- /dev/null
+++ b/incubator/model-protobuf/src/main/moditect/module-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+module io.aklivity.zilla.runtime.model.protobuf
+{
+ requires org.antlr.antlr4.runtime;
+ requires protobuf.java;
+ requires io.aklivity.zilla.runtime.engine;
+
+ exports io.aklivity.zilla.runtime.model.protobuf.config;
+
+ provides io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
+ with io.aklivity.zilla.runtime.model.protobuf.internal.config.ProtobufModelConfigAdapter;
+
+ provides io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
+ with io.aklivity.zilla.runtime.model.protobuf.internal.ProtobufModelFactorySpi;
+}
diff --git a/incubator/model-protobuf/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi b/incubator/model-protobuf/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
new file mode 100644
index 0000000000..187d9d722b
--- /dev/null
+++ b/incubator/model-protobuf/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ModelConfigAdapterSpi
@@ -0,0 +1 @@
+io.aklivity.zilla.runtime.model.protobuf.internal.config.ProtobufModelConfigAdapter
diff --git a/incubator/model-protobuf/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi b/incubator/model-protobuf/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
new file mode 100644
index 0000000000..98f696ae0b
--- /dev/null
+++ b/incubator/model-protobuf/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.model.ModelFactorySpi
@@ -0,0 +1 @@
+io.aklivity.zilla.runtime.model.protobuf.internal.ProtobufModelFactorySpi
diff --git a/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelFactorySpiTest.java b/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelFactorySpiTest.java
new file mode 100644
index 0000000000..27a7f643a5
--- /dev/null
+++ b/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelFactorySpiTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.config.ModelConfig;
+import io.aklivity.zilla.runtime.engine.model.Model;
+import io.aklivity.zilla.runtime.engine.model.ModelContext;
+import io.aklivity.zilla.runtime.engine.model.ModelFactory;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public class ProtobufModelFactorySpiTest
+{
+ @Test
+ public void shouldLoadAndCreate()
+ {
+ Configuration config = new Configuration();
+ ModelFactory factory = ModelFactory.instantiate();
+ Model model = factory.create("protobuf", config);
+
+ ModelContext context = new ProtobufModelContext(mock(EngineContext.class));
+
+ ModelConfig modelConfig = ProtobufModelConfig.builder()
+ .subject("test-value")
+ .catalog()
+ .name("test0")
+ .schema()
+ .subject("subject1")
+ .version("latest")
+ .build()
+ .build()
+ .build();
+
+ assertThat(model, instanceOf(ProtobufModel.class));
+ assertThat(context.supplyReadConverterHandler(modelConfig), instanceOf(ProtobufReadConverterHandler.class));
+ assertThat(context.supplyWriteConverterHandler(modelConfig), instanceOf(ProtobufWriteConverterHandler.class));
+ }
+}
diff --git a/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelTest.java b/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelTest.java
new file mode 100644
index 0000000000..746e46f8d9
--- /dev/null
+++ b/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/ProtobufModelTest.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.model.protobuf.internal;
+
+import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_DIRECTORY;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+import java.util.function.LongFunction;
+
+import org.agrona.DirectBuffer;
+import org.agrona.concurrent.UnsafeBuffer;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.engine.Configuration;
+import io.aklivity.zilla.runtime.engine.EngineContext;
+import io.aklivity.zilla.runtime.engine.catalog.Catalog;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogContext;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
+import io.aklivity.zilla.runtime.engine.config.CatalogConfig;
+import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer;
+import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalog;
+import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public class ProtobufModelTest
+{
+ private static final String SCHEMA = "syntax = \"proto3\";" +
+ "package io.aklivity.examples.clients.proto;" +
+ "message SimpleMessage " +
+ "{ " +
+ "string content = 1;" +
+ "optional string date_time = 2;" +
+ "message DeviceMessage2 " +
+ "{ " +
+ "int32 id = 1;" +
+ "message DeviceMessage6 " +
+ "{ " +
+ "int32 id = 1;" +
+ "}" +
+ "}" +
+ "DeviceMessage2 device = 3;" +
+ "}" +
+ "message DemoMessage " +
+ "{ " +
+ "string status = 1;" +
+ "message DeviceMessage " +
+ "{ " +
+ "int32 id = 1;" +
+ "}" +
+ "message DeviceMessage1 " +
+ "{ " +
+ "int32 id = 1;" +
+ "}" +
+ "optional string date_time = 2;" +
+ "message SimpleMessage " +
+ "{ " +
+ "string content = 1;" +
+ "optional string date_time = 2;" +
+ "}" +
+ "}";
+ private CatalogContext context;
+
+ @Before
+ public void init()
+ {
+ Properties properties = new Properties();
+ properties.setProperty(ENGINE_DIRECTORY.name(), "target/zilla-itests");
+ Configuration config = new Configuration(properties);
+ Catalog catalog = new TestCatalog(config);
+ context = catalog.supply(mock(EngineContext.class));
+ }
+
+ @Test
+ public void shouldWriteValidProtobufEvent()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .record("SimpleMessage")
+ .build()
+ .build()
+ .build();
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufWriteConverterHandler converter = new ProtobufWriteConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity() + 1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+
+ assertEquals(data.capacity() + 1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldWriteValidProtobufEventNestedMessage()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .record("DemoMessage.SimpleMessage")
+ .build()
+ .build()
+ .build();
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufWriteConverterHandler converter = new ProtobufWriteConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity() + 3, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldWriteValidProtobufEventIncorrectRecordName()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .record("DemoMessage.IncorrectRecord")
+ .build()
+ .build()
+ .build();
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufWriteConverterHandler converter = new ProtobufWriteConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(-1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldReadValidProtobufEvent()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufReadConverterHandler converter = new ProtobufReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x00, 0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity() - 1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+
+ assertEquals(data.capacity() - 1, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldReadValidProtobufEventNestedMessage()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufReadConverterHandler converter = new ProtobufReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x04, 0x02, 0x04, 0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ data.wrap(bytes, 0, bytes.length);
+ assertEquals(data.capacity() - 3, converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldReadValidProtobufEventFormatJson()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufReadConverterHandler converter = new ProtobufReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ byte[] bytes = {0x00, 0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ data.wrap(bytes, 0, bytes.length);
+
+ String json =
+ "{" +
+ "\"content\":\"OK\"," +
+ "\"date_time\":\"01012024\"" +
+ "}";
+
+ final ValueConsumer consumer = (buffer, index, length) ->
+ {
+ byte[] jsonBytes = new byte[length];
+ buffer.getBytes(index, jsonBytes);
+ assertEquals(json, new String(jsonBytes, StandardCharsets.UTF_8));
+ };
+ converter.convert(data, 0, data.capacity(), consumer);
+
+ converter.convert(data, 0, data.capacity(), consumer);
+ }
+
+ @Test
+ public void shouldWriteValidProtobufEventFormatJson()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(1)
+ .schema(SCHEMA)
+ .build());
+
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .record("SimpleMessage")
+ .build()
+ .build()
+ .build();
+
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufWriteConverterHandler converter = new ProtobufWriteConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ String json =
+ "{" +
+ "\"content\":\"OK\"," +
+ "\"date_time\":\"01012024\"" +
+ "}";
+ data.wrap(json.getBytes(), 0, json.getBytes().length);
+
+ byte[] expectedBytes = {0x00, 0x0a, 0x02, 0x4f, 0x4b, 0x12, 0x08, 0x30, 0x31, 0x30, 0x31, 0x32, 0x30, 0x32, 0x34};
+ DirectBuffer expected = new UnsafeBuffer();
+ expected.wrap(expectedBytes, 0, expectedBytes.length);
+
+ assertEquals(expected.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+
+ assertEquals(expected.capacity(), converter.convert(data, 0, data.capacity(), ValueConsumer.NOP));
+ }
+
+ @Test
+ public void shouldVerifyJsonFormatPaddingLength()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .view("json")
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .build()
+ .build()
+ .build();
+ ProtobufReadConverterHandler converter = new ProtobufReadConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ assertEquals(71, converter.padding(data, 0, data.capacity()));
+ }
+
+ @Test
+ public void shouldVerifyIndexPaddingLength()
+ {
+ CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test",
+ TestCatalogOptionsConfig.builder()
+ .id(9)
+ .schema(SCHEMA)
+ .build());
+ LongFunction handler = value -> context.attach(catalogConfig);
+ ProtobufModelConfig config = ProtobufModelConfig.builder()
+ .catalog()
+ .name("test0")
+ .schema()
+ .strategy("topic")
+ .version("latest")
+ .subject("test-value")
+ .record("DemoMessage.SimpleMessage")
+ .build()
+ .build()
+ .build();
+ ProtobufWriteConverterHandler converter = new ProtobufWriteConverterHandler(config, handler);
+
+ DirectBuffer data = new UnsafeBuffer();
+
+ assertEquals(3, converter.padding(data, 0, data.capacity()));
+
+ }
+}
diff --git a/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigAdapterTest.java b/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/config/ProtobufModelConfigAdapterTest.java
similarity index 65%
rename from incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigAdapterTest.java
rename to incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/config/ProtobufModelConfigAdapterTest.java
index 4e7e123c98..9c95ad4832 100644
--- a/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigAdapterTest.java
+++ b/incubator/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/config/ProtobufModelConfigAdapterTest.java
@@ -12,7 +12,7 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.validator.avro.config;
+package io.aklivity.zilla.runtime.model.protobuf.internal.config;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@@ -26,7 +26,9 @@
import org.junit.Before;
import org.junit.Test;
-public class AvroValidatorConfigAdapterTest
+import io.aklivity.zilla.runtime.model.protobuf.config.ProtobufModelConfig;
+
+public class ProtobufModelConfigAdapterTest
{
private Jsonb jsonb;
@@ -34,17 +36,17 @@ public class AvroValidatorConfigAdapterTest
public void initJson()
{
JsonbConfig config = new JsonbConfig()
- .withAdapters(new AvroValidatorConfigAdapter());
+ .withAdapters(new ProtobufModelConfigAdapter());
jsonb = JsonbBuilder.create(config);
}
@Test
- public void shouldReadAvroValidator()
+ public void shouldReadAvroConverter()
{
// GIVEN
String json =
"{" +
- "\"type\": \"avro\"," +
+ "\"model\": \"protobuf\"," +
"\"catalog\":" +
"{" +
"\"test0\":" +
@@ -65,32 +67,32 @@ public void shouldReadAvroValidator()
"}";
// WHEN
- AvroValidatorConfig validator = jsonb.fromJson(json, AvroValidatorConfig.class);
+ ProtobufModelConfig converter = jsonb.fromJson(json, ProtobufModelConfig.class);
// THEN
- assertThat(validator, not(nullValue()));
- assertThat(validator.type, equalTo("avro"));
- assertThat(validator.catalogs.size(), equalTo(1));
- assertThat(validator.catalogs.get(0).name, equalTo("test0"));
- assertThat(validator.catalogs.get(0).schemas.get(0).strategy, equalTo("topic"));
- assertThat(validator.catalogs.get(0).schemas.get(0).version, equalTo("latest"));
- assertThat(validator.catalogs.get(0).schemas.get(0).id, equalTo(0));
- assertThat(validator.catalogs.get(0).schemas.get(1).subject, equalTo("cat"));
- assertThat(validator.catalogs.get(0).schemas.get(1).strategy, nullValue());
- assertThat(validator.catalogs.get(0).schemas.get(1).version, equalTo("latest"));
- assertThat(validator.catalogs.get(0).schemas.get(1).id, equalTo(0));
- assertThat(validator.catalogs.get(0).schemas.get(2).strategy, nullValue());
- assertThat(validator.catalogs.get(0).schemas.get(2).version, nullValue());
- assertThat(validator.catalogs.get(0).schemas.get(2).id, equalTo(42));
+ assertThat(converter, not(nullValue()));
+ assertThat(converter.model, equalTo("protobuf"));
+ assertThat(converter.cataloged.size(), equalTo(1));
+ assertThat(converter.cataloged.get(0).name, equalTo("test0"));
+ assertThat(converter.cataloged.get(0).schemas.get(0).strategy, equalTo("topic"));
+ assertThat(converter.cataloged.get(0).schemas.get(0).version, equalTo("latest"));
+ assertThat(converter.cataloged.get(0).schemas.get(0).id, equalTo(0));
+ assertThat(converter.cataloged.get(0).schemas.get(1).subject, equalTo("cat"));
+ assertThat(converter.cataloged.get(0).schemas.get(1).strategy, nullValue());
+ assertThat(converter.cataloged.get(0).schemas.get(1).version, equalTo("latest"));
+ assertThat(converter.cataloged.get(0).schemas.get(1).id, equalTo(0));
+ assertThat(converter.cataloged.get(0).schemas.get(2).strategy, nullValue());
+ assertThat(converter.cataloged.get(0).schemas.get(2).version, nullValue());
+ assertThat(converter.cataloged.get(0).schemas.get(2).id, equalTo(42));
}
@Test
- public void shouldWriteAvroValidator()
+ public void shouldWriteAvroConverter()
{
// GIVEN
String expectedJson =
"{" +
- "\"type\":\"avro\"," +
+ "\"model\":\"protobuf\"," +
"\"catalog\":" +
"{" +
"\"test0\":" +
@@ -109,7 +111,7 @@ public void shouldWriteAvroValidator()
"]" +
"}" +
"}";
- AvroValidatorConfig validator = AvroValidatorConfig.builder()
+ ProtobufModelConfig converter = ProtobufModelConfig.builder()
.catalog()
.name("test0")
.schema()
@@ -127,7 +129,7 @@ public void shouldWriteAvroValidator()
.build();
// WHEN
- String json = jsonb.toJson(validator);
+ String json = jsonb.toJson(converter);
// THEN
assertThat(json, not(nullValue()));
diff --git a/incubator/pom.xml b/incubator/pom.xml
index 83e67412d4..48c1798af4 100644
--- a/incubator/pom.xml
+++ b/incubator/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.66
+ 0.9.67
../pom.xml
@@ -21,9 +21,10 @@
catalog-inline.spec
catalog-schema-registry.spec
exporter-otlp.spec
- validator-avro.spec
- validator-core.spec
- validator-json.spec
+ model-avro.spec
+ model-core.spec
+ model-json.spec
+ model-protobuf.spec
binding-amqp
@@ -37,9 +38,10 @@
exporter-otlp
- validator-avro
- validator-core
- validator-json
+ model-avro
+ model-core
+ model-json
+ model-protobuf
@@ -86,17 +88,22 @@
${project.groupId}
- validator-avro
+ model-avro
${project.version}
${project.groupId}
- validator-core
+ model-core
${project.version}
${project.groupId}
- validator-json
+ model-json
+ ${project.version}
+
+
+ ${project.groupId}
+ model-protobuf
${project.version}
diff --git a/incubator/validator-avro.spec/src/main/scripts/io/aklivity/zilla/specs/validator/avro/schema/avro.schema.patch.json b/incubator/validator-avro.spec/src/main/scripts/io/aklivity/zilla/specs/validator/avro/schema/avro.schema.patch.json
deleted file mode 100644
index 1d451f5fb2..0000000000
--- a/incubator/validator-avro.spec/src/main/scripts/io/aklivity/zilla/specs/validator/avro/schema/avro.schema.patch.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- {
- "op": "add",
- "path": "/$defs/validator/types/enum/-",
- "value": "avro"
- }
-]
diff --git a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/AvroValidator.java b/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/AvroValidator.java
deleted file mode 100644
index 3b69dae544..0000000000
--- a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/AvroValidator.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.avro;
-
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-import java.util.stream.Collectors;
-
-import org.agrona.DirectBuffer;
-import org.agrona.collections.Long2ObjectHashMap;
-import org.apache.avro.Schema;
-import org.apache.avro.Schema.Parser;
-import org.apache.avro.generic.GenericDatumReader;
-import org.apache.avro.io.DatumReader;
-import org.apache.avro.io.DecoderFactory;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
-import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.avro.config.AvroValidatorConfig;
-
-public final class AvroValidator implements Validator
-{
- private static final byte MAGIC_BYTE = 0x0;
-
- private final List catalogs;
- private final SchemaConfig catalog;
- private final Long2ObjectHashMap handlersById;
- private final CatalogHandler handler;
- private final DecoderFactory decoder;
- private final String subject;
- private DatumReader reader;
- private Parser parser;
-
- public AvroValidator(
- AvroValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
- {
- this.handlersById = new Long2ObjectHashMap<>();
- this.decoder = DecoderFactory.get();
- this.catalogs = config.catalogs.stream().map(c ->
- {
- c.id = resolveId.applyAsLong(c.name);
- handlersById.put(c.id, supplyCatalog.apply(c.id));
- return c;
- }).collect(Collectors.toList());
- this.handler = handlersById.get(catalogs.get(0).id);
- this.parser = new Schema.Parser();
- this.catalog = catalogs.get(0).schemas.size() != 0 ? catalogs.get(0).schemas.get(0) : null;
- this.subject = config.subject;
- }
-
- @Override
- public boolean read(
- DirectBuffer data,
- int index,
- int length)
- {
- boolean status = false;
- byte[] payloadBytes = new byte[length];
- data.getBytes(0, payloadBytes);
- ByteBuffer byteBuf = ByteBuffer.wrap(payloadBytes);
-
- if (byteBuf.get() == MAGIC_BYTE)
- {
- int schemaId = byteBuf.getInt();
- int valLength = length - 1 - 4;
- byte[] valBytes = new byte[valLength];
- data.getBytes(length - valLength, valBytes);
-
- String schema = handler.resolve(schemaId);
-
- if (schema != null && validate(schema, valBytes))
- {
- status = true;
- }
- }
- return status;
- }
-
- @Override
- public boolean write(
- DirectBuffer data,
- int index,
- int length)
- {
- boolean status = false;
- String schema = null;
- int schemaId = catalog != null ? catalog.id : 0;
-
- byte[] payloadBytes = new byte[length];
- data.getBytes(0, payloadBytes);
-
- if (schemaId > 0)
- {
- schema = handler.resolve(schemaId);
- }
- else if (catalog != null && "topic".equals(catalog.strategy))
- {
- schemaId = handler.resolve(subject, catalog.version);
- if (schemaId > 0)
- {
- schema = handler.resolve(schemaId);
- }
- }
-
- if (schema != null && validate(schema, payloadBytes))
- {
- status = true;
- }
-
- return status;
- }
-
- private boolean validate(
- String schema,
- byte[] payloadBytes)
- {
- boolean status = false;
- try
- {
- reader = new GenericDatumReader(parser.parse(schema));
- reader.read(null, decoder.binaryDecoder(payloadBytes, null));
- status = true;
- }
- catch (Exception e)
- {
- }
- return status;
- }
-}
diff --git a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigAdapter.java b/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigAdapter.java
deleted file mode 100644
index b244bf2787..0000000000
--- a/incubator/validator-avro/src/main/java/io/aklivity/zilla/runtime/validator/avro/config/AvroValidatorConfigAdapter.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.avro.config;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import jakarta.json.Json;
-import jakarta.json.JsonArray;
-import jakarta.json.JsonArrayBuilder;
-import jakarta.json.JsonObject;
-import jakarta.json.JsonObjectBuilder;
-import jakarta.json.JsonValue;
-import jakarta.json.bind.adapter.JsonbAdapter;
-
-import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
-import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
-import io.aklivity.zilla.runtime.engine.config.SchemaConfigAdapter;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi;
-
-public final class AvroValidatorConfigAdapter implements ValidatorConfigAdapterSpi, JsonbAdapter
-{
- private static final String AVRO = "avro";
- private static final String TYPE_NAME = "type";
- private static final String CATALOG_NAME = "catalog";
- private static final String SUBJECT = "subject";
-
- private final SchemaConfigAdapter schema = new SchemaConfigAdapter();
-
- @Override
- public String type()
- {
- return AVRO;
- }
-
- @Override
- public JsonValue adaptToJson(
- ValidatorConfig config)
- {
- AvroValidatorConfig validatorConfig = (AvroValidatorConfig) config;
- JsonObjectBuilder validator = Json.createObjectBuilder();
- validator.add(TYPE_NAME, AVRO);
- if (validatorConfig.catalogs != null && !validatorConfig.catalogs.isEmpty())
- {
- JsonObjectBuilder catalogs = Json.createObjectBuilder();
- for (CatalogedConfig catalog : validatorConfig.catalogs)
- {
- JsonArrayBuilder array = Json.createArrayBuilder();
- for (SchemaConfig schemaItem: catalog.schemas)
- {
- array.add(schema.adaptToJson(schemaItem));
- }
- catalogs.add(catalog.name, array);
- }
- validator.add(CATALOG_NAME, catalogs);
- }
- return validator.build();
- }
-
- @Override
- public ValidatorConfig adaptFromJson(
- JsonValue value)
- {
- JsonObject object = (JsonObject) value;
- ValidatorConfig result = null;
- if (object.containsKey(CATALOG_NAME))
- {
- JsonObject catalogsJson = object.getJsonObject(CATALOG_NAME);
- List catalogs = new LinkedList<>();
- for (String catalogName: catalogsJson.keySet())
- {
- JsonArray schemasJson = catalogsJson.getJsonArray(catalogName);
- List schemas = new LinkedList<>();
- for (JsonValue item : schemasJson)
- {
- JsonObject schemaJson = (JsonObject) item;
- SchemaConfig schemaElement = schema.adaptFromJson(schemaJson);
- schemas.add(schemaElement);
- }
- catalogs.add(new CatalogedConfig(catalogName, schemas));
- }
-
- String subject = object.containsKey(SUBJECT)
- ? object.getString(SUBJECT)
- : null;
-
- result = new AvroValidatorConfig(catalogs, subject);
- }
- return result;
- }
-}
diff --git a/incubator/validator-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi b/incubator/validator-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
deleted file mode 100644
index aba3576a05..0000000000
--- a/incubator/validator-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
+++ /dev/null
@@ -1 +0,0 @@
-io.aklivity.zilla.runtime.validator.avro.config.AvroValidatorConfigAdapter
diff --git a/incubator/validator-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi b/incubator/validator-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
deleted file mode 100644
index 3282542a93..0000000000
--- a/incubator/validator-avro/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
+++ /dev/null
@@ -1 +0,0 @@
-io.aklivity.zilla.runtime.validator.avro.AvroValidatorFactory
diff --git a/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorFactoryTest.java b/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorFactoryTest.java
deleted file mode 100644
index a4179ba7f1..0000000000
--- a/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorFactoryTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.avro;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import java.util.List;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalogHandler;
-import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.avro.config.AvroValidatorConfig;
-
-public class AvroValidatorFactoryTest
-{
- @Test
- public void shouldCreate()
- {
- // GIVEN
- ValidatorConfig validator = new AvroValidatorConfig(List.of(new CatalogedConfig("test0", List.of())), "test-value");
- ToLongFunction resolveId = i -> 0L;
- LongFunction supplyCatalog = i -> new TestCatalogHandler(new TestCatalogOptionsConfig("schema0"));
- AvroValidatorFactory factory = new AvroValidatorFactory();
-
- // WHEN
- Validator avroValidator = factory.create(validator, resolveId, supplyCatalog);
-
- // THEN
- assertThat(avroValidator, instanceOf(AvroValidator.class));
- }
-}
diff --git a/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorTest.java b/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorTest.java
deleted file mode 100644
index bd43cdbcf3..0000000000
--- a/incubator/validator-avro/src/test/java/io/aklivity/zilla/runtime/validator/avro/AvroValidatorTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.avro;
-
-import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_DIRECTORY;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import java.util.Properties;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import org.agrona.DirectBuffer;
-import org.agrona.concurrent.UnsafeBuffer;
-import org.junit.Before;
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.engine.EngineConfiguration;
-import io.aklivity.zilla.runtime.engine.EngineContext;
-import io.aklivity.zilla.runtime.engine.catalog.Catalog;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogContext;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.CatalogConfig;
-import io.aklivity.zilla.runtime.engine.internal.LabelManager;
-import io.aklivity.zilla.runtime.engine.internal.stream.NamespacedId;
-import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalog;
-import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
-import io.aklivity.zilla.runtime.validator.avro.config.AvroValidatorConfig;
-
-public class AvroValidatorTest
-{
- private static final String SCHEMA = "{\"fields\":[{\"name\":\"id\",\"type\":\"string\"}," +
- "{\"name\":\"status\",\"type\":\"string\"}]," +
- "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}";
-
- private final AvroValidatorConfig avroConfig = AvroValidatorConfig.builder()
- .catalog()
- .name("test0")
- .schema()
- .strategy("topic")
- .version("latest")
- .subject("test-value")
- .build()
- .build()
- .build();
-
- private LabelManager labels;
- private ToLongFunction resolveId;
- private CatalogContext context;
-
- @Before
- public void init()
- {
- Properties properties = new Properties();
- properties.setProperty(ENGINE_DIRECTORY.name(), "target/zilla-itests");
- EngineConfiguration config = new EngineConfiguration(properties);
- labels = new LabelManager(config.directory());
- resolveId = name -> name != null ? NamespacedId.id(1, labels.supplyLabelId(name)) : 0L;
- Catalog catalog = new TestCatalog(config);
- context = catalog.supply(mock(EngineContext.class));
- }
-
- @Test
- public void shouldVerifyValidAvroEvent()
- {
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(SCHEMA));
- LongFunction handler = value -> context.attach(catalogConfig);
- AvroValidator validator = new AvroValidator(avroConfig, resolveId, handler);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x69, 0x64,
- 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65};
- data.wrap(bytes, 0, bytes.length);
- assertTrue(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyInvalidAvroEvent()
- {
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(SCHEMA));
- LongFunction handler = value -> context.attach(catalogConfig);
- AvroValidator validator = new AvroValidator(avroConfig, resolveId, handler);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x69, 0x64, 0x30, 0x10};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyMagicBytes()
- {
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(SCHEMA));
- LongFunction handler = value -> context.attach(catalogConfig);
- AvroValidator validator = new AvroValidator(avroConfig, resolveId, handler);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = "Invalid Event".getBytes();
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyInvalidSchemaId()
- {
- CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", new TestCatalogOptionsConfig(SCHEMA));
- LongFunction handler = value -> context.attach(catalogConfig);
- AvroValidator validator = new AvroValidator(avroConfig, resolveId, handler);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0x00, 0x00, 0x00, 0x00, 0x79, 0x06, 0x69, 0x64, 0x30, 0x10};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-}
diff --git a/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/long.schema.patch.json b/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/long.schema.patch.json
deleted file mode 100644
index fda2154cad..0000000000
--- a/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/long.schema.patch.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- {
- "op": "add",
- "path": "/$defs/validator/types/enum/-",
- "value": "long"
- }
-]
diff --git a/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/string.schema.patch.json b/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/string.schema.patch.json
deleted file mode 100644
index 6cee03d49d..0000000000
--- a/incubator/validator-core.spec/src/main/scripts/io/aklivity/zilla/specs/validator/core/schema/string.schema.patch.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- {
- "op": "add",
- "path": "/$defs/validator/types/enum/-",
- "value": "string"
- }
-]
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/LongValidatorFactory.java b/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/LongValidatorFactory.java
deleted file mode 100644
index e0bcbe33df..0000000000
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/LongValidatorFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import java.net.URL;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import io.aklivity.zilla.runtime.common.feature.Incubating;
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi;
-import io.aklivity.zilla.runtime.validator.core.config.LongValidatorConfig;
-
-@Incubating
-public class LongValidatorFactory implements ValidatorFactorySpi
-{
- @Override
- public String type()
- {
- return "long";
- }
-
- @Override
- public URL schema()
- {
- return getClass().getResource("schema/long.schema.patch.json");
- }
-
- @Override
- public Validator create(
- ValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
- {
- return new LongValidator(LongValidatorConfig.class.cast(config));
- }
-}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/StringValidator.java b/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/StringValidator.java
deleted file mode 100644
index b79b298021..0000000000
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/StringValidator.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import java.util.function.Predicate;
-
-import org.agrona.DirectBuffer;
-
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfig;
-
-public final class StringValidator implements Validator
-{
- private Predicate predicate;
-
- public StringValidator(
- StringValidatorConfig config)
- {
- this.predicate = config.encoding.equals("utf_8") ? this::isValidUTF8 :
- config.encoding.equals("utf_16") ? this::isValidUTF16 :
- bytes -> false;
- }
-
- @Override
- public boolean read(
- DirectBuffer data,
- int index,
- int length)
- {
- return validate(data, index, length);
- }
-
- @Override
- public boolean write(
- DirectBuffer data,
- int index,
- int length)
- {
- return validate(data, index, length);
- }
-
- private boolean validate(
- DirectBuffer data,
- int index,
- int length)
- {
- byte[] payloadBytes = new byte[length];
- data.getBytes(0, payloadBytes);
- return predicate.test(payloadBytes);
- }
-
- private boolean isValidUTF8(
- byte[] byteArray)
- {
- int i = 0;
- while (i < byteArray.length)
- {
- int numBytes;
- if ((byteArray[i] & 0b10000000) == 0b00000000)
- {
- numBytes = 1;
- }
- else if ((byteArray[i] & 0b11100000) == 0b11000000)
- {
- numBytes = 2;
- }
- else if ((byteArray[i] & 0b11110000) == 0b11100000)
- {
- numBytes = 3;
- }
- else if ((byteArray[i] & 0b11111000) == 0b11110000)
- {
- numBytes = 4;
- }
- else
- {
- return false;
- }
-
- for (int j = 1; j < numBytes; j++)
- {
- if (i + j >= byteArray.length)
- {
- return false;
- }
- if ((byteArray[i + j] & 0b11000000) != 0b10000000)
- {
- return false;
- }
- }
- i += numBytes;
- }
- return true;
- }
-
- private boolean isValidUTF16(
- byte[] byteArray)
- {
- int i = 0;
- boolean status = false;
-
- while (i < byteArray.length)
- {
- if (i + 1 >= byteArray.length)
- {
- status = false;
- break;
- }
-
- int highByte = byteArray[i] & 0xFF;
- int lowByte = byteArray[i + 1] & 0xFF;
- int codeUnit = (highByte << 8) | lowByte;
-
- if (codeUnit >= 0xD800 && codeUnit <= 0xDBFF)
- {
- if (i + 3 >= byteArray.length)
- {
- status = false;
- break;
- }
- int secondHighByte = byteArray[i + 2] & 0xFF;
- int secondLowByte = byteArray[i + 3] & 0xFF;
- int secondCodeUnit = (secondHighByte << 8) | secondLowByte;
- if (secondCodeUnit < 0xDC00 || secondCodeUnit > 0xDFFF)
- {
- status = false;
- break;
- }
- i += 4;
- }
- else if (codeUnit >= 0xDC00 && codeUnit <= 0xDFFF)
- {
- status = false;
- break;
- }
- else
- {
- i += 2;
- }
- status = true;
- }
- return status;
- }
-}
diff --git a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigBuilder.java b/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigBuilder.java
deleted file mode 100644
index 016551f448..0000000000
--- a/incubator/validator-core/src/main/java/io/aklivity/zilla/runtime/validator/core/config/IntegerValidatorConfigBuilder.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core.config;
-
-import java.util.function.Function;
-
-import io.aklivity.zilla.runtime.engine.config.ConfigBuilder;
-
-public class IntegerValidatorConfigBuilder extends ConfigBuilder>
-{
- private final Function mapper;
-
- IntegerValidatorConfigBuilder(
- Function mapper)
- {
- this.mapper = mapper;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- protected Class> thisType()
- {
- return (Class>) getClass();
- }
-
- @Override
- public T build()
- {
- return mapper.apply(new IntegerValidatorConfig());
- }
-}
diff --git a/incubator/validator-core/src/main/moditect/module-info.java b/incubator/validator-core/src/main/moditect/module-info.java
deleted file mode 100644
index e114502215..0000000000
--- a/incubator/validator-core/src/main/moditect/module-info.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-module io.aklivity.zilla.runtime.validator.core
-{
- requires io.aklivity.zilla.runtime.engine;
-
- exports io.aklivity.zilla.runtime.validator.core.config;
-
- provides io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
- with io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfigAdapter,
- io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfigAdapter,
- io.aklivity.zilla.runtime.validator.core.config.LongValidatorConfigAdapter;
-
- provides io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
- with io.aklivity.zilla.runtime.validator.core.StringValidatorFactory,
- io.aklivity.zilla.runtime.validator.core.IntegerValidatorFactory,
- io.aklivity.zilla.runtime.validator.core.LongValidatorFactory;
-}
diff --git a/incubator/validator-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi b/incubator/validator-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
deleted file mode 100644
index fbac878d8b..0000000000
--- a/incubator/validator-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
+++ /dev/null
@@ -1,3 +0,0 @@
-io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfigAdapter
-io.aklivity.zilla.runtime.validator.core.config.LongValidatorConfigAdapter
-io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfigAdapter
diff --git a/incubator/validator-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi b/incubator/validator-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
deleted file mode 100644
index d8637946ac..0000000000
--- a/incubator/validator-core/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
+++ /dev/null
@@ -1,3 +0,0 @@
-io.aklivity.zilla.runtime.validator.core.IntegerValidatorFactory
-io.aklivity.zilla.runtime.validator.core.LongValidatorFactory
-io.aklivity.zilla.runtime.validator.core.StringValidatorFactory
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorFactoryTest.java b/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorFactoryTest.java
deleted file mode 100644
index cc1c02f163..0000000000
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/IntegerValidatorFactoryTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.core.config.IntegerValidatorConfig;
-
-public class IntegerValidatorFactoryTest
-{
- @Test
- @SuppressWarnings("unchecked")
- public void shouldCreate()
- {
- // GIVEN
- ValidatorConfig validator = new IntegerValidatorConfig();
- ToLongFunction resolveId = mock(ToLongFunction.class);
- LongFunction supplyCatalog = mock(LongFunction.class);
- IntegerValidatorFactory factory = new IntegerValidatorFactory();
-
- // WHEN
- Validator integerValidator = factory.create(validator, resolveId, supplyCatalog);
-
- // THEN
- assertThat(integerValidator, instanceOf(IntegerValidator.class));
- }
-}
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/LongValidatorFactoryTest.java b/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/LongValidatorFactoryTest.java
deleted file mode 100644
index e45afe1893..0000000000
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/LongValidatorFactoryTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.core.config.LongValidatorConfig;
-
-public class LongValidatorFactoryTest
-{
- @Test
- @SuppressWarnings("unchecked")
- public void shouldCreate()
- {
- // GIVEN
- ValidatorConfig validator = new LongValidatorConfig();
- ToLongFunction resolveId = mock(ToLongFunction.class);
- LongFunction supplyCatalog = mock(LongFunction.class);
- LongValidatorFactory factory = new LongValidatorFactory();
-
- // WHEN
- Validator longValidator = factory.create(validator, resolveId, supplyCatalog);
-
- // THEN
- assertThat(longValidator, instanceOf(LongValidator.class));
- }
-}
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/LongValidatorTest.java b/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/LongValidatorTest.java
deleted file mode 100644
index b1b8d9a926..0000000000
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/LongValidatorTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.agrona.DirectBuffer;
-import org.agrona.concurrent.UnsafeBuffer;
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.validator.core.config.LongValidatorConfig;
-
-public class LongValidatorTest
-{
- private final LongValidatorConfig config = new LongValidatorConfig();
- private final LongValidator validator = new LongValidator(config);
-
- @Test
- public void shouldVerifyValidLong()
- {
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0, 0, 0, 0, 0, 0, 0, 42};
- data.wrap(bytes, 0, bytes.length);
- assertTrue(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyInvalidLong()
- {
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0, 0, 0, 42};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.write(data, 0, data.capacity()));
- }
-}
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/StringValidatorFactoryTest.java b/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/StringValidatorFactoryTest.java
deleted file mode 100644
index 51ea3c2f3a..0000000000
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/StringValidatorFactoryTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfig;
-
-public class StringValidatorFactoryTest
-{
- @Test
- @SuppressWarnings("unchecked")
- public void shouldCreate()
- {
- // GIVEN
- ValidatorConfig validator = new StringValidatorConfig("utf_8");
- ToLongFunction resolveId = mock(ToLongFunction.class);
- LongFunction supplyCatalog = mock(LongFunction.class);
- StringValidatorFactory factory = new StringValidatorFactory();
-
- // WHEN
- Validator stringValidator = factory.create(validator, resolveId, supplyCatalog);
-
- // THEN
- assertThat(stringValidator, instanceOf(StringValidator.class));
- }
-}
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/StringValidatorTest.java b/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/StringValidatorTest.java
deleted file mode 100644
index 1141d6ea16..0000000000
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/StringValidatorTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.nio.charset.StandardCharsets;
-
-import org.agrona.DirectBuffer;
-import org.agrona.concurrent.UnsafeBuffer;
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.validator.core.config.StringValidatorConfig;
-
-public class StringValidatorTest
-{
- @Test
- public void shouldVerifyValidUTF8()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_8");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = "Valid String".getBytes();
- data.wrap(bytes, 0, bytes.length);
- assertTrue(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyInvalidUTF8()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_8");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {(byte) 0xc0};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyValidUTF16()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_16");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = "Valid String".getBytes(StandardCharsets.UTF_16);
- data.wrap(bytes, 0, bytes.length);
-
- assertTrue(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyIncompleteUTF16()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_16");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0x48};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyIncompleteSurrogatePairUTF16()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_16");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {(byte) 0xD8, (byte) 0x00};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyInvalidSecondSurrogateUTF16()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_16");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {(byte) 0xDC, (byte) 0x01};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyUnexpectedSecondSurrogateUTF16()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_16");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {(byte) 0xDC, (byte) 0x80};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.read(data, 0, data.capacity()));
- }
-
- @Test
- public void shouldVerifyValidMixedUTF16()
- {
- StringValidatorConfig config = new StringValidatorConfig("utf_16");
- StringValidator validator = new StringValidator(config);
-
- DirectBuffer data = new UnsafeBuffer();
-
- byte[] bytes = {0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 65, 66, 67};
- data.wrap(bytes, 0, bytes.length);
- assertFalse(validator.write(data, 0, data.capacity()));
- }
-}
diff --git a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigAdapterTest.java b/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigAdapterTest.java
deleted file mode 100644
index 3d8e140c36..0000000000
--- a/incubator/validator-core/src/test/java/io/aklivity/zilla/runtime/validator/core/config/LongValidatorConfigAdapterTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.core.config;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.nullValue;
-
-import jakarta.json.bind.Jsonb;
-import jakarta.json.bind.JsonbBuilder;
-import jakarta.json.bind.JsonbConfig;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class LongValidatorConfigAdapterTest
-{
- private Jsonb jsonb;
-
- @Before
- public void initJson()
- {
- JsonbConfig config = new JsonbConfig()
- .withAdapters(new LongValidatorConfigAdapter());
- jsonb = JsonbBuilder.create(config);
- }
-
- @Test
- public void shouldReadLongValidator()
- {
- // GIVEN
- String json =
- "{" +
- "\"type\":\"long\"" +
- "}";
-
- // WHEN
- LongValidatorConfig validator = jsonb.fromJson(json, LongValidatorConfig.class);
-
- // THEN
- assertThat(validator, not(nullValue()));
- assertThat(validator.type, equalTo("long"));
- }
-
- @Test
- public void shouldWriteLongValidator()
- {
- // GIVEN
- String expectedJson = "\"long\"";
- LongValidatorConfig validator = LongValidatorConfig.builder().build();
-
- // WHEN
- String json = jsonb.toJson(validator);
-
- // THEN
- assertThat(json, not(nullValue()));
- assertThat(json, equalTo(expectedJson));
- }
-}
diff --git a/incubator/validator-json.spec/src/main/scripts/io/aklivity/zilla/specs/validator/json/schema/json.schema.patch.json b/incubator/validator-json.spec/src/main/scripts/io/aklivity/zilla/specs/validator/json/schema/json.schema.patch.json
deleted file mode 100644
index 080c669aeb..0000000000
--- a/incubator/validator-json.spec/src/main/scripts/io/aklivity/zilla/specs/validator/json/schema/json.schema.patch.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- {
- "op": "add",
- "path": "/$defs/validator/types/enum/-",
- "value": "json"
- }
-]
diff --git a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/JsonValidator.java b/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/JsonValidator.java
deleted file mode 100644
index 1e7ddeecd6..0000000000
--- a/incubator/validator-json/src/main/java/io/aklivity/zilla/runtime/validator/json/JsonValidator.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.json;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.util.List;
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-import java.util.stream.Collectors;
-
-import jakarta.json.spi.JsonProvider;
-import jakarta.json.stream.JsonParser;
-import jakarta.json.stream.JsonParserFactory;
-
-import org.agrona.DirectBuffer;
-import org.agrona.collections.Long2ObjectHashMap;
-import org.leadpony.justify.api.JsonSchema;
-import org.leadpony.justify.api.JsonSchemaReader;
-import org.leadpony.justify.api.JsonValidationService;
-import org.leadpony.justify.api.ProblemHandler;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
-import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
-
-public class JsonValidator implements Validator
-{
- private final JsonProvider schemaProvider;
- private final Long2ObjectHashMap handlersById;
- private final JsonValidationService service;
- private final JsonParserFactory factory;
- private final List catalogs;
- private final SchemaConfig catalog;
- private final CatalogHandler handler;
-
- public JsonValidator(
- JsonValidatorConfig config,
- ToLongFunction resolveId,
- LongFunction supplyCatalog)
- {
- this.handlersById = new Long2ObjectHashMap<>();
- this.schemaProvider = JsonProvider.provider();
- this.service = JsonValidationService.newInstance();
- this.factory = schemaProvider.createParserFactory(null);
- this.catalogs = config.catalogs.stream().map(c ->
- {
- c.id = resolveId.applyAsLong(c.name);
- handlersById.put(c.id, supplyCatalog.apply(c.id));
- return c;
- }).collect(Collectors.toList());
- this.catalog = catalogs.get(0).schemas.size() != 0 ? catalogs.get(0).schemas.get(0) : null;
- this.handler = handlersById.get(catalogs.get(0).id);
- }
-
- @Override
- public boolean read(
- DirectBuffer data,
- int index,
- int length)
- {
- return validate(data, index, length);
- }
-
- @Override
- public boolean write(
- DirectBuffer data,
- int index,
- int length)
- {
- return validate(data, index, length);
- }
-
- private boolean validate(
- DirectBuffer data,
- int index,
- int length)
- {
- String schema = null;
- int schemaId = catalog != null ? catalog.id : 0;
-
- byte[] payloadBytes = new byte[length];
- data.getBytes(0, payloadBytes);
-
- if (schemaId > 0)
- {
- schema = handler.resolve(schemaId);
- }
- else if (catalog != null)
- {
- schemaId = handler.resolve(catalog.subject, catalog.version);
- if (schemaId != 0)
- {
- schema = handler.resolve(schemaId);
- }
- }
-
- return schema != null && validate(schema, payloadBytes);
- }
-
- private boolean validate(
- String schema,
- byte[] payloadBytes)
- {
- boolean status = false;
- try
- {
- JsonParser schemaParser = factory.createParser(new StringReader(schema));
- JsonSchemaReader reader = service.createSchemaReader(schemaParser);
- JsonSchema jsonSchema = reader.read();
- JsonProvider provider = service.createJsonProvider(jsonSchema, parser -> ProblemHandler.throwing());
- InputStream input = new ByteArrayInputStream(payloadBytes);
- provider.createReader(input).readValue();
- status = true;
- }
- catch (Exception e)
- {
- }
- return status;
- }
-}
diff --git a/incubator/validator-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi b/incubator/validator-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
deleted file mode 100644
index 1b107098bc..0000000000
--- a/incubator/validator-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.config.ValidatorConfigAdapterSpi
+++ /dev/null
@@ -1 +0,0 @@
-io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfigAdapter
diff --git a/incubator/validator-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi b/incubator/validator-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
deleted file mode 100644
index bf8cca9996..0000000000
--- a/incubator/validator-json/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.validator.ValidatorFactorySpi
+++ /dev/null
@@ -1 +0,0 @@
-io.aklivity.zilla.runtime.validator.json.JsonValidatorFactory
diff --git a/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorFactoryTest.java b/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorFactoryTest.java
deleted file mode 100644
index 481e3295a3..0000000000
--- a/incubator/validator-json/src/test/java/io/aklivity/zilla/runtime/validator/json/JsonValidatorFactoryTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.validator.json;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import java.util.function.LongFunction;
-import java.util.function.ToLongFunction;
-
-import org.junit.Test;
-
-import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
-import io.aklivity.zilla.runtime.engine.config.ValidatorConfig;
-import io.aklivity.zilla.runtime.engine.test.internal.catalog.TestCatalogHandler;
-import io.aklivity.zilla.runtime.engine.test.internal.catalog.config.TestCatalogOptionsConfig;
-import io.aklivity.zilla.runtime.engine.validator.Validator;
-import io.aklivity.zilla.runtime.validator.json.config.JsonValidatorConfig;
-
-public class JsonValidatorFactoryTest
-{
- @Test
- public void shouldCreate()
- {
- // GIVEN
- ValidatorConfig validator = JsonValidatorConfig.builder()
- .catalog()
- .name("test0")
- .build()
- .build();
- ToLongFunction resolveId = i -> 0L;
- LongFunction supplyCatalog = i -> new TestCatalogHandler(new TestCatalogOptionsConfig("schema0"));
- JsonValidatorFactory factory = new JsonValidatorFactory();
-
- // WHEN
- Validator jsonValidator = factory.create(validator, resolveId, supplyCatalog);
-
- // THEN
- assertThat(jsonValidator, instanceOf(JsonValidator.class));
- }
-}
diff --git a/manager/pom.xml b/manager/pom.xml
index 1e9b507a9a..8a45e90412 100644
--- a/manager/pom.xml
+++ b/manager/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/pom.xml b/pom.xml
index 692c732ac7..be0ce6e786 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
4.0.0
io.aklivity.zilla
zilla
- 0.9.66
+ 0.9.67
pom
zilla
https://github.com/aklivity/zilla
diff --git a/runtime/binding-echo/pom.xml b/runtime/binding-echo/pom.xml
index 1fa806d689..6bea1de329 100644
--- a/runtime/binding-echo/pom.xml
+++ b/runtime/binding-echo/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/runtime/binding-fan/pom.xml b/runtime/binding-fan/pom.xml
index ad99ab845a..aa65cfd9f4 100644
--- a/runtime/binding-fan/pom.xml
+++ b/runtime/binding-fan/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/runtime/binding-filesystem/pom.xml b/runtime/binding-filesystem/pom.xml
index 793d857a93..68b55812fc 100644
--- a/runtime/binding-filesystem/pom.xml
+++ b/runtime/binding-filesystem/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/runtime/binding-grpc-kafka/pom.xml b/runtime/binding-grpc-kafka/pom.xml
index d93d7a15de..020f2cded1 100644
--- a/runtime/binding-grpc-kafka/pom.xml
+++ b/runtime/binding-grpc-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/runtime/binding-grpc/pom.xml b/runtime/binding-grpc/pom.xml
index 15144e2a2f..d772cb166a 100644
--- a/runtime/binding-grpc/pom.xml
+++ b/runtime/binding-grpc/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.66
+ 0.9.67
../pom.xml
diff --git a/runtime/binding-grpc/src/main/java/io/aklivity/zilla/runtime/binding/grpc/internal/config/GrpcBindingConfig.java b/runtime/binding-grpc/src/main/java/io/aklivity/zilla/runtime/binding/grpc/internal/config/GrpcBindingConfig.java
index 323417f06a..164fd795e7 100644
--- a/runtime/binding-grpc/src/main/java/io/aklivity/zilla/runtime/binding/grpc/internal/config/GrpcBindingConfig.java
+++ b/runtime/binding-grpc/src/main/java/io/aklivity/zilla/runtime/binding/grpc/internal/config/GrpcBindingConfig.java
@@ -16,6 +16,7 @@
import static io.aklivity.zilla.runtime.binding.grpc.internal.types.stream.GrpcType.BASE64;
import static io.aklivity.zilla.runtime.binding.grpc.internal.types.stream.GrpcType.TEXT;
+import static io.aklivity.zilla.runtime.engine.catalog.CatalogHandler.NO_SCHEMA_ID;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
@@ -28,15 +29,19 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.LongFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
import org.agrona.AsciiSequenceView;
import org.agrona.DirectBuffer;
import org.agrona.MutableDirectBuffer;
+import org.agrona.collections.ObjectHashSet;
import io.aklivity.zilla.runtime.binding.grpc.config.GrpcMethodConfig;
import io.aklivity.zilla.runtime.binding.grpc.config.GrpcOptionsConfig;
+import io.aklivity.zilla.runtime.binding.grpc.config.GrpcProtobufConfig;
import io.aklivity.zilla.runtime.binding.grpc.internal.types.Array32FW;
import io.aklivity.zilla.runtime.binding.grpc.internal.types.HttpHeaderFW;
import io.aklivity.zilla.runtime.binding.grpc.internal.types.String16FW;
@@ -44,8 +49,11 @@
import io.aklivity.zilla.runtime.binding.grpc.internal.types.stream.GrpcMetadataFW;
import io.aklivity.zilla.runtime.binding.grpc.internal.types.stream.GrpcType;
import io.aklivity.zilla.runtime.binding.grpc.internal.types.stream.HttpBeginExFW;
+import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
import io.aklivity.zilla.runtime.engine.config.BindingConfig;
+import io.aklivity.zilla.runtime.engine.config.CatalogedConfig;
import io.aklivity.zilla.runtime.engine.config.KindConfig;
+import io.aklivity.zilla.runtime.engine.config.SchemaConfig;
public final class GrpcBindingConfig
{
@@ -56,7 +64,6 @@ public final class GrpcBindingConfig
private static final byte[] HEADER_BIN_SUFFIX = new byte[4];
private static final byte[] GRPC_PREFIX = "grpc-".getBytes();
private static final byte[] BIN_SUFFIX = "-bin".getBytes();
- private final HttpGrpcHeaderHelper helper;
public final long id;
public final String name;
@@ -64,20 +71,34 @@ public final class GrpcBindingConfig
public final GrpcOptionsConfig options;
public final List routes;
+ private final GrpcProtobufParser parser;
+ private final HttpGrpcHeaderHelper helper;
+ private final Set catalogs;
public GrpcBindingConfig(
BindingConfig binding,
- MutableDirectBuffer metadataBuffer)
+ MutableDirectBuffer metadataBuffer,
+ LongFunction supplyCatalog)
{
this.id = binding.id;
this.name = binding.name;
this.kind = binding.kind;
this.options = GrpcOptionsConfig.class.cast(binding.options);
this.routes = binding.routes.stream().map(GrpcRouteConfig::new).collect(toList());
+ this.parser = new GrpcProtobufParser();
this.helper = new HttpGrpcHeaderHelper(metadataBuffer);
+ Set