diff --git a/.github/workflows/dev-stg-release.yml b/.github/workflows/dev-stg-release.yml index 49d6f52..f9d6e5e 100644 --- a/.github/workflows/dev-stg-release.yml +++ b/.github/workflows/dev-stg-release.yml @@ -19,3 +19,4 @@ jobs: secrets: inherit with: environment: ${{ github.event.inputs.environment }} + additional-publish-flags: "-x :confluent.cavroserdes-examples:build" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index e844b6f..d74b27f 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -23,7 +23,7 @@ dependencies = [ [[package]] org = "ballerina" name = "avro" -version = "0.1.0" +version = "0.1.1" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -359,7 +359,7 @@ modules = [ [[package]] org = "ballerinax" name = "confluent.cregistry" -version = "0.1.0" +version = "0.1.1" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] diff --git a/build.gradle b/build.gradle index 7301168..40c1e4e 100644 --- a/build.gradle +++ b/build.gradle @@ -82,6 +82,7 @@ subprojects { task build { dependsOn(":confluent.cavroserdes-native:build") dependsOn(":confluent.cavroserdes-ballerina:build") + dependsOn(":confluent.cavroserdes-examples:build") } def moduleVersion = project.version.replace("-SNAPSHOT", "") diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..2355afb --- /dev/null +++ b/examples/README.md @@ -0,0 +1,63 @@ +## Examples + +The Ballerina Avro Serializer/Deserializer connector for Confluent Schema Registry provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-confluent.cavroserdes/tree/main/examples). + +1. [Kafka Avro producer](https://github.com/ballerina-platform/module-ballerinax-confluent.cavroserdes/tree/main/examples/kafka-avro-producer) + This example shows how to publish Avro serialized data to a Kafka topic. + +2. [Kafka Avro consumer](https://github.com/ballerina-platform/module-ballerinax-confluent.cavroserdes/tree/main/examples/kafka-avro-consumer) + This guide demonstrates how to consume data in the correct format according to Avro schema from a Kafka topic. + +## Prerequisites + +Create a `Config.toml` file with the base URL, schema capacity, subject, connection configurations and header values. Here's an example of how your `Config.toml` file should look: + + ```toml + baseUrl = "" + identityMapCapacity = + subject = "" + + [originals] + "schema.registry.url" = "" + "basic.auth.credentials.source" = "USER_INFO" + "bootstrap.servers" = ":" + "schema.registry.basic.auth.user.info" = ":" + + [headers] + ``` + +## Running an Example + +Follow these steps to run the examples. + +## Step 01: Start a Kafka Server + +Execute the following docker command to start the Kafka server. + +```bash +docker-compose -f docker-compose.yaml up -d +``` + +## Step 02: Start the Kafka Producer + +Go to the [kafka-avro-producer](https://github.com/ballerina-platform/module-ballerinax-confluent.cavroserdes/tree/main/examples/kafka-avro-producer) directory and start the Ballerina service. + +```bash +bal run +``` + +## Step 03: Run the Kafka Consumer + +Go to the [kafka-avro-consumer](https://github.com/ballerina-platform/module-ballerinax-confluent.cavroserdes/tree/main/examples/kafka-avro-consumer) directory and execute the following command. + +```bash +bal run +``` + +## Step 04: Execute the cURL command + +Execute the following curl command in a terminal. + +```curl +curl http://localhost:9090/orders -H "Content-type:application/json" -d "{\"orderId\": 1, \"productName\": \"sport-shoes\"}" +``` diff --git a/examples/build.gradle b/examples/build.gradle new file mode 100644 index 0000000..1b84a26 --- /dev/null +++ b/examples/build.gradle @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.com). + * + * WSO2 Inc. 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. + */ + +import org.apache.tools.ant.taskdefs.condition.Os + +def graalvmFlag = "" + +task testExamples { + if (project.hasProperty("balGraalVMTest")) { + graalvmFlag = "--graalvm" + } + doLast { + try { + exec { + workingDir project.projectDir + println("Working dir: ${workingDir}") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'sh', "/c", "chmod +x ./build.sh && ./build.sh run && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh run" + } + } + } catch (Exception e) { + println("Example Build failed: " + e.message) + throw e + } + } +} + +task buildExamples { + gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(":confluent.cregistry-examples:test")) { + buildExamples.enabled = false + } else { + testExamples.enabled = false + } + } + doLast { + try { + exec { + workingDir project.projectDir + println("Working dir: ${workingDir}") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'sh', "/c", "chmod +x ./build.sh && ./build.sh build && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh build" + } + } + } catch (Exception e) { + println("Example Build failed: " + e.message) + throw e + } + } +} + +task build { + dependsOn buildExamples +} + +buildExamples.dependsOn ":confluent.cavroserdes-ballerina:build" +testExamples.dependsOn ":confluent.cavroserdes-ballerina:build" diff --git a/examples/build.sh b/examples/build.sh new file mode 100755 index 0000000..121920f --- /dev/null +++ b/examples/build.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +BAL_EXAMPLES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BAL_CENTRAL_DIR="$HOME/.ballerina/repositories/central.ballerina.io/" +BAL_HOME_DIR="$BAL_EXAMPLES_DIR/../ballerina" + +set -e + +case "$1" in +build) + BAL_CMD="build" + ;; +run) + BAL_CMD="run" + ;; +*) + echo "Invalid command provided: '$1'. Please provide 'build' or 'run' as the command." + exit 1 + ;; +esac + +# Read Ballerina package name +BAL_PACKAGE_NAME=$(awk -F'"' '/^name/ {print $2}' "$BAL_HOME_DIR/Ballerina.toml") + +# Push the package to the local repository +cd "$BAL_HOME_DIR" && + bal pack && + bal push --repository=local + +# Remove the cache directories in the repositories +rm -rf "$BAL_CENTRAL_DIR/cache-*" + +# Update the central repository +BAL_DESTINATION_DIR="$HOME/.ballerina/repositories/central.ballerina.io/bala/ballerinax" +BAL_SOURCE_DIR="$HOME/.ballerina/repositories/local/bala/ballerinax/$BAL_PACKAGE_NAME" + +mkdir -p "$BAL_DESTINATION_DIR" + +[ -d "$BAL_SOURCE_DIR" ] && cp -r "$BAL_SOURCE_DIR" "$BAL_DESTINATION_DIR" +echo "Successfully updated the local central repositories" + +# Loop through examples in the examples directory +cd "$BAL_EXAMPLES_DIR" +for dir in $(find "$BAL_EXAMPLES_DIR" -type d -maxdepth 1 -mindepth 1); do + # Skip the build directory + if [[ "$dir" == *build ]]; then + continue + fi + if [[ "$dir" == *configs ]]; then + continue + fi + if [[ "$dir" == *secrets ]]; then + continue + fi + (cd "$dir" && bal "$BAL_CMD" && cd ..); +done + +# Remove generated JAR files +find "$BAL_HOME_DIR" -maxdepth 1 -type f -name "*.jar" | while read -r JAR_FILE; do + rm "$JAR_FILE" +done diff --git a/examples/configs/kafka_server_jaas.conf b/examples/configs/kafka_server_jaas.conf new file mode 100644 index 0000000..cb79601 --- /dev/null +++ b/examples/configs/kafka_server_jaas.conf @@ -0,0 +1,14 @@ +KafkaServer { + org.apache.kafka.common.security.plain.PlainLoginModule required + serviceName="test-service" + username="admin" + password="password" + user_admin="password" + user_client="client-secret"; +}; + +Client { + org.apache.zookeeper.server.auth.DigestLoginModule required + username="admin" + password="password"; +}; diff --git a/examples/configs/zookeeper_jaas.conf b/examples/configs/zookeeper_jaas.conf new file mode 100644 index 0000000..0158eb4 --- /dev/null +++ b/examples/configs/zookeeper_jaas.conf @@ -0,0 +1,5 @@ +Server { + org.apache.zookeeper.server.auth.DigestLoginModule required + user_super="admin-secret" + user_admin="password"; +}; diff --git a/examples/docker-compose.yaml b/examples/docker-compose.yaml new file mode 100644 index 0000000..6abf120 --- /dev/null +++ b/examples/docker-compose.yaml @@ -0,0 +1,53 @@ +version: '2' + +services: + zookeeper: + image: 'confluentinc/cp-zookeeper:latest' + hostname: zookeeper + container_name: kafka-test-zookeeper + ports: + - '2181:2181' + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: 2000 + KAFKA_OPTS: '-Djava.security.auth.login.config=/opt/confluentinc/kafka/config/zookeeper_jaas.conf' + volumes: + - ./configs/zookeeper_jaas.conf:/opt/confluentinc/kafka/config/zookeeper_jaas.conf + broker: + image: 'confluentinc/cp-server:latest' + hostname: broker + container_name: kafka-test-broker + depends_on: + - zookeeper + ports: + - '9092:9092' + - '9093:9093' + - '9094:9094' + - '9095:9095' + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' + KAFKA_SASL_ENABLED_MECHANISMS: PLAIN + KAFKA_SECURITY_INTER_BROKER_PROTOCOL: PLAINTEXT + KAFKA_SSL_CLIENT_AUTH: "requested" + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,EX_PLAINTEXT://localhost:9092,EX_SASL_PLAINTEXT://localhost:9093,EX_SSL://localhost:9094,EX_SASL_SSL://localhost:9095 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,EX_PLAINTEXT:PLAINTEXT,EX_SASL_PLAINTEXT:SASL_PLAINTEXT,EX_SSL:SSL,EX_SASL_SSL:SASL_SSL + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 + KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 + KAFKA_SSL_KEYSTORE_FILENAME: kafka.broker.keystore.jks + KAFKA_SSL_KEYSTORE_CREDENTIALS: broker_keystore_creds + KAFKA_SSL_KEY_CREDENTIALS: broker_sslkey_creds + KAFKA_SSL_TRUSTSTORE_FILENAME: kafka.broker.truststore.jks + KAFKA_SSL_TRUSTSTORE_CREDENTIALS: broker_truststore_creds + KAFKA_OPTS: '-Djava.security.auth.login.config=/opt/confluentinc/kafka/config/kafka_server_jaas.conf' + volumes: + - ./secrets/trustoresandkeystores/broker_keystore_creds:/etc/kafka/secrets/broker_keystore_creds + - ./secrets/trustoresandkeystores/broker_sslkey_creds:/etc/kafka/secrets/broker_sslkey_creds + - ./secrets/trustoresandkeystores/broker_truststore_creds:/etc/kafka/secrets/broker_truststore_creds + - ./secrets/trustoresandkeystores/kafka.broker.keystore.jks:/etc/kafka/secrets/kafka.broker.keystore.jks + - ./secrets/trustoresandkeystores/kafka.broker.truststore.jks:/etc/kafka/secrets/kafka.broker.truststore.jks + - ./configs/kafka_server_jaas.conf:/opt/confluentinc/kafka/config/kafka_server_jaas.conf diff --git a/examples/kafka-avro-consumer/.github/README.md b/examples/kafka-avro-consumer/.github/README.md new file mode 120000 index 0000000..254e554 --- /dev/null +++ b/examples/kafka-avro-consumer/.github/README.md @@ -0,0 +1 @@ +../kafka-avro-consumer.md \ No newline at end of file diff --git a/examples/kafka-avro-consumer/Ballerina.toml b/examples/kafka-avro-consumer/Ballerina.toml new file mode 100644 index 0000000..61d615f --- /dev/null +++ b/examples/kafka-avro-consumer/Ballerina.toml @@ -0,0 +1,8 @@ +[package] +org = "wso2" +name = "kafka_avro_consumer" +version = "0.1.0" +distribution = "2201.8.6" + +[build-options] +observabilityIncluded = true diff --git a/examples/kafka-avro-consumer/kafka-avro-consumer.md b/examples/kafka-avro-consumer/kafka-avro-consumer.md new file mode 100644 index 0000000..a0df137 --- /dev/null +++ b/examples/kafka-avro-consumer/kafka-avro-consumer.md @@ -0,0 +1,31 @@ +# Consume Avro Serialized Data from a Kafka Topic + +## Introduction + +This guide demonstrates how to consume data in the correct format according to Avro schema from a Kafka topic. + +### Configuration + +Configure the followings in `Config.toml` in the directory. + +```toml +baseUrl = "" +identityMapCapacity = +subject = "" + +[originals] +"schema.registry.url" = "" +"basic.auth.credentials.source" = "USER_INFO" +"bootstrap.servers" = ":" +"schema.registry.basic.auth.user.info" = ":" + +[headers] +``` + +## Run the example + +Execute the following command to run the example. + +```ballerina +bal run +``` diff --git a/examples/kafka-avro-consumer/main.bal b/examples/kafka-avro-consumer/main.bal new file mode 100644 index 0000000..18d76f1 --- /dev/null +++ b/examples/kafka-avro-consumer/main.bal @@ -0,0 +1,50 @@ +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) +// +// WSO2 LLC. 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. + +import ballerina/io; +import ballerinax/confluent.cavroserdes; +import ballerinax/kafka; + +type Order readonly & record { + int orderId; + string productName; +}; + +configurable string baseUrl = ?; +configurable int identityMapCapacity = ?; +configurable map originals = ?; +configurable map headers = ?; + +public function main() returns error? { + kafka:Consumer orderConsumer = check new (kafka:DEFAULT_URL, { + groupId: "test-topic-id", + topics: "test-topic" + }); + + cavroserdes:Client registry = check new ({ + baseUrl, + identityMapCapacity, + originals, + headers + }); + + while true { + kafka:AnydataConsumerRecord[] getValues = check orderConsumer->poll(60); + byte[] orderData = getValues[0].value; + Order getOrder = check registry->deserialize(orderData); + io:println("Order : ", getOrder); + } +} diff --git a/examples/kafka-avro-producer/.github/README.md b/examples/kafka-avro-producer/.github/README.md new file mode 120000 index 0000000..2b1897f --- /dev/null +++ b/examples/kafka-avro-producer/.github/README.md @@ -0,0 +1 @@ +../kafka-avro-producer.md \ No newline at end of file diff --git a/examples/kafka-avro-producer/Ballerina.toml b/examples/kafka-avro-producer/Ballerina.toml new file mode 100644 index 0000000..78ab3ba --- /dev/null +++ b/examples/kafka-avro-producer/Ballerina.toml @@ -0,0 +1,8 @@ +[package] +org = "wso2" +name = "kafka_avro_producer" +version = "0.1.0" +distribution = "2201.8.6" + +[build-options] +observabilityIncluded = true diff --git a/examples/kafka-avro-producer/kafka-avro-producer.md b/examples/kafka-avro-producer/kafka-avro-producer.md new file mode 100644 index 0000000..e5b20e5 --- /dev/null +++ b/examples/kafka-avro-producer/kafka-avro-producer.md @@ -0,0 +1,31 @@ +# Publish Avro Serialized Data to a Kafka Topic + +## Introduction + +This guide demonstrates how to publish Avro serialized data to a Kafka topic. + +### Configuration + +Configure the followings in `Config.toml` in the directory. + +```toml +baseUrl = "" +identityMapCapacity = +subject = "" + +[originals] +"schema.registry.url" = "" +"basic.auth.credentials.source" = "USER_INFO" +"bootstrap.servers" = ":" +"schema.registry.basic.auth.user.info" = ":" + +[headers] +``` + +## Run the example + +Execute the following command to run the example. + +```ballerina +bal run +``` diff --git a/examples/kafka-avro-producer/main.bal b/examples/kafka-avro-producer/main.bal new file mode 100644 index 0000000..9e9fc9f --- /dev/null +++ b/examples/kafka-avro-producer/main.bal @@ -0,0 +1,61 @@ +// Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) +// +// WSO2 LLC. 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. + +import ballerina/http; +import ballerinax/confluent.cavroserdes; +import ballerinax/kafka; + +configurable string baseUrl = ?; +configurable map originals = ?; +configurable map headers = ?; + +type Order readonly & record { + int orderId; + string productName; +}; + +service / on new http:Listener(9090) { + private final kafka:Producer orderProducer; + private final cavroserdes:Client registry; + + function init() returns error? { + self.orderProducer = check new (kafka:DEFAULT_URL); + self.registry = check new ({ + baseUrl, + originals, + headers + }); + } + + resource function post orders(Order newOrder) returns http:Accepted|error { + string schema = string ` + { + "namespace": "example.avro", + "type": "record", + "name": "Order", + "fields": [ + {"name": "orderId", "type": "int"}, + {"name": "productName", "type": "string"} + ] + }`; + byte[] byteValue = check self.registry->serialize(schema, newOrder, "new-subject"); + check self.orderProducer->send({ + topic: "test-topic", + value: byteValue + }); + return http:ACCEPTED; + } +} diff --git a/examples/secrets/certsandkeys/broker.public.crt b/examples/secrets/certsandkeys/broker.public.crt new file mode 100644 index 0000000..490b946 --- /dev/null +++ b/examples/secrets/certsandkeys/broker.public.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRjCCAi4CFEtcpjpBgELtRhMH0wWKPrzTmmnuMA0GCSqGSIb3DQEBCwUAMFYx +EjAQBgNVBAMMCWxvY2FsaG9zdDENMAsGA1UECwwEVEVTVDESMBAGA1UECgwJQ09O +RkxVRU5UMRAwDgYDVQQHDAdDb2xvbWJvMQswCQYDVQQGEwJMSzAeFw0yMTA2MDIx +MzM5MDlaFw0zMTA1MzExMzM5MDlaMGkxCzAJBgNVBAYTAkxLMREwDwYDVQQIEwhT +b3V0aGVybjEQMA4GA1UEBxMHQ29sb21ibzESMBAGA1UEChMJQ09ORkxVRU5UMQ0w +CwYDVQQLEwRURVNUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCc7D71QMmwi98ra+l5OGZM3UNPdT4vkJ9iUGo4w8kr +mTZHJCGmc3//CE/oi+YtkOnDokNe0F5kyYl3Sq8jAMNhOYT6IBjR6sDkljqNx/IC +mEiI10EgCS2oV6ntG5YWjK1EQh3dnYxoSfwbzV+HbvUwqSbhNRRqJQkH/vb4foY/ +VcXvjf2uVf5IjlbvfpD8ZSVL6fp99+daUw10o4MLbxowysWauZnPuFCy8UjDDYVW +V/IYlEpnDHbhl4Gea8kUsfdxP/6XRB4FODoTkZX9nVdStIICqErXr9coLFwPVntd +3eSEfu7hWvWtz3J7NMPjE6D3s/PwL+H9UR2x2niiU7MDAgMBAAEwDQYJKoZIhvcN +AQELBQADggEBAMNRaAA3bkk6pAJ2bA9P+rj7IIMRx+PjamSLS8iWvDJ0BOANxMzS +rvxoqGgbnIrNAoHSr4Pa5o2zBcb1E4pDHPqNS1SVDY1Mz/rGa291VKClxqzEd3n8 +7LDnJm3FOSFv5/p7fTlgW6IZGn9O6DNiwhURPcGwyTSmGtE+OcVyzugOOR0zH4MO +GlfK3sG86M2+bTzkMgJDk99vTuogpwaddj0d67ra3TwCkma1Vk0D0MM+7Cplxh9g +9msJTe5K7Zluy2J2KR7WK5uliXO/bwCJYgfyF0U8rBOHDd50BFxqujHybTZLKlaE +pnbOGLjLOistRjnpaKbdzUIejaKd1NT518Y= +-----END CERTIFICATE----- diff --git a/examples/secrets/certsandkeys/client.private.key b/examples/secrets/certsandkeys/client.private.key new file mode 100644 index 0000000..58b04d9 --- /dev/null +++ b/examples/secrets/certsandkeys/client.private.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAk7ToFYTNSYyQ +QGI0l2PxuvY5W/UO+KoOXLAGVpEXfTwbzoZT8VWSATv4ez6q+lTDo0pbYqbYRaNn +5El+dEOFEMbHWgxhGmZVOmkD8wYT+3HD57NJVCl7tnJI2I0akjAqiiljTf2rD/Wm +aN9yNTGsRcZaIv5HMO9dK+5yhCvVJ30NKD5fGYSkluIJsT5bYut+o9ZXTp20Z8ST +vOPtAYrHaM4nUFzTVnEVJNM70f6wa6hMvzpNuXOY4BY1A3z04EB1AQe/9ECFV04X +Dt7wisYxD1n1VfAqwbcWLJH+Y+3fe6+bYRIOk3LHO/lMEVqAEoMTkeplwGDB3Uh7 +6GkR/SrVAgMBAAECggEBALBWEC77lVEM6eMksUgK3/92/QNkyq5c0Aq6oIwNNGpX +yHSF1caDk6FP9AQBhk61Tmyd1vZ7DN+4VHpLNWjPOQxdYkckk3VO4SllhMeS/pvJ +gFCslySsJhgb5eYCNKKB/gzV2jQONBsxT/SCzygawVNHyOq8ZC34BxY/peXCVQil +uYYRj8pYJhVLqZPt2jUJFENk0W/K2Yr5xHcvX4ZckeHGMloEuI0u/jFCYI4tPXSi +0GyuUnZ2TFjMC/WEW5crbWEHZOZkskagdnlcU/QfvwwabXtJEPBfqjoJR3dwpbWa +ORukAOW8uZh4opoH76c0d6012DT0jNK6FBHe46X1JLkCgYEA9Exd6KYvPGmB+Tx3 +BgtD8XVM9qK3a2SIJcU4Wl6R6ulYLqCzGh79I+mGFFEzEOGM5DK/syBQ5TR7ctTc +Npt0tJm9XZrokb5uKU5CqafI4RotIfj7epOrjajIUCb17Ac4UkU/CMa9Cog9THzk +tNwpaC0h1QT7/V1KntBVDdzwi68CgYEAyc0fdVVddgytfYgc4v11VvbLfjVr1xbt +Cx2BwL3uyqUdNQnDI8s1MENhCQW1488ou7D1Z4DqX9QvYPcOVNAaaf3MVm41YBTf +Rq6x9VgZW+n5UytuG3yvrrbPkt2zP06+/1uoKgTHP7SzOQdE+Q1Jpf9NRpqM8Lfx +YXKjWN2pfrsCgYEA6nQf7BcRXjkjs76DvBkzq5eXtVuUDEz/HMCZxKDeCUTIjHdN +a9QxvTVwqC8Fgz3zqU3LDG4HNPGZSCtg7EdlSa4CPsNcUAMiViH1eDy+XMpyZhg9 +wPXXvqwtEj9R5KNJOiuawyF4a5M0wSNbmvdwBbrKrVWLQS03YBMwjY1sjaECgYBr +4sLnurydqQdzbjprTC/YT1bZYXwG4NXXtG2y+pfYNM/ZlB+EWlZUOCF/blMguJbB +SUjZjf0/QDQYNdyukRceBTaiGodkl6QKqMixLulXz02hHj3eahmOYWO109rJhLLt +2DWeSTGwqE2Mtos0TttJ6KSKk4O4Cc79VwlnMBI2kwKBgQC7FfnLYhPZ+QrluCYA +62rs+BNI8QzoDv3btY0skn/MueE1py6lsUX1BtaV8AKY6hx4woQSCHx2zJIg/FhG +j4nMlYSlPk5heueSG19jznS/ASPskh0BbVGmwJgrIMc+643LA7GJig8HlBNUvtux +jb/DNrHu4wWp5yxqS+kJ3VX4Hw== +-----END PRIVATE KEY----- diff --git a/examples/secrets/certsandkeys/client.public.crt b/examples/secrets/certsandkeys/client.public.crt new file mode 100644 index 0000000..810e573 --- /dev/null +++ b/examples/secrets/certsandkeys/client.public.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOTCCAiECFD9o08xgwVMIpyIrzmWt0an2DIrsMA0GCSqGSIb3DQEBCwUAMFkx +CzAJBgNVBAYTAkxLMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMTA3 +MDUwNDQ4MTZaFw0zMTA3MDMwNDQ4MTZaMFkxCzAJBgNVBAYTAkxLMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMCTtOgVhM1JjJBAYjSXY/G69jlb9Q74qg5csAZWkRd9PBvOhlPxVZIBO/h7 +Pqr6VMOjSltipthFo2fkSX50Q4UQxsdaDGEaZlU6aQPzBhP7ccPns0lUKXu2ckjY +jRqSMCqKKWNN/asP9aZo33I1MaxFxloi/kcw710r7nKEK9UnfQ0oPl8ZhKSW4gmx +Plti636j1ldOnbRnxJO84+0BisdozidQXNNWcRUk0zvR/rBrqEy/Ok25c5jgFjUD +fPTgQHUBB7/0QIVXThcO3vCKxjEPWfVV8CrBtxYskf5j7d97r5thEg6Tcsc7+UwR +WoASgxOR6mXAYMHdSHvoaRH9KtUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAN63C +qU5wEhLlucUhY+zL9hC7FGuKfDaIq5yudigL7Ui2Ab2fr7hSf6TcmkXr8qAXNHpc +CfI9WdxyVzuweiEBAat46L/bVHtsIoIYyUEGtt0aIRT7ojcAyPNX+G0aT2q18ydZ +pp1VWzYp8PxBhSHqZlRj9Ake78rH64qLn5XCOopiSI4eocSVHKAY6oBojMKdbJHF +8MgyMgDlkpQyBmHTpJk67cyFr+BOjuAVo9EzsUYqImrIK7sLAGx4V51/8bzt5UfU +HCWW0/tCWQAzrRU2rupndZHLImPzy/tGQBA/61ICDa80VMVggmQkzo3FjtuU9PCY +SFeMnPiWSaMeDTBKZg== +-----END CERTIFICATE----- diff --git a/examples/secrets/incorrecttrustoresandkeystores/kafka.client.keystore.jks b/examples/secrets/incorrecttrustoresandkeystores/kafka.client.keystore.jks new file mode 100644 index 0000000..f2edd52 Binary files /dev/null and b/examples/secrets/incorrecttrustoresandkeystores/kafka.client.keystore.jks differ diff --git a/examples/secrets/incorrecttrustoresandkeystores/kafka.client.truststore.jks b/examples/secrets/incorrecttrustoresandkeystores/kafka.client.truststore.jks new file mode 100644 index 0000000..aaa2f68 Binary files /dev/null and b/examples/secrets/incorrecttrustoresandkeystores/kafka.client.truststore.jks differ diff --git a/examples/secrets/trustoresandkeystores/broker_keystore_creds b/examples/secrets/trustoresandkeystores/broker_keystore_creds new file mode 100644 index 0000000..f3097ab --- /dev/null +++ b/examples/secrets/trustoresandkeystores/broker_keystore_creds @@ -0,0 +1 @@ +password diff --git a/examples/secrets/trustoresandkeystores/broker_sslkey_creds b/examples/secrets/trustoresandkeystores/broker_sslkey_creds new file mode 100644 index 0000000..f3097ab --- /dev/null +++ b/examples/secrets/trustoresandkeystores/broker_sslkey_creds @@ -0,0 +1 @@ +password diff --git a/examples/secrets/trustoresandkeystores/broker_truststore_creds b/examples/secrets/trustoresandkeystores/broker_truststore_creds new file mode 100644 index 0000000..f3097ab --- /dev/null +++ b/examples/secrets/trustoresandkeystores/broker_truststore_creds @@ -0,0 +1 @@ +password diff --git a/examples/secrets/trustoresandkeystores/kafka.broker.keystore.jks b/examples/secrets/trustoresandkeystores/kafka.broker.keystore.jks new file mode 100644 index 0000000..5bd0ed7 Binary files /dev/null and b/examples/secrets/trustoresandkeystores/kafka.broker.keystore.jks differ diff --git a/examples/secrets/trustoresandkeystores/kafka.broker.truststore.jks b/examples/secrets/trustoresandkeystores/kafka.broker.truststore.jks new file mode 100644 index 0000000..4b732b8 Binary files /dev/null and b/examples/secrets/trustoresandkeystores/kafka.broker.truststore.jks differ diff --git a/examples/secrets/trustoresandkeystores/kafka.client.keystore.jks b/examples/secrets/trustoresandkeystores/kafka.client.keystore.jks new file mode 100644 index 0000000..dc105d9 Binary files /dev/null and b/examples/secrets/trustoresandkeystores/kafka.client.keystore.jks differ diff --git a/examples/secrets/trustoresandkeystores/kafka.client.truststore.jks b/examples/secrets/trustoresandkeystores/kafka.client.truststore.jks new file mode 100644 index 0000000..b003dfd Binary files /dev/null and b/examples/secrets/trustoresandkeystores/kafka.client.truststore.jks differ diff --git a/settings.gradle b/settings.gradle index 819974b..11475e4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -47,10 +47,12 @@ rootProject.name = "ballerinax-${projectName}" include ":checkstyle" include ":${projectName}-native" include ":${projectName}-ballerina" +include ":${projectName}-examples" project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") project(":${projectName}-native").projectDir = file('native') project(":${projectName}-ballerina").projectDir = file('ballerina') +project(":${projectName}-examples").projectDir = file('examples') gradleEnterprise { buildScan {