From e275db2ad04ce1ab93e6be8b4d83203dbfd21717 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 11:40:54 -0300 Subject: [PATCH 01/83] Alignment: bytes package --- .../io/zenoh/{prelude => bytes}/Encoding.kt | 4 +- .../kotlin/io/zenoh/bytes/IntoZBytes.kt | 18 +++++ .../kotlin/io/zenoh/bytes/ZBytes.kt | 68 +++++++++++++++++++ .../kotlin/io/zenoh/jni/JNISession.kt | 4 +- .../kotlin/io/zenoh/publication/Put.kt | 1 + .../commonMain/kotlin/io/zenoh/value/Value.kt | 2 +- 6 files changed, 91 insertions(+), 6 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{prelude => bytes}/Encoding.kt (99%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/Encoding.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt similarity index 99% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/Encoding.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt index 22e3fdc5..8c10a497 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/Encoding.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.prelude +package io.zenoh.bytes /** * Default encoding values used by Zenoh. @@ -115,5 +115,3 @@ class Encoding(val id: ID, val schema: String? = null) { } } } - - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt new file mode 100644 index 00000000..41f6f86c --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt @@ -0,0 +1,18 @@ +package io.zenoh.bytes + +/** + * IntoZBytes interface. + * + * Classes implementing this interface can be serialized into a ZBytes object. + * + * Example: + * ```kotlin + * class Foo(val content: String) : IntoZBytes { + * + * override fun into(): ZBytes = content.into() + * } + * ``` + */ +interface IntoZBytes { + fun into(): ZBytes +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt new file mode 100644 index 00000000..35cd9d52 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt @@ -0,0 +1,68 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.bytes + +/** + * ZBytes contains the serialized bytes of user data. + * + * It provides convenient methods to the user for serialization/deserialization. + * + * **NOTE** + * + * Zenoh semantic and protocol take care of sending and receiving bytes + * without restricting the actual data types. Default (de)serializers are provided for + * convenience to the users to deal with primitives data types via a simple + * out-of-the-box encoding. They are NOT by any means the only (de)serializers + * users can use nor a limitation to the types supported by Zenoh. Users are free and + * encouraged to use any data format of their choice like JSON, protobuf, + * flatbuffers, etc. + * + * See also: [ZBytes examples](https://github.com/eclipse-zenoh/zenoh-kotlin/blob/main/examples/src/main/kotlin/io.zenoh/ZBytes.kt) + */ +class ZBytes internal constructor(internal val bytes: ByteArray) : IntoZBytes { + + companion object { + + /** + * Creates a [ZBytes] instance from a [String]. + */ + fun from(string: String) = ZBytes(string.encodeToByteArray()) + + /** + * Creates a [ZBytes] instance from a [ByteArray]. + */ + fun from(bytes: ByteArray) = ZBytes(bytes) + } + + /** Returns the internal byte representation of the [ZBytes]. */ + fun toBytes(): ByteArray = bytes + + /** Attempts to decode the [ZBytes] into a string with UTF-8 encoding. */ + @Throws + fun tryToString(): String = + bytes.decodeToString(throwOnInvalidSequence = true) + + override fun toString(): String = bytes.decodeToString() + + override fun into(): ZBytes = this + + override fun equals(other: Any?) = other is ZBytes && bytes.contentEquals(other.bytes) + + override fun hashCode() = bytes.contentHashCode() +} + +internal fun ByteArray.into(): ZBytes { + return ZBytes(this) +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index e12b2948..e10fae1f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -15,8 +15,8 @@ package io.zenoh.jni import io.zenoh.* -import io.zenoh.prelude.Encoding -import io.zenoh.prelude.Encoding.ID +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.Encoding.ID import io.zenoh.exceptions.SessionException import io.zenoh.exceptions.ZenohException import io.zenoh.handlers.Callback diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt index 94266a25..c75528d7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt @@ -16,6 +16,7 @@ package io.zenoh.publication import io.zenoh.Resolvable import io.zenoh.Session +import io.zenoh.bytes.Encoding import io.zenoh.exceptions.ZenohException import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.* diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt index ba787bcb..9a68eb0d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt @@ -14,7 +14,7 @@ package io.zenoh.value -import io.zenoh.prelude.Encoding +import io.zenoh.bytes.Encoding /** * A Zenoh value. From bd94fe31a28ca056fc39cf168880a832cd2d02a4 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 11:58:53 -0300 Subject: [PATCH 02/83] Alignment: encoding update --- .../kotlin/io/zenoh/bytes/Encoding.kt | 486 +++++++++++++++--- 1 file changed, 408 insertions(+), 78 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt index 8c10a497..e9c14984 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt @@ -24,9 +24,413 @@ package io.zenoh.bytes * * A set of associated constants are provided to cover the most common encodings for user convenience. * This is particularly useful in helping Zenoh to perform additional network optimizations. - * */ -class Encoding(val id: ID, val schema: String? = null) { +class Encoding private constructor( + internal val id: Int, + internal val schema: String? = null, + private val description: String? = null +) { + internal constructor(id: Int, schema: String? = null) : this(id, schema, null) + + companion object { + /** + * Just some bytes. + * + * Constant alias for string: `"zenoh/bytes"`. + * + * Usually used for types: `ByteArray`, `List`. + */ + val ZENOH_BYTES = Encoding(0, description = "zenoh/bytes") + + /** + * A UTF-8 string. + * + * Constant alias for string: `"zenoh/string"`. + * + * Usually used for type: `String`. + */ + val ZENOH_STRING = Encoding(1, description = "zenoh/string") + + /** + * Zenoh serialized data. + * + * Constant alias for string: `"zenoh/serialized"`. + */ + val ZENOH_SERIALIZED = Encoding(2, description = "zenoh/serialized") + + /** + * An application-specific stream of bytes. + * + * Constant alias for string: `"application/octet-stream"`. + */ + val APPLICATION_OCTET_STREAM = Encoding(3, description = "application/octet-stream") + + /** + * A textual file. + * + * Constant alias for string: `"text/plain"`. + */ + val TEXT_PLAIN = Encoding(4, description = "text/plain") + + /** + * JSON data intended to be consumed by an application. + * + * Constant alias for string: `"application/json"`. + */ + val APPLICATION_JSON = Encoding(5, description = "application/json") + + /** + * JSON data intended to be human readable. + * + * Constant alias for string: `"text/json"`. + */ + val TEXT_JSON = Encoding(6, description = "text/json") + + /** + * A Common Data Representation (CDR)-encoded data. + * + * Constant alias for string: `"application/cdr"`. + */ + val APPLICATION_CDR = Encoding(7, description = "application/cdr") + + /** + * A Concise Binary Object Representation (CBOR)-encoded data. + * + * Constant alias for string: `"application/cbor"`. + */ + val APPLICATION_CBOR = Encoding(8, description = "application/cbor") + + /** + * YAML data intended to be consumed by an application. + * + * Constant alias for string: `"application/yaml"`. + */ + val APPLICATION_YAML = Encoding(9, description = "application/yaml") + + /** + * YAML data intended to be human readable. + * + * Constant alias for string: `"text/yaml"`. + */ + val TEXT_YAML = Encoding(10, description = "text/yaml") + + /** + * JSON5 encoded data that are human readable. + * + * Constant alias for string: `"text/json5"`. + */ + val TEXT_JSON5 = Encoding(11, description = "text/json5") + + /** + * A Python object serialized using [pickle](https://docs.python.org/3/library/pickle.html). + * + * Constant alias for string: `"application/python-serialized-object"`. + */ + val APPLICATION_PYTHON_SERIALIZED_OBJECT = + Encoding(12, description = "application/python-serialized-object") + + /** + * An application-specific protobuf-encoded data. + * + * Constant alias for string: `"application/protobuf"`. + */ + val APPLICATION_PROTOBUF = Encoding(13, description = "application/protobuf") + + /** + * A Java serialized object. + * + * Constant alias for string: `"application/java-serialized-object"`. + */ + val APPLICATION_JAVA_SERIALIZED_OBJECT = + Encoding(14, description = "application/java-serialized-object") + + /** + * OpenMetrics data, commonly used by [Prometheus](https://prometheus.io/). + * + * Constant alias for string: `"application/openmetrics-text"`. + */ + val APPLICATION_OPENMETRICS_TEXT = + Encoding(15, description = "application/openmetrics-text") + + /** + * A Portable Network Graphics (PNG) image. + * + * Constant alias for string: `"image/png"`. + */ + val IMAGE_PNG = Encoding(16, description = "image/png") + + /** + * A Joint Photographic Experts Group (JPEG) image. + * + * Constant alias for string: `"image/jpeg"`. + */ + val IMAGE_JPEG = Encoding(17, description = "image/jpeg") + + /** + * A Graphics Interchange Format (GIF) image. + * + * Constant alias for string: `"image/gif"`. + */ + val IMAGE_GIF = Encoding(18, description = "image/gif") + + /** + * A BitMap (BMP) image. + * + * Constant alias for string: `"image/bmp"`. + */ + val IMAGE_BMP = Encoding(19, description = "image/bmp") + + /** + * A WebP image. + * + * Constant alias for string: `"image/webp"`. + */ + val IMAGE_WEBP = Encoding(20, description = "image/webp") + + /** + * An XML file intended to be consumed by an application. + * + * Constant alias for string: `"application/xml"`. + */ + val APPLICATION_XML = Encoding(21, description = "application/xml") + + /** + * A list of tuples, each consisting of a name and a value. + * + * Constant alias for string: `"application/x-www-form-urlencoded"`. + */ + val APPLICATION_X_WWW_FORM_URLENCODED = + Encoding(22, description = "application/x-www-form-urlencoded") + + /** + * An HTML file. + * + * Constant alias for string: `"text/html"`. + */ + val TEXT_HTML = Encoding(23, description = "text/html") + + /** + * An XML file that is human readable. + * + * Constant alias for string: `"text/xml"`. + */ + val TEXT_XML = Encoding(24, description = "text/xml") + + /** + * A CSS file. + * + * Constant alias for string: `"text/css"`. + */ + val TEXT_CSS = Encoding(25, description = "text/css") + + /** + * A JavaScript file. + * + * Constant alias for string: `"text/javascript"`. + */ + val TEXT_JAVASCRIPT = Encoding(26, description = "text/javascript") + + /** + * A Markdown file. + * + * Constant alias for string: `"text/markdown"`. + */ + val TEXT_MARKDOWN = Encoding(27, description = "text/markdown") + + /** + * A CSV file. + * + * Constant alias for string: `"text/csv"`. + */ + val TEXT_CSV = Encoding(28, description = "text/csv") + + /** + * An application-specific SQL query. + * + * Constant alias for string: `"application/sql"`. + */ + val APPLICATION_SQL = Encoding(29, description = "application/sql") + + /** + * Constrained Application Protocol (CoAP) data intended for CoAP-to-HTTP and HTTP-to-CoAP proxies. + * + * Constant alias for string: `"application/coap-payload"`. + */ + val APPLICATION_COAP_PAYLOAD = Encoding(30, description = "application/coap-payload") + + /** + * Defines a JSON document structure for expressing a sequence of operations to apply to a JSON document. + * + * Constant alias for string: `"application/json-patch+json"`. + */ + val APPLICATION_JSON_PATCH_JSON = Encoding(31, description = "application/json-patch+json") + + /** + * A JSON text sequence consists of any number of JSON texts, all encoded in UTF-8. + * + * Constant alias for string: `"application/json-seq"`. + */ + val APPLICATION_JSON_SEQ = Encoding(32, description = "application/json-seq") + + /** + * A JSONPath defines a string syntax for selecting and extracting JSON values from within a given JSON value. + * + * Constant alias for string: `"application/jsonpath"`. + */ + val APPLICATION_JSONPATH = Encoding(33, description = "application/jsonpath") + + /** + * A JSON Web Token (JWT). + * + * Constant alias for string: `"application/jwt"`. + */ + val APPLICATION_JWT = Encoding(34, description = "application/jwt") + + /** + * An application-specific MPEG-4 encoded data, either audio or video. + * + * Constant alias for string: `"application/mp4"`. + */ + val APPLICATION_MP4 = Encoding(35, description = "application/mp4") + + /** + * A SOAP 1.2 message serialized as XML 1.0. + * + * Constant alias for string: `"application/soap+xml"`. + */ + val APPLICATION_SOAP_XML = Encoding(36, description = "application/soap+xml") + + /** + * A YANG-encoded data commonly used by the Network Configuration Protocol (NETCONF). + * + * Constant alias for string: `"application/yang"`. + */ + val APPLICATION_YANG = Encoding(37, description = "application/yang") + + /** + * A MPEG-4 Advanced Audio Coding (AAC) media. + * + * Constant alias for string: `"audio/aac"`. + */ + val AUDIO_AAC = Encoding(38, description = "audio/aac") + + /** + * A Free Lossless Audio Codec (FLAC) media. + * + * Constant alias for string: `"audio/flac"`. + */ + val AUDIO_FLAC = Encoding(39, description = "audio/flac") + + /** + * An audio codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority. + * + * Constant alias for string: `"audio/mp4"`. + */ + val AUDIO_MP4 = Encoding(40, description = "audio/mp4") + + /** + * An Ogg-encapsulated audio stream. + * + * Constant alias for string: `"audio/ogg"`. + */ + val AUDIO_OGG = Encoding(41, description = "audio/ogg") + + /** + * A Vorbis-encoded audio stream. + * + * Constant alias for string: `"audio/vorbis"`. + */ + val AUDIO_VORBIS = Encoding(42, description = "audio/vorbis") + + /** + * A h261-encoded video stream. + * + * Constant alias for string: `"video/h261"`. + */ + val VIDEO_H261 = Encoding(43, description = "video/h261") + + /** + * A h263-encoded video stream. + * + * Constant alias for string: `"video/h263"`. + */ + val VIDEO_H263 = Encoding(44, description = "video/h263") + + /** + * A h264-encoded video stream. + * + * Constant alias for string: `"video/h264"`. + */ + val VIDEO_H264 = Encoding(45, description = "video/h264") + + /** + * A h265-encoded video stream. + * + * Constant alias for string: `"video/h265"`. + */ + val VIDEO_H265 = Encoding(46, description = "video/h265") + + /** + * A h266-encoded video stream. + * + * Constant alias for string: `"video/h266"`. + */ + val VIDEO_H266 = Encoding(47, description = "video/h266") + + /** + * A video codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority. + * + * Constant alias for string: `"video/mp4"`. + */ + val VIDEO_MP4 = Encoding(48, description = "video/mp4") + + /** + * An Ogg-encapsulated video stream. + * + * Constant alias for string: `"video/ogg"`. + */ + val VIDEO_OGG = Encoding(49, description = "video/ogg") + + /** + * An uncompressed, studio-quality video stream. + * + * Constant alias for string: `"video/raw"`. + */ + val VIDEO_RAW = Encoding(50, description = "video/raw") + + /** + * A VP8-encoded video stream. + * + * Constant alias for string: `"video/vp8"`. + */ + val VIDEO_VP8 = Encoding(51, description = "video/vp8") + + /** + * A VP9-encoded video stream. + * + * Constant alias for string: `"video/vp9"`. + */ + val VIDEO_VP9 = Encoding(52, description = "video/vp9") + + /** + * The default [Encoding] is [ZENOH_BYTES]. + */ + fun default() = ZENOH_BYTES + } + + /** + * Set a schema to this encoding. Zenoh does not define what a schema is and its semantics is left to the implementer. + * E.g. a common schema for `text/plain` encoding is `utf-8`. + */ + fun withSchema(schema: String): Encoding { + return Encoding(this.id, schema, this.description) + } + + override fun toString(): String { + val base = description ?: "unknown(${this.id})" + val schemaInfo = schema?.let { ";$it" } ?: "" + return "$base$schemaInfo" + } override fun equals(other: Any?): Boolean { if (this === other) return true @@ -34,84 +438,10 @@ class Encoding(val id: ID, val schema: String? = null) { other as Encoding - if (id != other.id) return false - return schema == other.schema + return id == other.id && schema == other.schema } override fun hashCode(): Int { - var result = id.hashCode() - result = 31 * result + schema.hashCode() - return result - } - - /** - * The ID of the encoding. - * - * @property id The id of the encoding. - * @property encoding The encoding name. - */ - enum class ID(val id: Int, val encoding: String) { - ZENOH_BYTES(0, "zenoh/bytes"), - ZENOH_INT(1, "zenoh/int"), - ZENOH_UINT(2, "zenoh/uint"), - ZENOH_FLOAT(3, "zenoh/float"), - ZENOH_BOOL(4, "zenoh/bool"), - ZENOH_STRING(5, "zenoh/string"), - ZENOH_ERROR(6, "zenoh/error"), - APPLICATION_OCTET_STREAM(7, "application/octet-stream"), - TEXT_PLAIN(8, "text/plain"), - APPLICATION_JSON(9, "application/json"), - TEXT_JSON(10, "text/json"), - APPLICATION_CDR(11, "application/cdr"), - APPLICATION_CBOR(12, "application/cbor"), - APPLICATION_YAML(13, "application/yaml"), - TEXT_YAML(14, "text/yaml"), - TEXT_JSON5(15, "text/json5"), - APPLICATION_PYTHON_SERIALIZED_OBJECT(16, "application/python-serialized-object"), - APPLICATION_PROTOBUF(17, "application/protobuf"), - APPLICATION_JAVA_SERIALIZED_OBJECT(18, "application/java-serialized-object"), - APPLICATION_OPENMETRICS_TEXT(19, "application/openmetrics-text"), - IMAGE_PNG(20, "image/png"), - IMAGE_JPEG(21, "image/jpeg"), - IMAGE_GIF(22, "image/gif"), - IMAGE_BMP(23, "image/bmp"), - IMAGE_WEBP(24, "image/webp"), - APPLICATION_XML(25, "application/xml"), - APPLICATION_X_WWW_FORM_URLENCODED(26, "application/x-www-form-urlencoded"), - TEXT_HTML(27, "text/html"), - TEXT_XML(28, "text/xml"), - TEXT_CSS(29, "text/css"), - TEXT_JAVASCRIPT(30, "text/javascript"), - TEXT_MARKDOWN(31, "text/markdown"), - TEXT_CSV(32, "text/csv"), - APPLICATION_SQL(33, "application/sql"), - APPLICATION_COAP_PAYLOAD(34, "application/coap-payload"), - APPLICATION_JSON_PATCH_JSON(35, "application/json-patch+json"), - APPLICATION_JSON_SEQ(36, "application/json-seq"), - APPLICATION_JSONPATH(37, "application/jsonpath"), - APPLICATION_JWT(38, "application/jwt"), - APPLICATION_MP4(39, "application/mp4"), - APPLICATION_SOAP_XML(40, "application/soap+xml"), - APPLICATION_YANG(41, "application/yang"), - AUDIO_AAC(42, "audio/aac"), - AUDIO_FLAC(43, "audio/flac"), - AUDIO_MP4(44, "audio/mp4"), - AUDIO_OGG(45, "audio/ogg"), - AUDIO_VORBIS(46, "audio/vorbis"), - VIDEO_H261(47, "video/h261"), - VIDEO_H263(48, "video/h263"), - VIDEO_H264(49, "video/h264"), - VIDEO_H265(50, "video/h265"), - VIDEO_H266(51, "video/h266"), - VIDEO_MP4(52, "video/mp4"), - VIDEO_OGG(53, "video/ogg"), - VIDEO_RAW(54, "video/raw"), - VIDEO_VP8(55, "video/vp8"), - VIDEO_VP9(56, "video/vp9"); - - companion object { - private val idToEnum = entries.associateBy(ID::id) - fun fromId(id: Int): ID? = idToEnum[id] - } + return id.hashCode() } } From 9b62e1e4d926b4b2e090d6cd38805ce37b3c0440 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 12:00:40 -0300 Subject: [PATCH 03/83] Alignment: config package --- .../kotlin/io/zenoh/config/WhatAmI.kt | 30 ++++++++++++++ .../kotlin/io/zenoh/config/ZenohId.kt | 40 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt new file mode 100644 index 00000000..983c9221 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt @@ -0,0 +1,30 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.config + +/** + * WhatAmI + * + * The role of the node sending the `hello` message. + */ +enum class WhatAmI(internal val value: Int) { + Router(1), + Peer(2), + Client(4); + + companion object { + internal fun fromInt(value: Int) = entries.first { value == it.value } + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt new file mode 100644 index 00000000..62fefac5 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt @@ -0,0 +1,40 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.config + +import io.zenoh.jni.JNIZenohId + +/** + * The global unique id of a Zenoh peer. + */ +data class ZenohId internal constructor(internal val bytes: ByteArray) { + + override fun toString(): String { + return JNIZenohId.toStringViaJNI(bytes) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ZenohId + + return bytes.contentEquals(other.bytes) + } + + override fun hashCode(): Int { + return bytes.contentHashCode() + } +} From e9ba08ab5400a6a8d621a6af1dfb85dca7630d77 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 12:30:24 -0300 Subject: [PATCH 04/83] Alignment: replacing all exceptions with ZError --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 31 +++++++++---------- .../io/zenoh/exceptions/JNIException.kt | 23 -------------- .../io/zenoh/exceptions/KeyExprException.kt | 24 -------------- .../io/zenoh/exceptions/SessionException.kt | 22 ------------- .../{ZenohException.kt => ZError.kt} | 4 +-- .../kotlin/io/zenoh/jni/JNIKeyExpr.kt | 6 ++-- .../kotlin/io/zenoh/jni/JNIPublisher.kt | 10 +++--- .../kotlin/io/zenoh/jni/JNIQuery.kt | 14 ++++----- .../kotlin/io/zenoh/jni/JNISession.kt | 22 ++++++------- .../kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt | 7 ++--- .../kotlin/io/zenoh/keyexpr/KeyExpr.kt | 10 +++--- .../kotlin/io/zenoh/publication/Delete.kt | 6 ++-- .../kotlin/io/zenoh/publication/Publisher.kt | 15 +++++---- .../kotlin/io/zenoh/publication/Put.kt | 4 +-- .../commonMain/kotlin/io/zenoh/query/Get.kt | 4 +-- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 6 ++-- .../kotlin/io/zenoh/queryable/Query.kt | 5 ++- .../kotlin/io/zenoh/queryable/Queryable.kt | 5 ++- .../kotlin/io/zenoh/selector/IntoSelector.kt | 7 ++--- .../kotlin/io/zenoh/selector/Selector.kt | 8 ++--- .../kotlin/io/zenoh/subscriber/Subscriber.kt | 4 +-- .../commonTest/kotlin/io/zenoh/KeyExprTest.kt | 4 +-- .../kotlin/io/zenoh/SelectorTest.kt | 4 +-- .../commonTest/kotlin/io/zenoh/SessionTest.kt | 8 ++--- 24 files changed, 89 insertions(+), 164 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIException.kt delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/KeyExprException.kt delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/SessionException.kt rename zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/{ZenohException.kt => ZError.kt} (82%) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index c5e50d67..3ce09725 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -14,8 +14,8 @@ package io.zenoh -import io.zenoh.exceptions.SessionException -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError +import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr @@ -56,16 +56,16 @@ class Session private constructor(private val config: Config) : AutoCloseable { companion object { - private val sessionClosedException = SessionException("Session is closed.") + private val sessionClosedException = ZError("Session is closed.") /** * Open a [Session] with the default [Config]. * * @return The opened [Session]. - * @throws [SessionException] in the case of a failure. + * @throws [ZError] in the case of a failure. */ @JvmStatic - @Throws(SessionException::class) + @Throws(ZError::class) fun open(): Session { val session = Session(Config.default()) return session.launch() @@ -76,10 +76,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * @param config The configuration for the session. * @return The opened [Session]. - * @throws [SessionException] in the case of a failure. + * @throws [ZError] in the case of a failure. */ @JvmStatic - @Throws(SessionException::class) + @Throws(ZError::class) fun open(config: Config): Session { val session = Session(config) return session.launch() @@ -98,7 +98,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * However, any session declaration that was still alive and bound to the session previous to closing it, will still be alive. */ - @Throws(SessionException::class) + @Throws(ZError::class) override fun close() { jniSession?.close() jniSession = null @@ -355,14 +355,14 @@ class Session private constructor(private val config: Config) : AutoCloseable { return jniSession != null } - @Throws(SessionException::class) + @Throws(ZError::class) internal fun resolvePublisher(keyExpr: KeyExpr, qos: QoS): Publisher { return jniSession?.run { declarePublisher(keyExpr, qos) } ?: throw(sessionClosedException) } - @Throws(ZenohException::class) + @Throws(ZError::class) internal fun resolveSubscriber( keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, reliability: Reliability ): Subscriber { @@ -371,7 +371,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { } ?: throw (sessionClosedException) } - @Throws(ZenohException::class) + @Throws(ZError::class) internal fun resolveQueryable( keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, complete: Boolean ): Queryable { @@ -380,7 +380,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { } ?: throw (sessionClosedException) } - @Throws(ZenohException::class) + @Throws(ZError::class) internal fun resolveGet( selector: Selector, callback: Callback, @@ -398,21 +398,20 @@ class Session private constructor(private val config: Config) : AutoCloseable { return jniSession?.performGet(selector, callback, onClose, receiver, timeout, target, consolidation, value, attachment) } - @Throws(ZenohException::class) + @Throws(ZError::class) internal fun resolvePut(keyExpr: KeyExpr, put: Put) { jniSession?.run { performPut(keyExpr, put) } } - @Throws(ZenohException::class) + @Throws(ZError::class) internal fun resolveDelete(keyExpr: KeyExpr, delete: Delete) { jniSession?.run { performDelete(keyExpr, delete) } } /** Launches the session through the jni session, returning the [Session] on success. */ - @Throws(SessionException::class) + @Throws(ZError::class) private fun launch(): Session { jniSession!!.open(config) return this } } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIException.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIException.kt deleted file mode 100644 index dd06cda7..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIException.kt +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.exceptions - -/** - * JNI (Java native interface) exception. - * - * This type of exception is thrown from the native code when something goes wrong regarding the - * communication between the Java/Kotlin layer and the native layer through the JNI. - */ -class JNIException(msg: String?) : ZenohException(msg) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/KeyExprException.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/KeyExprException.kt deleted file mode 100644 index 5836e02c..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/KeyExprException.kt +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.exceptions - -/** - * Key expression exception. - * - * This kind of exceptions are thrown from the native code when something goes wrong regarding a key expression, - * for instance when attempting to create a [io.zenoh.keyexpr.KeyExpr] from a string that does not respect the - * key expression conventions. - */ -class KeyExprException(msg: String) : ZenohException(msg) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/SessionException.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/SessionException.kt deleted file mode 100644 index 02027e0f..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/SessionException.kt +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.exceptions - -/** - * Session exception. - * - * This kind of exceptions are thrown from the native code when something goes wrong with a Zenoh session. - */ -class SessionException(message: String?) : ZenohException(message) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZenohException.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt similarity index 82% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZenohException.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt index c94a2dac..c63a19ce 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZenohException.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt @@ -15,6 +15,6 @@ package io.zenoh.exceptions /** - * A Zenoh exception. + * A Zenoh Error. */ -abstract class ZenohException(override val message: String? = null) : Exception() +class ZError(override val message: String? = null): Exception() diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt index a8e62cc4..764c7052 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt @@ -15,19 +15,19 @@ package io.zenoh.jni import io.zenoh.Zenoh -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr internal class JNIKeyExpr(internal val ptr: Long) { companion object { - @Throws(ZenohException::class) + @Throws(ZError::class) fun tryFrom(keyExpr: String): KeyExpr { Zenoh.load() // It may happen the zenoh library is not yet loaded when creating a key expression. return KeyExpr(tryFromViaJNI(keyExpr)) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun autocanonize(keyExpr: String): KeyExpr { Zenoh.load() return KeyExpr(autocanonizeViaJNI(keyExpr)) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt index b2eb478f..83e6c2b9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt @@ -14,7 +14,7 @@ package io.zenoh.jni -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.value.Value /** @@ -30,7 +30,7 @@ internal class JNIPublisher(private val ptr: Long) { * @param value The [Value] to be put. * @param attachment Optional attachment. */ - @Throws(ZenohException::class) + @Throws(ZError::class) fun put(value: Value, attachment: ByteArray?) { putViaJNI(value.payload, value.encoding.id.ordinal, value.encoding.schema, attachment, ptr) } @@ -40,7 +40,7 @@ internal class JNIPublisher(private val ptr: Long) { * * @param attachment Optional attachment. */ - @Throws(ZenohException::class) + @Throws(ZError::class) fun delete(attachment: ByteArray?) { deleteViaJNI(attachment, ptr) } @@ -54,12 +54,12 @@ internal class JNIPublisher(private val ptr: Long) { freePtrViaJNI(ptr) } - @Throws(ZenohException::class) + @Throws(ZError::class) private external fun putViaJNI( valuePayload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?, ptr: Long ) - @Throws(ZenohException::class) + @Throws(ZError::class) private external fun deleteViaJNI(attachment: ByteArray?, ptr: Long) private external fun freePtrViaJNI(ptr: Long) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt index 20b8fb87..013f5a2f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt @@ -14,7 +14,7 @@ package io.zenoh.jni -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.QoS import io.zenoh.sample.Sample @@ -30,7 +30,7 @@ import org.apache.commons.net.ntp.TimeStamp */ internal class JNIQuery(private val ptr: Long) { - @Throws(ZenohException::class) + @Throws(ZError::class) fun replySuccess(sample: Sample) { val timestampEnabled = sample.timestamp != null replySuccessViaJNI( @@ -49,12 +49,12 @@ internal class JNIQuery(private val ptr: Long) { ) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun replyError(errorValue: Value) { replyErrorViaJNI(ptr, errorValue.payload, errorValue.encoding.id.ordinal, errorValue.encoding.schema) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun replyDelete(keyExpr: KeyExpr, timestamp: TimeStamp?, attachment: ByteArray?, qos: QoS) { val timestampEnabled = timestamp != null replyDeleteViaJNI( @@ -74,7 +74,7 @@ internal class JNIQuery(private val ptr: Long) { freePtrViaJNI(ptr) } - @Throws(ZenohException::class) + @Throws(ZError::class) private external fun replySuccessViaJNI( queryPtr: Long, keyExprPtr: Long, @@ -90,7 +90,7 @@ internal class JNIQuery(private val ptr: Long) { qosCongestionControl: Int, ) - @Throws(ZenohException::class) + @Throws(ZError::class) private external fun replyErrorViaJNI( queryPtr: Long, errorValuePayload: ByteArray, @@ -98,7 +98,7 @@ internal class JNIQuery(private val ptr: Long) { encodingSchema: String?, ) - @Throws(ZenohException::class) + @Throws(ZError::class) private external fun replyDeleteViaJNI( queryPtr: Long, keyExprPtr: Long, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index e10fae1f..f4529a48 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -17,8 +17,8 @@ package io.zenoh.jni import io.zenoh.* import io.zenoh.bytes.Encoding import io.zenoh.bytes.Encoding.ID -import io.zenoh.exceptions.SessionException -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError +import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.callbacks.JNIOnCloseCallback import io.zenoh.jni.callbacks.JNIGetCallback @@ -48,7 +48,7 @@ internal class JNISession { /* Pointer to the underlying Rust zenoh session. */ private var sessionPtr: AtomicLong = AtomicLong(0) - @Throws(ZenohException::class) + @Throws(ZError::class) fun open(config: Config) { config.jsonConfig?.let { jsonConfig -> sessionPtr.set(openSessionWithJsonConfigViaJNI(jsonConfig.toString())) @@ -57,12 +57,12 @@ internal class JNISession { } } - @Throws(ZenohException::class) + @Throws(ZError::class) fun close() { closeSessionViaJNI(sessionPtr.get()) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun declarePublisher(keyExpr: KeyExpr, qos: QoS): Publisher { val publisherRawPtr = declarePublisherViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, @@ -79,7 +79,7 @@ internal class JNISession { ) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun declareSubscriber( keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, reliability: Reliability ): Subscriber { @@ -102,7 +102,7 @@ internal class JNISession { return Subscriber(keyExpr, receiver, JNISubscriber(subscriberRawPtr)) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun declareQueryable( keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, complete: Boolean ): Queryable { @@ -122,7 +122,7 @@ internal class JNISession { return Queryable(keyExpr, receiver, JNIQueryable(queryableRawPtr)) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun performGet( selector: Selector, callback: Callback, @@ -200,18 +200,18 @@ internal class JNISession { return receiver } - @Throws(ZenohException::class) + @Throws(ZError::class) fun declareKeyExpr(keyExpr: String): KeyExpr { val ptr = declareKeyExprViaJNI(sessionPtr.get(), keyExpr) return KeyExpr(keyExpr, JNIKeyExpr(ptr)) } - @Throws(ZenohException::class) + @Throws(ZError::class) fun undeclareKeyExpr(keyExpr: KeyExpr) { keyExpr.jniKeyExpr?.run { undeclareKeyExprViaJNI(sessionPtr.get(), this.ptr) keyExpr.jniKeyExpr = null - } ?: throw SessionException("Attempting to undeclare a non declared key expression.") + } ?: throw ZError("Attempting to undeclare a non declared key expression.") } @Throws(Exception::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt index 74ab2d80..f9ace4d8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt @@ -14,13 +14,12 @@ package io.zenoh.keyexpr -import io.zenoh.exceptions.KeyExprException +import io.zenoh.exceptions.ZError -@Throws(KeyExprException::class) +@Throws(ZError::class) fun String.intoKeyExpr(): KeyExpr { if (this.isEmpty()) { - throw(KeyExprException("Attempting to create a KeyExpr from an empty string.")) + throw(ZError("Attempting to create a KeyExpr from an empty string.")) } return KeyExpr.autocanonize(this) } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt index ec138385..d8676bc4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt @@ -16,7 +16,7 @@ package io.zenoh.keyexpr import io.zenoh.Resolvable import io.zenoh.Session -import io.zenoh.exceptions.KeyExprException +import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIKeyExpr /** @@ -74,10 +74,10 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * * @param keyExpr The intended key expression as a string. * @return The [KeyExpr] in case of success. - * @throws KeyExprException in the case of failure. + * @throws ZError in the case of failure. */ @JvmStatic - @Throws(KeyExprException::class) + @Throws(ZError::class) fun tryFrom(keyExpr: String): KeyExpr { return JNIKeyExpr.tryFrom(keyExpr) } @@ -90,10 +90,10 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * * @param keyExpr The intended key expression as a string. * @return The canonized [KeyExpr]. - * @throws KeyExprException in the case of failure. + * @throws ZError in the case of failure. */ @JvmStatic - @Throws(KeyExprException::class) + @Throws(ZError::class) fun autocanonize(keyExpr: String): KeyExpr { return JNIKeyExpr.autocanonize(keyExpr) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt index 22cf7f60..c27ebe80 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt @@ -16,7 +16,7 @@ package io.zenoh.publication import io.zenoh.Resolvable import io.zenoh.Session -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.CongestionControl import io.zenoh.prelude.Priority @@ -28,7 +28,7 @@ import kotlin.Throws * * Example: * ```java - * public void deleteExample() throws ZenohException { + * public void deleteExample() throws ZError { * System.out.println("Opening session..."); * try (Session session = Session.open()) { * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/java/example")) { @@ -95,7 +95,7 @@ class Delete private constructor( * A successful [Result] only states the Delete request was properly sent through the network, it doesn't mean it * was properly executed remotely. */ - @Throws(ZenohException::class) + @Throws(ZError::class) override fun res() { val delete = Delete(this.keyExpr, qosBuilder.build(), attachment) session.resolveDelete(keyExpr, delete) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt index e22298bc..c6b64e4d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt @@ -15,8 +15,8 @@ package io.zenoh.publication import io.zenoh.* -import io.zenoh.exceptions.SessionException -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError +import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIPublisher import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.CongestionControl @@ -48,7 +48,7 @@ import kotlin.Throws * } * } * } - * } catch (ZenohException | InterruptedException e) { + * } catch (ZError | InterruptedException e) { * System.out.println("Error: " + e); * } * ``` @@ -67,7 +67,7 @@ class Publisher internal constructor( ) : SessionDeclaration, AutoCloseable { companion object { - private val sessionException = SessionException("Publisher is not valid.") + private val ZError = ZError("Publisher is not valid.") } /** Performs a PUT operation on the specified [keyExpr] with the specified [value]. */ @@ -120,7 +120,7 @@ class Publisher internal constructor( fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } override fun res() { - jniPublisher?.put(value, attachment) ?: throw(sessionException) + jniPublisher?.put(value, attachment) ?: throw(ZError) } } @@ -131,9 +131,9 @@ class Publisher internal constructor( fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } - @Throws(ZenohException::class) + @Throws(ZError::class) override fun res() { - jniPublisher?.delete(attachment) ?: throw(sessionException) + jniPublisher?.delete(attachment) ?: throw(ZError) } } @@ -167,4 +167,3 @@ class Publisher internal constructor( } } } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt index c75528d7..b613fb03 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt @@ -17,7 +17,7 @@ package io.zenoh.publication import io.zenoh.Resolvable import io.zenoh.Session import io.zenoh.bytes.Encoding -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.* import io.zenoh.value.Value @@ -109,7 +109,7 @@ class Put private constructor( fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } /** Resolves the put operation, returning a [Result]. */ - @Throws(ZenohException::class) + @Throws(ZError::class) override fun res() { val put = Put(keyExpr, value, qosBuilder.build(), attachment) session.run { resolvePut(keyExpr, put) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index fcd74e9e..04bdace1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -16,7 +16,7 @@ package io.zenoh.query import io.zenoh.handlers.Callback import io.zenoh.Session -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler import io.zenoh.selector.Selector @@ -168,7 +168,7 @@ class Get private constructor() { * * @return The receiver [R] from the specified [Handler] (if specified). */ - @Throws(ZenohException::class) + @Throws(ZError::class) fun res(): R? { require(callback != null || handler != null) { "Either a callback or a handler must be provided." } val resolvedCallback = callback ?: Callback { t: Reply -> handler?.handle(t) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index 01d3ed98..47f646e3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -16,7 +16,7 @@ package io.zenoh.query import io.zenoh.Resolvable import io.zenoh.ZenohType -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.sample.Sample import io.zenoh.prelude.SampleKind import io.zenoh.value.Value @@ -163,7 +163,7 @@ sealed class Reply private constructor(val replierId: ZenohID?) : ZenohType { /** * Constructs the reply sample with the provided parameters and triggers the reply to the query. */ - @Throws(ZenohException::class) + @Throws(ZError::class) override fun res() { val sample = Sample(keyExpr, value, kind, timeStamp, qosBuilder.build(), attachment) return query.reply(Success(null, sample)).res() @@ -287,4 +287,4 @@ sealed class Reply private constructor(val replierId: ZenohID?) : ZenohType { } } } -} \ No newline at end of file +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt index cd4b7c80..7001a2ab 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt @@ -18,7 +18,7 @@ import io.zenoh.Resolvable import io.zenoh.ZenohType import io.zenoh.selector.Selector import io.zenoh.value.Value -import io.zenoh.exceptions.SessionException +import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIQuery import io.zenoh.keyexpr.KeyExpr import io.zenoh.query.Reply @@ -93,7 +93,6 @@ class Query internal constructor( jniQuery = null return@Resolvable result } - throw(SessionException("Query is invalid")) + throw(ZError("Query is invalid")) } } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt index 1c13f44d..4baaf117 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt @@ -15,7 +15,7 @@ package io.zenoh.queryable import io.zenoh.* -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler @@ -161,7 +161,7 @@ class Queryable internal constructor( * * @return The newly created [Queryable]. */ - @Throws(ZenohException::class) + @Throws(ZError::class) override fun res(): Queryable { require(callback != null || handler != null) { "Either a callback or a handler must be provided." } val resolvedCallback = callback ?: Callback { t: Query -> handler?.handle(t) } @@ -173,4 +173,3 @@ class Queryable internal constructor( } } } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt index fe47ac68..8ad604e9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt @@ -14,17 +14,16 @@ package io.zenoh.selector -import io.zenoh.exceptions.KeyExprException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr -@Throws(KeyExprException::class) +@Throws(ZError::class) fun String.intoSelector(): Selector { if (this.isEmpty()) { - throw(KeyExprException("Attempting to create a KeyExpr from an empty string.")) + throw(ZError("Attempting to create a KeyExpr from an empty string.")) } val result = this.split('?', limit = 2) val keyExpr = KeyExpr.autocanonize(result[0]) val params = if (result.size == 2) result[1] else "" return Selector(keyExpr, params) } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt index 133bcc04..6d06f092 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt @@ -14,7 +14,7 @@ package io.zenoh.selector -import io.zenoh.exceptions.KeyExprException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr /** @@ -39,13 +39,13 @@ class Selector(val keyExpr: KeyExpr, val parameters: String = ""): AutoCloseable * * @param expression A string with the form "?". * @return A [Selector] in case of success. - * @throws KeyExprException in case of failure generating the key expression. + * @throws ZError in case of failure generating the key expression. */ @JvmStatic - @Throws(KeyExprException::class) + @Throws(ZError::class) fun tryFrom(expression: String): Selector { if (expression.isEmpty()) { - throw(KeyExprException("Attempting to create a KeyExpr from an empty string.")) + throw(ZError("Attempting to create a KeyExpr from an empty string.")) } val result = expression.split('?', limit = 2) val keyExpr = KeyExpr.autocanonize(result[0]) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt index 53b41f3a..cd24ac24 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt @@ -15,7 +15,7 @@ package io.zenoh.subscriber import io.zenoh.* -import io.zenoh.exceptions.ZenohException +import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler @@ -170,7 +170,7 @@ class Subscriber internal constructor( * * @return The newly created [Subscriber]. */ - @Throws(ZenohException::class) + @Throws(ZError::class) override fun res(): Subscriber { require(callback != null || handler != null) { "Either a callback or a handler must be provided." } val resolvedCallback = callback ?: Callback { t: Sample -> handler?.handle(t) } diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt index bb0b0ec2..4af63cde 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt @@ -14,7 +14,7 @@ package io.zenoh -import io.zenoh.exceptions.SessionException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr import org.junit.Assert.assertThrows @@ -107,7 +107,7 @@ class KeyExprTest { // Undeclaring a key expr that was not declared through a session. val keyExpr2 = "x/y/z".intoKeyExpr() - assertThrows(SessionException::class.java) {session.undeclare(keyExpr2).res()} + assertThrows(ZError::class.java) {session.undeclare(keyExpr2).res()} session.close() keyExpr.close() diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt index 99d133f4..eab167fd 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt @@ -1,6 +1,6 @@ package io.zenoh -import io.zenoh.exceptions.KeyExprException +import io.zenoh.exceptions.ZError import io.zenoh.selector.Selector import io.zenoh.selector.intoSelector import kotlin.test.Test @@ -25,6 +25,6 @@ class SelectorTest { assertEquals("", selector.parameters) } - assertFailsWith { "".intoSelector() } + assertFailsWith { "".intoSelector() } } } diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt index 89d1a47b..10bef2f9 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt @@ -14,7 +14,7 @@ package io.zenoh -import io.zenoh.exceptions.SessionException +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.intoKeyExpr import io.zenoh.sample.Sample import kotlin.test.* @@ -57,9 +57,9 @@ class SessionTest { fun sessionClose_newDeclarationsReturnNullAfterClosingSession() { val session = Session.open() session.close() - assertFailsWith { session.declarePublisher(TEST_KEY_EXP).res() } - assertFailsWith { session.declareSubscriber(TEST_KEY_EXP).with {}.res() } - assertFailsWith { session.declareQueryable(TEST_KEY_EXP).with {}.res() } + assertFailsWith { session.declarePublisher(TEST_KEY_EXP).res() } + assertFailsWith { session.declareSubscriber(TEST_KEY_EXP).with {}.res() } + assertFailsWith { session.declareQueryable(TEST_KEY_EXP).with {}.res() } } } From 941efe8ad3fe9bef57fb856fc6c661dfe5447e24 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 12:34:54 -0300 Subject: [PATCH 05/83] Alignment: ext package --- .../kotlin/io/zenoh/ext/ZDeserialize.kt | 76 +++++++++++++++++++ .../kotlin/io/zenoh/ext/ZSerialize.kt | 76 +++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt new file mode 100644 index 00000000..93d86a4c --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt @@ -0,0 +1,76 @@ +package io.zenoh.ext + +import io.zenoh.bytes.ZBytes +import io.zenoh.jni.JNIZBytes.deserializeViaJNI +import kotlin.reflect.typeOf + +/** + * Deserialize the [ZBytes] instance into an element of type [T]. + * + * This function supports the following types: + * - [Boolean] + * - [Byte] + * - [Short] + * - [Int] + * - [Long] + * - [Float] + * - [Double] + * - [UByte] + * - [UShort] + * - [UInt] + * - [ULong] + * - [List] + * - [String] + * - [ByteArray] + * - [Map] + * - [Pair] + * - [Triple] + * + * **NOTE** + * + * This deserialization utility can be used across the Zenoh ecosystem with Zenoh + * versions based on other supported languages such as Rust, Python, C and C++. + * This works when the types are equivalent (a `Byte` corresponds to an `i8` in Rust, a `Short` to an `i16`, etc). + * + * ### Examples + * + * For a Boolean: + * ``` + * val input: Boolean = true + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For a List: + * ``` + * val input: List = listOf(1, 2, 3, 4, 5) + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize>(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For a nested list: + * ``` + * val input: List> = listOf(listOf(1, 2, 3)) + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize>>(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For a combined list of maps: + * ``` + * val input: List> = listOf(mapOf("a" to 1, "b" to 2)) + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize>>(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For additional examples, checkout the [ZBytes examples](https://github.com/eclipse-zenoh/zenoh-kotlin/blob/main/examples/src/main/kotlin/io.zenoh/ZBytes.kt). + * + * @see ZBytes + * @return a [Result] with the deserialization. + */ +inline fun zDeserialize(zbytes: ZBytes): Result = runCatching { + deserializeViaJNI(zbytes, typeOf()) as T +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt new file mode 100644 index 00000000..e4d9b224 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt @@ -0,0 +1,76 @@ +package io.zenoh.ext + +import io.zenoh.bytes.ZBytes +import io.zenoh.jni.JNIZBytes.serializeViaJNI +import kotlin.reflect.typeOf + +/** + * Serializes an element of type [T] into a [ZBytes]. + * + * This function supports the following types: + * - [Boolean] + * - [Byte] + * - [Short] + * - [Int] + * - [Long] + * - [Float] + * - [Double] + * - [UByte] + * - [UShort] + * - [UInt] + * - [ULong] + * - [List] + * - [String] + * - [ByteArray] + * - [Map] + * - [Pair] + * - [Triple] + * + * **NOTE** + * + * This serialization utility can be used across the Zenoh ecosystem with Zenoh + * versions based on other supported languages such as Rust, Python, C and C++. + * This works when the types are equivalent (a `Byte` corresponds to an `i8` in Rust, a `Short` to an `i16`, etc). + * + * ### Examples + * + * For a Boolean: + * ``` + * val input: Boolean = true + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For a List: + * ``` + * val input: List = listOf(1, 2, 3, 4, 5) + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize>(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For a nested list: + * ``` + * val input: List> = listOf(listOf(1, 2, 3)) + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize>>(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For a combined list of maps: + * ``` + * val input: List> = listOf(mapOf("a" to 1, "b" to 2)) + * val zbytes = zSerialize(input).getOrThrow() + * val output = zDeserialize>>(zbytes).getOrThrow() + * check(input == output) + * ``` + * + * For additional examples, checkout the [ZBytes examples](https://github.com/eclipse-zenoh/zenoh-kotlin/blob/main/examples/src/main/kotlin/io.zenoh/ZBytes.kt). + * + * @see ZBytes + * @return a [Result] with the serialized [ZBytes]. + */ +inline fun zSerialize(t: T): Result = runCatching { + serializeViaJNI(t, typeOf()) +} From 1ee563b94b07d5badea0df524e8bdc68b5cb2df4 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 12:35:56 -0300 Subject: [PATCH 06/83] Alignment: jni callbacks --- .../io/zenoh/jni/callbacks/JNIGetCallback.kt | 2 +- .../jni/callbacks/JNIQueryableCallback.kt | 17 +++++++--------- .../zenoh/jni/callbacks/JNIScoutCallback.kt | 20 +++++++++++++++++++ 3 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt index b78fc33f..ae978471 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt @@ -17,7 +17,7 @@ package io.zenoh.jni.callbacks internal fun interface JNIGetCallback { fun run( - replierId: String?, + replierId: ByteArray?, success: Boolean, keyExpr: String?, payload: ByteArray, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt index 477d0dd0..31f5885f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt @@ -15,14 +15,11 @@ package io.zenoh.jni.callbacks internal fun interface JNIQueryableCallback { - fun run( - keyExpr: String, - selectorParams: String, - withValue: Boolean, - payload: ByteArray?, - encodingId: Int, - encodingSchema: String?, - attachmentBytes: ByteArray?, - queryPtr: Long - ) + fun run(keyExpr: String, + selectorParams: String, + payload: ByteArray?, + encodingId: Int, + encodingSchema: String?, + attachmentBytes: ByteArray?, + queryPtr: Long) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt new file mode 100644 index 00000000..0a8b20e9 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt @@ -0,0 +1,20 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.jni.callbacks + +internal fun interface JNIScoutCallback { + + fun run(whatAmI: Int, zid: ByteArray, locators: List) +} From 95a13e5f89bff38aaa077ba6b49dc4513895ee64 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 13:52:40 -0300 Subject: [PATCH 07/83] Alignment: config --- .../src/commonMain/kotlin/io/zenoh/Config.kt | 299 ++++++++++++++++-- .../kotlin/io/zenoh/jni/JNIConfig.kt | 101 ++++++ 2 files changed, 381 insertions(+), 19 deletions(-) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt index 2e2964a7..e331d03c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt @@ -14,56 +14,317 @@ package io.zenoh +import io.zenoh.exceptions.ZError +import io.zenoh.jni.JNIConfig import java.io.File import java.nio.file.Path -import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement - /** - * Config class to set the Zenoh configuration to be used through a [Session]. + * # Config + * + * Config class to set the Zenoh configuration to be used through a [io.zenoh.Session]. + * + * The configuration can be specified in two different ways: + * - By providing a file or a path to a file with the configuration + * - By providing a raw string configuration. + * + * Either way, the supported formats are `yaml`, `json` and `json5`. + * + * A default configuration can be loaded using [Config.default]. + * + * ## Examples: + * + * ### Loading default config: + * + * ```kotlin + * val config = Config.default() + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * ### Loading from file + * + * Using [Path]: + * ```kotlin + * val config = Config.fromFile(Path("example/path/config.json5")).getOrThrow() + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * + * or alternatively, using [File] + * ```kotlin + * val config = Config.fromFile(File("example/path/config.json5")).getOrThrow() + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * ### Embedded string configuration + * - Json5 + * ```kotlin + * val json5config = """ + * { + * mode: "peer", + * connect: { + * endpoints: ["tcp/localhost:7450"], + * }, + * scouting: { + * multicast: { + * enabled: false, + * } + * } + * } + * """.trimIndent() + * val config = Config.fromJson5(json5config).getOrThrow() + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * + * - Json + * ```kotlin + * val jsonConfig = """ + * { + * mode: "peer", + * listen: { + * endpoints: ["tcp/localhost:7450"], + * }, + * scouting: { + * multicast: { + * enabled: false, + * } + * } + * } + * """.trimIndent() + * val config = Config.fromJson(jsonConfig).getOrThrow() + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * + * - Yaml + * ```kotlin + * val yamlConfig = """ + * mode: peer + * connect: + * endpoints: + * - tcp/localhost:7450 + * scouting: + * multicast: + * enabled: false + * """.trimIndent() + * val config = Config.fromYaml(yamlConfig).getOrThrow() + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` * - * @property path The path to the configuration file. - * @constructor Create empty Config + * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more + * information on the Zenoh config parameters. */ -class Config private constructor(internal val path: Path? = null, internal val jsonConfig: JsonElement? = null) { +class Config internal constructor(internal val jniConfig: JNIConfig) { companion object { + private const val CONFIG_ENV = "ZENOH_CONFIG" + /** - * Loads the default zenoh configuration. + * Returns the default config. */ fun default(): Config { - return Config() + return JNIConfig.loadDefaultConfig() } /** * Loads the configuration from the [File] specified. * - * @param file The zenoh config file. + * @param file The Zenoh config file. Supported types are: JSON, JSON5 and YAML. + * Note the format is determined after the file extension. + * @return The [Config]. */ - fun from(file: File): Config { - return Config(file.toPath()) + @Throws(ZError::class) + fun fromFile(file: File): Config { + return JNIConfig.loadConfigFile(file) } /** * Loads the configuration from the [Path] specified. * - * @param path The zenoh config file path. + * @param path Path to the Zenoh config file. Supported types are: JSON, JSON5 and YAML. + * Note the format is determined after the file extension. + * @return The [Config]. + */ + @Throws(ZError::class) + fun fromFile(path: Path): Config { + return JNIConfig.loadConfigFile(path) + } + + /** + * Loads the configuration from json-formatted string. + * + * Example: + * ```kotlin + * val config = Config.fromJson( + * config = """ + * { + * "mode": "peer", + * "connect": { + * "endpoints": ["tcp/localhost:7450"] + * }, + * "scouting": { + * "multicast": { + * "enabled": false + * } + * } + * } + * """.trimIndent() + * ).getOrThrow() + * + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * + * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more + * information on the Zenoh config parameters. + * + * @param config Json formatted config. + * @return The [Config]. */ - fun from(path: Path): Config { - return Config(path) + @Throws(ZError::class) + fun fromJson(config: String): Config { + return JNIConfig.loadJsonConfig(config) } /** - * Loads the configuration from the [json] specified. + * Loads the configuration from json5-formatted string. + * + * Example: + * ```kotlin + * val config = Config.fromJson5( + * config = """ + * { + * mode: "peer", + * connect: { + * endpoints: ["tcp/localhost:7450"], + * }, + * scouting: { + * multicast: { + * enabled: false, + * } + * } + * } + * """.trimIndent() + * ).getOrThrow() + * + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * + * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more + * information on the Zenoh config parameters. * - * @param json The zenoh raw zenoh config. + * @param config Json5 formatted config + * @return The [Config]. */ - fun from(json: String): Config { - return Config(jsonConfig = Json.decodeFromString(json)) + @Throws(ZError::class) + fun fromJson5(config: String): Config { + return JNIConfig.loadJson5Config(config) + } + + /** + * Loads the configuration from yaml-formatted string. + * + * Example: + * ```kotlin + * val config = Config.fromYaml( + * config = """ + * mode: peer + * connect: + * endpoints: + * - tcp/localhost:7450 + * scouting: + * multicast: + * enabled: false + * """.trimIndent() + * ).getOrThrow() + * + * Zenoh.open(config).onSuccess { + * // ... + * } + * ``` + * + * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more + * information on the Zenoh config parameters. + * + * @param config Yaml formatted config + * @return The [Config]. + */ + @Throws(ZError::class) + fun fromYaml(config: String): Config { + return JNIConfig.loadYamlConfig(config) + } + + /** + * Loads the configuration from the [jsonElement] specified. + * + * @param jsonElement The zenoh config as a [JsonElement]. + */ + @Throws(ZError::class) + fun fromJsonElement(jsonElement: JsonElement): Config { + return JNIConfig.loadJsonConfig(jsonElement.toString()) + } + + /** + * Loads the configuration from the env variable [CONFIG_ENV]. + * + * @return The config. + */ + @Throws(ZError::class) + fun fromEnv(): Config { + val envValue = System.getenv(CONFIG_ENV) + if (envValue != null) { + return fromFile(File(envValue)) + } else { + throw Exception("Couldn't load env variable: $CONFIG_ENV.") + } } } - constructor(jsonConfig: JsonElement) : this(null, jsonConfig = jsonConfig) + /** + * The json value associated to the [key]. + */ + @Throws(ZError::class) + fun getJson(key: String): String { + return jniConfig.getJson(key) + } + + /** + * Inserts a json5 value associated to the [key] into the Config. + * + * Example: + * ```kotlin + * val config = Config.default() + * + * // ... + * val scouting = """ + * { + * multicast: { + * enabled: true, + * } + * } + * """.trimIndent() + * config.insertJson5("scouting", scouting).getOrThrow() + * ``` + */ + @Throws(ZError::class) + fun insertJson5(key: String, value: String) { + jniConfig.insertJson5(key, value) + } + + protected fun finalize() { + jniConfig.close() + } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt new file mode 100644 index 00000000..ea278988 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt @@ -0,0 +1,101 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.jni + +import io.zenoh.Config +import io.zenoh.ZenohLoad +import io.zenoh.exceptions.ZError +import java.io.File +import java.nio.file.Path + +internal class JNIConfig(internal val ptr: Long) { + + companion object { + + init { + ZenohLoad + } + + fun loadDefaultConfig(): Config { + val cfgPtr = loadDefaultConfigViaJNI() + return Config(JNIConfig(cfgPtr)) + } + + @Throws(ZError::class) + fun loadConfigFile(path: Path): Config { + val cfgPtr = loadConfigFileViaJNI(path.toString()) + return Config(JNIConfig(cfgPtr)) + } + + @Throws(ZError::class) + fun loadConfigFile(file: File): Config = loadConfigFile(file.toPath()) + + @Throws(ZError::class) + fun loadJsonConfig(rawConfig: String): Config { + val cfgPtr = loadJsonConfigViaJNI(rawConfig) + return Config(JNIConfig(cfgPtr)) + } + + @Throws(ZError::class) + fun loadJson5Config(rawConfig: String): Config { + val cfgPtr = loadJsonConfigViaJNI(rawConfig) + return Config(JNIConfig(cfgPtr)) + } + + @Throws(ZError::class) + fun loadYamlConfig(rawConfig: String): Config { + val cfgPtr = loadYamlConfigViaJNI(rawConfig) + return Config(JNIConfig(cfgPtr)) + } + + @Throws(ZError::class) + private external fun loadDefaultConfigViaJNI(): Long + + @Throws(ZError::class) + private external fun loadConfigFileViaJNI(path: String): Long + + @Throws(ZError::class) + private external fun loadJsonConfigViaJNI(rawConfig: String): Long + + @Throws(ZError::class) + private external fun loadYamlConfigViaJNI(rawConfig: String): Long + + @Throws(ZError::class) + private external fun getIdViaJNI(ptr: Long): ByteArray + + @Throws(ZError::class) + private external fun insertJson5ViaJNI(ptr: Long, key: String, value: String): Long + + /** Frees the underlying native config. */ + private external fun freePtrViaJNI(ptr: Long) + + @Throws(ZError::class) + private external fun getJsonViaJNI(ptr: Long, key: String): String + } + + fun close() { + freePtrViaJNI(ptr) + } + + @Throws(ZError::class) + fun getJson(key: String): String { + return getJsonViaJNI(ptr, key) + } + + @Throws(ZError::class) + fun insertJson5(key: String, value: String) { + insertJson5ViaJNI(this.ptr, key, value) + } +} From 7f372b9c5afe9dbb5a697cc918d9106d4e7e9a62 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 14:06:13 -0300 Subject: [PATCH 08/83] Alignment: JNIKeyExpr --- .../kotlin/io/zenoh/jni/JNIKeyExpr.kt | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt index 764c7052..4b7fc8cf 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt @@ -14,22 +14,23 @@ package io.zenoh.jni -import io.zenoh.Zenoh +import io.zenoh.ZenohLoad import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr +import io.zenoh.keyexpr.SetIntersectionLevel internal class JNIKeyExpr(internal val ptr: Long) { companion object { - @Throws(ZError::class) + init { + ZenohLoad + } + fun tryFrom(keyExpr: String): KeyExpr { - Zenoh.load() // It may happen the zenoh library is not yet loaded when creating a key expression. return KeyExpr(tryFromViaJNI(keyExpr)) } - @Throws(ZError::class) fun autocanonize(keyExpr: String): KeyExpr { - Zenoh.load() return KeyExpr(autocanonizeViaJNI(keyExpr)) } @@ -47,17 +48,44 @@ internal class JNIKeyExpr(internal val ptr: Long) { keyExprB.keyExpr ) - @Throws(Exception::class) + fun relationTo(keyExpr: KeyExpr, other: KeyExpr): SetIntersectionLevel { + val intersection = relationToViaJNI( + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + other.jniKeyExpr?.ptr ?: 0, + other.keyExpr + ) + return SetIntersectionLevel.fromInt(intersection) + } + + fun joinViaJNI(keyExpr: KeyExpr, other: String): KeyExpr { + return KeyExpr(joinViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other)) + } + + fun concatViaJNI(keyExpr: KeyExpr, other: String): KeyExpr { + return KeyExpr(concatViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other)) + } + + @Throws(ZError::class) private external fun tryFromViaJNI(keyExpr: String): String - @Throws(Exception::class) + @Throws(ZError::class) private external fun autocanonizeViaJNI(keyExpr: String): String - @Throws(Exception::class) + @Throws(ZError::class) private external fun intersectsViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Boolean - @Throws(Exception::class) + @Throws(ZError::class) private external fun includesViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Boolean + + @Throws(ZError::class) + private external fun relationToViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Int + + @Throws(ZError::class) + private external fun joinViaJNI(ptrA: Long, keyExprA: String, other: String): String + + @Throws(ZError::class) + private external fun concatViaJNI(ptrA: Long, keyExprA: String, other: String): String } fun close() { From 9cb1dcc82da6775e7bf3ef1a1dd8b2603f098980 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 14:21:14 -0300 Subject: [PATCH 09/83] Alignment: JNIPublisher --- .../kotlin/io/zenoh/jni/JNIPublisher.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt index 83e6c2b9..9db2522a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt @@ -15,7 +15,8 @@ package io.zenoh.jni import io.zenoh.exceptions.ZError -import io.zenoh.value.Value +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes /** * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.publication.Publisher]. @@ -27,12 +28,14 @@ internal class JNIPublisher(private val ptr: Long) { /** * Put operation. * - * @param value The [Value] to be put. + * @param payload Payload of the put. + * @param encoding Encoding of the payload. * @param attachment Optional attachment. */ @Throws(ZError::class) - fun put(value: Value, attachment: ByteArray?) { - putViaJNI(value.payload, value.encoding.id.ordinal, value.encoding.schema, attachment, ptr) + fun put(payload: IntoZBytes, encoding: Encoding?, attachment: IntoZBytes?) { + val resolvedEncoding = encoding ?: Encoding.default() + putViaJNI(payload.into().bytes, resolvedEncoding.id, resolvedEncoding.schema, attachment?.into()?.bytes, ptr) } /** @@ -41,8 +44,8 @@ internal class JNIPublisher(private val ptr: Long) { * @param attachment Optional attachment. */ @Throws(ZError::class) - fun delete(attachment: ByteArray?) { - deleteViaJNI(attachment, ptr) + fun delete(attachment: IntoZBytes?) { + deleteViaJNI(attachment?.into()?.bytes, ptr) } /** From 439004044ffc15b3e60928d82a89ee89c167d74e Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 14:22:54 -0300 Subject: [PATCH 10/83] Alignment: JNIQuery --- .../kotlin/io/zenoh/jni/JNIQuery.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt index 013f5a2f..1a0a9090 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt @@ -16,9 +16,10 @@ package io.zenoh.jni import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.QoS +import io.zenoh.bytes.Encoding +import io.zenoh.qos.QoS +import io.zenoh.bytes.IntoZBytes import io.zenoh.sample.Sample -import io.zenoh.value.Value import org.apache.commons.net.ntp.TimeStamp /** @@ -30,19 +31,18 @@ import org.apache.commons.net.ntp.TimeStamp */ internal class JNIQuery(private val ptr: Long) { - @Throws(ZError::class) - fun replySuccess(sample: Sample) { + fun replySuccess(sample: Sample): Result = runCatching { val timestampEnabled = sample.timestamp != null replySuccessViaJNI( ptr, sample.keyExpr.jniKeyExpr?.ptr ?: 0, sample.keyExpr.keyExpr, - sample.value.payload, - sample.value.encoding.id.ordinal, - sample.value.encoding.schema, + sample.payload.bytes, + sample.encoding.id, + sample.encoding.schema, timestampEnabled, if (timestampEnabled) sample.timestamp!!.ntpValue() else 0, - sample.attachment, + sample.attachment?.bytes, sample.qos.express, sample.qos.priority.value, sample.qos.congestionControl.value @@ -50,12 +50,12 @@ internal class JNIQuery(private val ptr: Long) { } @Throws(ZError::class) - fun replyError(errorValue: Value) { - replyErrorViaJNI(ptr, errorValue.payload, errorValue.encoding.id.ordinal, errorValue.encoding.schema) + fun replyError(error: IntoZBytes, encoding: Encoding) { + replyErrorViaJNI(ptr, error.into().bytes, encoding.id, encoding.schema) } @Throws(ZError::class) - fun replyDelete(keyExpr: KeyExpr, timestamp: TimeStamp?, attachment: ByteArray?, qos: QoS) { + fun replyDelete(keyExpr: KeyExpr, timestamp: TimeStamp?, attachment: IntoZBytes?, qos: QoS) { val timestampEnabled = timestamp != null replyDeleteViaJNI( ptr, @@ -63,7 +63,7 @@ internal class JNIQuery(private val ptr: Long) { keyExpr.keyExpr, timestampEnabled, if (timestampEnabled) timestamp!!.ntpValue() else 0, - attachment, + attachment?.into()?.bytes, qos.express, qos.priority.value, qos.congestionControl.value From c9e04161511f7b55b8208b3dd158fc81ee5d3f52 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 14:30:53 -0300 Subject: [PATCH 11/83] Alignment: JNIScout --- .../kotlin/io/zenoh/jni/JNIScout.kt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt new file mode 100644 index 00000000..d6083a4f --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt @@ -0,0 +1,63 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.jni + +import io.zenoh.Config +import io.zenoh.exceptions.ZError +import io.zenoh.handlers.Callback +import io.zenoh.jni.callbacks.JNIScoutCallback +import io.zenoh.config.ZenohId +import io.zenoh.scouting.Hello +import io.zenoh.scouting.Scout +import io.zenoh.config.WhatAmI + +/** + * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.scouting.Scout] + * + * @property ptr: raw pointer to the underlying native scout. + */ +internal class JNIScout(private val ptr: Long) { + + companion object { + @Throws(ZError::class) + fun scout( + whatAmI: Set, + callback: Callback, + config: Config?, + receiver: R + ): Scout { + val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List -> + callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) + } + val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } + val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, config?.jniConfig?.ptr ?: 0) + return Scout(receiver, JNIScout(ptr)) + } + + @Throws(ZError::class) + private external fun scoutViaJNI( + whatAmI: Int, + callback: JNIScoutCallback, + configPtr: Long, + ): Long + + @Throws(ZError::class) + external fun freePtrViaJNI(ptr: Long) + } + + fun close() { + freePtrViaJNI(ptr) + } +} From 5b2194fa59895736ef8be16f27049fba2d1c772e Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 21 Oct 2024 14:40:09 -0300 Subject: [PATCH 12/83] Alignment: JNISession --- .../kotlin/io/zenoh/jni/JNISession.kt | 227 ++++++++++-------- 1 file changed, 132 insertions(+), 95 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index f4529a48..82ce9831 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -16,8 +16,6 @@ package io.zenoh.jni import io.zenoh.* import io.zenoh.bytes.Encoding -import io.zenoh.bytes.Encoding.ID -import io.zenoh.exceptions.ZError import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.callbacks.JNIOnCloseCallback @@ -25,19 +23,25 @@ import io.zenoh.jni.callbacks.JNIGetCallback import io.zenoh.jni.callbacks.JNIQueryableCallback import io.zenoh.jni.callbacks.JNISubscriberCallback import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.* -import io.zenoh.protocol.ZenohID -import io.zenoh.publication.Delete -import io.zenoh.publication.Publisher -import io.zenoh.publication.Put +import io.zenoh.bytes.IntoZBytes +import io.zenoh.config.ZenohId +import io.zenoh.bytes.into +import io.zenoh.Config +import io.zenoh.pubsub.Delete +import io.zenoh.pubsub.Publisher +import io.zenoh.pubsub.Put +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS import io.zenoh.query.* -import io.zenoh.queryable.Query -import io.zenoh.queryable.Queryable +import io.zenoh.query.Query +import io.zenoh.query.Queryable import io.zenoh.sample.Sample -import io.zenoh.selector.Selector -import io.zenoh.subscriber.Reliability -import io.zenoh.subscriber.Subscriber -import io.zenoh.value.Value +import io.zenoh.query.Parameters +import io.zenoh.query.Selector +import io.zenoh.qos.Reliability +import io.zenoh.sample.SampleKind +import io.zenoh.pubsub.Subscriber import org.apache.commons.net.ntp.TimeStamp import java.time.Duration import java.util.concurrent.atomic.AtomicLong @@ -45,16 +49,19 @@ import java.util.concurrent.atomic.AtomicLong /** Adapter class to handle the communication with the Zenoh JNI code for a [Session]. */ internal class JNISession { + companion object { + init { + ZenohLoad + } + } + /* Pointer to the underlying Rust zenoh session. */ private var sessionPtr: AtomicLong = AtomicLong(0) @Throws(ZError::class) fun open(config: Config) { - config.jsonConfig?.let { jsonConfig -> - sessionPtr.set(openSessionWithJsonConfigViaJNI(jsonConfig.toString())) - } ?: run { - sessionPtr.set(openSessionViaJNI(config.path?.toString())) - } + val session = openSessionViaJNI(config.jniConfig.ptr) + sessionPtr.set(session) } @Throws(ZError::class) @@ -63,57 +70,69 @@ internal class JNISession { } @Throws(ZError::class) - fun declarePublisher(keyExpr: KeyExpr, qos: QoS): Publisher { + fun declarePublisher(keyExpr: KeyExpr, qos: QoS, encoding: Encoding, reliability: Reliability): Publisher { val publisherRawPtr = declarePublisherViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), qos.congestionControl.value, qos.priority.value, - qos.express + qos.express, + reliability.ordinal ) return Publisher( keyExpr, qos, + encoding, JNIPublisher(publisherRawPtr), ) } @Throws(ZError::class) fun declareSubscriber( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, reliability: Reliability + keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R ): Subscriber { val subCallback = - JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> + JNISubscriberCallback { keyExpr, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null val sample = Sample( - KeyExpr(keyExpr2, null), - Value(payload, Encoding(ID.fromId(encodingId)!!, encodingSchema)), + KeyExpr(keyExpr, null), + payload.into(), + Encoding(encodingId, schema = encodingSchema), SampleKind.fromInt(kind), timestamp, - QoS(express, congestionControl, priority), - attachmentBytes + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() ) callback.run(sample) } val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, onClose, reliability.ordinal + keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, onClose ) return Subscriber(keyExpr, receiver, JNISubscriber(subscriberRawPtr)) } @Throws(ZError::class) fun declareQueryable( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, complete: Boolean + keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R, complete: Boolean ): Queryable { val queryCallback = - JNIQueryableCallback { keyExprStr: String, selectorParams: String, withValue: Boolean, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> + JNIQueryableCallback { keyExpr: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> val jniQuery = JNIQuery(queryPtr) - val keyExpr2 = KeyExpr(keyExprStr, null) - val selector = Selector(keyExpr2, selectorParams) - val value: Value? = - if (withValue) Value(payload!!, Encoding(ID.fromId(encodingId)!!, encodingSchema)) else null - val query = Query(keyExpr2, selector, value, attachmentBytes, jniQuery) + val keyExpr2 = KeyExpr(keyExpr, null) + val selector = if (selectorParams.isEmpty()) { + Selector(keyExpr2) + } else { + Selector(keyExpr2, Parameters.from(selectorParams).getOrThrow()) + } + val query = Query( + keyExpr2, + selector, + payload?.into(), + payload?.let { Encoding(encodingId, schema = encodingSchema) }, + attachmentBytes?.into(), + jniQuery + ) callback.run(query) } val queryableRawPtr = declareQueryableViaJNI( @@ -127,15 +146,16 @@ internal class JNISession { selector: Selector, callback: Callback, onClose: () -> Unit, - receiver: R?, + receiver: R, timeout: Duration, target: QueryTarget, consolidation: ConsolidationMode, - value: Value?, - attachment: ByteArray? - ): R? { + payload: IntoZBytes?, + encoding: Encoding?, + attachment: IntoZBytes? + ): R { val getCallback = JNIGetCallback { - replierId: String?, + replierId: ByteArray?, success: Boolean, keyExpr: String?, payload: ByteArray, @@ -152,31 +172,25 @@ internal class JNISession { val reply: Reply if (success) { val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - when (SampleKind.fromInt(kind)) { - SampleKind.PUT -> { - val sample = Sample( - KeyExpr(keyExpr!!, null), - Value(payload, Encoding(ID.fromId(encodingId)!!, encodingSchema)), - SampleKind.fromInt(kind), - timestamp, - QoS(express, congestionControl, priority), - attachmentBytes - ) - reply = Reply.Success(replierId?.let { ZenohID(it) }, sample) - } - - SampleKind.DELETE -> { - reply = Reply.Delete( - replierId?.let { ZenohID(it) }, - KeyExpr(keyExpr!!, null), - timestamp, - attachmentBytes, - QoS(express, congestionControl, priority) - ) - } - } + val sample = Sample( + KeyExpr(keyExpr!!, null), + payload.into(), + Encoding(encodingId, schema = encodingSchema), + SampleKind.fromInt(kind), + timestamp, + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() + ) + reply = Reply(replierId?.let { ZenohId(it) }, Result.success(sample)) } else { - reply = Reply.Error(replierId?.let { ZenohID(it) }, Value(payload, Encoding(ID.fromId(encodingId)!!, encodingSchema))) + reply = Reply( + replierId?.let { ZenohId(it) }, Result.failure( + ReplyError( + payload.into(), + Encoding(encodingId, schema = encodingSchema) + ) + ) + ) } callback.run(reply) } @@ -184,18 +198,17 @@ internal class JNISession { getViaJNI( selector.keyExpr.jniKeyExpr?.ptr ?: 0, selector.keyExpr.keyExpr, - selector.parameters, + selector.parameters.toString(), sessionPtr.get(), getCallback, onClose, timeout.toMillis(), target.ordinal, consolidation.ordinal, - attachment, - value != null, - value?.payload, - value?.encoding?.id?.ordinal ?: 0, - value?.encoding?.schema + attachment?.into()?.bytes, + payload?.into()?.bytes, + encoding?.id ?: Encoding.default().id, + encoding?.schema ) return receiver } @@ -214,7 +227,7 @@ internal class JNISession { } ?: throw ZError("Attempting to undeclare a non declared key expression.") } - @Throws(Exception::class) + @Throws(ZError::class) fun performPut( keyExpr: KeyExpr, put: Put, @@ -223,17 +236,18 @@ internal class JNISession { keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - put.value.payload, - put.value.encoding.id.ordinal, - put.value.encoding.schema, + put.payload.bytes, + put.encoding.id, + put.encoding.schema, put.qos.congestionControl.value, put.qos.priority.value, put.qos.express, - put.attachment + put.attachment?.bytes, + put.reliability.ordinal ) } - @Throws(Exception::class) + @Throws(ZError::class) fun performDelete( keyExpr: KeyExpr, delete: Delete, @@ -245,40 +259,62 @@ internal class JNISession { delete.qos.congestionControl.value, delete.qos.priority.value, delete.qos.express, - delete.attachment + delete.attachment?.bytes, + delete.reliability.ordinal ) } - @Throws(Exception::class) - private external fun openSessionViaJNI(configFilePath: String?): Long + @Throws(ZError::class) + fun zid(): ZenohId { + return ZenohId(getZidViaJNI(sessionPtr.get())) + } + + @Throws(ZError::class) + fun peersZid(): List { + return getPeersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } + } - @Throws(Exception::class) - private external fun openSessionWithJsonConfigViaJNI(jsonConfig: String?): Long + @Throws(ZError::class) + fun routersZid(): List { + return getRoutersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } + } - @Throws(Exception::class) + @Throws(ZError::class) + private external fun getZidViaJNI(ptr: Long): ByteArray + + @Throws(ZError::class) + private external fun getPeersZidViaJNI(ptr: Long): List + + @Throws(ZError::class) + private external fun getRoutersZidViaJNI(ptr: Long): List + + @Throws(ZError::class) + private external fun openSessionViaJNI(configPtr: Long): Long + + @Throws(ZError::class) private external fun closeSessionViaJNI(ptr: Long) - @Throws(Exception::class) + @Throws(ZError::class) private external fun declarePublisherViaJNI( keyExprPtr: Long, keyExprString: String, sessionPtr: Long, congestionControl: Int, priority: Int, - express: Boolean + express: Boolean, + reliability: Int ): Long - @Throws(Exception::class) + @Throws(ZError::class) private external fun declareSubscriberViaJNI( keyExprPtr: Long, keyExprString: String, sessionPtr: Long, callback: JNISubscriberCallback, onClose: JNIOnCloseCallback, - reliability: Int ): Long - @Throws(Exception::class) + @Throws(ZError::class) private external fun declareQueryableViaJNI( keyExprPtr: Long, keyExprString: String, @@ -288,17 +324,17 @@ internal class JNISession { complete: Boolean ): Long - @Throws(Exception::class) + @Throws(ZError::class) private external fun declareKeyExprViaJNI(sessionPtr: Long, keyExpr: String): Long - @Throws(Exception::class) + @Throws(ZError::class) private external fun undeclareKeyExprViaJNI(sessionPtr: Long, keyExprPtr: Long) - @Throws(Exception::class) + @Throws(ZError::class) private external fun getViaJNI( keyExprPtr: Long, keyExprString: String, - selectorParams: String, + selectorParams: String?, sessionPtr: Long, callback: JNIGetCallback, onClose: JNIOnCloseCallback, @@ -306,13 +342,12 @@ internal class JNISession { target: Int, consolidation: Int, attachmentBytes: ByteArray?, - withValue: Boolean, payload: ByteArray?, encodingId: Int, encodingSchema: String?, ) - @Throws(Exception::class) + @Throws(ZError::class) private external fun putViaJNI( keyExprPtr: Long, keyExprString: String, @@ -323,10 +358,11 @@ internal class JNISession { congestionControl: Int, priority: Int, express: Boolean, - attachmentBytes: ByteArray? + attachmentBytes: ByteArray?, + reliability: Int ) - @Throws(Exception::class) + @Throws(ZError::class) private external fun deleteViaJNI( keyExprPtr: Long, keyExprString: String, @@ -334,6 +370,7 @@ internal class JNISession { congestionControl: Int, priority: Int, express: Boolean, - attachmentBytes: ByteArray? + attachmentBytes: ByteArray?, + reliability: Int ) } From 5ed9777fa5431239ef5510a301e21c241f235453 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 10:29:27 -0300 Subject: [PATCH 13/83] Alignment JNIZBytes & JNIZenohId --- .../kotlin/io/zenoh/jni/JNIZBytes.kt | 31 +++++++++++++++++++ .../kotlin/io/zenoh/jni/JNIZenohId.kt | 27 ++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt new file mode 100644 index 00000000..8e9e94b2 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt @@ -0,0 +1,31 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.jni + +import io.zenoh.ZenohLoad +import io.zenoh.bytes.ZBytes +import kotlin.reflect.KType + +@PublishedApi +internal object JNIZBytes { + + init { + ZenohLoad + } + + external fun serializeViaJNI(any: Any, kType: KType): ZBytes + + external fun deserializeViaJNI(zBytes: ZBytes, kType: KType): Any +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt new file mode 100644 index 00000000..53ecb5dc --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.jni + +import io.zenoh.ZenohLoad + +internal object JNIZenohId { + + init { + ZenohLoad + } + + external fun toStringViaJNI(bytes: ByteArray): String + +} From aee2546cf42d808bf79b63b3099b7a27c5045332 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 10:38:01 -0300 Subject: [PATCH 14/83] Alignment: KeyExpr & SetIntersectionLevel --- .../kotlin/io/zenoh/SessionDeclaration.kt | 3 -- .../kotlin/io/zenoh/keyexpr/KeyExpr.kt | 45 ++++++++++++++----- .../io/zenoh/keyexpr/SetIntersectionLevel.kt | 31 +++++++++++++ 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt index 1c747e40..db4115a8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt @@ -22,9 +22,6 @@ package io.zenoh */ interface SessionDeclaration { - /** Returns true if the declaration has not been undeclared. */ - fun isValid(): Boolean - /** Undeclare a declaration. No further operations should be performed after calling this function. */ fun undeclare() } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt index d8676bc4..f4727096 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt @@ -16,6 +16,7 @@ package io.zenoh.keyexpr import io.zenoh.Resolvable import io.zenoh.Session +import io.zenoh.SessionDeclaration import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIKeyExpr @@ -60,7 +61,8 @@ import io.zenoh.jni.JNIKeyExpr * @param jniKeyExpr An optional [JNIKeyExpr] instance, present when the key expression was declared through [Session.declareKeyExpr], * it represents the native instance of the key expression. */ -class KeyExpr internal constructor(internal val keyExpr: String, internal var jniKeyExpr: JNIKeyExpr? = null): AutoCloseable { +class KeyExpr internal constructor(internal val keyExpr: String, internal var jniKeyExpr: JNIKeyExpr? = null): AutoCloseable, + SessionDeclaration { companion object { @@ -118,20 +120,30 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn } /** - * Undeclare the key expression if it was previously declared on the specified [session]. - * - * @param session The session from which the key expression was previously declared. - * @return An empty [Resolvable]. + * Returns the relation between 'this' and other from 'this''s point of view (SetIntersectionLevel::Includes + * signifies that self includes other). Note that this is slower than [intersects] and [includes], + * so you should favor these methods for most applications. + */ + fun relationTo(other: KeyExpr): SetIntersectionLevel { + return JNIKeyExpr.relationTo(this, other) + } + + /** + * Joins both sides, inserting a / in between them. + * This should be your preferred method when concatenating path segments. */ - fun undeclare(session: Session): Resolvable { - return session.undeclare(this) + @Throws(ZError::class) + fun join(other: String): KeyExpr { + return JNIKeyExpr.joinViaJNI(this, other) } /** - * Returns true if the [KeyExpr] has still associated a native key expression allowing it to perform operations. + * Performs string concatenation and returns the result as a KeyExpr if possible. + * You should probably prefer [join] as Zenoh may then take advantage of the hierarchical separation it inserts. */ - fun isValid(): Boolean { - return jniKeyExpr != null + @Throws(ZError::class) + fun concat(other: String): KeyExpr { + return JNIKeyExpr.concatViaJNI(this, other) } override fun toString(): String { @@ -139,9 +151,20 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn } /** - * Closes the key expression. Operations performed on this key expression won't be valid anymore after this call. + * Equivalent to [undeclare]. This function is automatically called when using try with resources. + * + * @see undeclare */ override fun close() { + undeclare() + } + + /** + * If the key expression was declared from a [Session], then [undeclare] frees the native key expression associated + * to this instance. The KeyExpr instance is downgraded into a normal KeyExpr, which still allows performing + * operations on it, but without the inner optimizations. + */ + override fun undeclare() { jniKeyExpr?.close() jniKeyExpr = null } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt new file mode 100644 index 00000000..981cc4b1 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt @@ -0,0 +1,31 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.keyexpr + +/** + * The possible relations between two sets. + * + * Note that [EQUALS] implies [INCLUDES], which itself implies [INTERSECTS]. + */ +enum class SetIntersectionLevel(internal val value: Int) { + DISJOINT(0), + INTERSECTS(1), + INCLUDES(2), + EQUALS(3); + + companion object { + internal fun fromInt(value: Int) = SetIntersectionLevel.entries.first { it.value == value } + } +} From 52300e58a53ad10abf96df679e8f4507c3c599fb Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 11:12:31 -0300 Subject: [PATCH 15/83] Alignment: pubsub package --- examples/src/main/java/io/zenoh/ZPub.java | 2 +- examples/src/main/java/io/zenoh/ZPubThr.java | 2 +- examples/src/main/java/io/zenoh/ZSub.java | 2 +- examples/src/main/java/io/zenoh/ZSubThr.java | 2 +- zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt | 9 ++++----- .../kotlin/io/zenoh/{publication => pubsub}/Delete.kt | 2 +- .../kotlin/io/zenoh/{publication => pubsub}/Publisher.kt | 3 +-- .../kotlin/io/zenoh/{publication => pubsub}/Put.kt | 2 +- .../kotlin/io/zenoh/{subscriber => pubsub}/Subscriber.kt | 5 +++-- .../src/commonTest/kotlin/io/zenoh/PublisherTest.kt | 4 ++-- 10 files changed, 16 insertions(+), 17 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{publication => pubsub}/Delete.kt (99%) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{publication => pubsub}/Publisher.kt (98%) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{publication => pubsub}/Put.kt (99%) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{subscriber => pubsub}/Subscriber.kt (98%) diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index 24965fc8..23bd021a 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -16,7 +16,7 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.publication.Publisher; +import io.zenoh.pubsub.Publisher; public class ZPub { public static void main(String[] args) throws ZenohException, InterruptedException { diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index 1d1b42d9..477127c8 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -18,7 +18,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.prelude.CongestionControl; import io.zenoh.prelude.Encoding; -import io.zenoh.publication.Publisher; +import io.zenoh.pubsub.Publisher; import io.zenoh.value.Value; public class ZPubThr { diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index 883139f7..88220e31 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.sample.Sample; -import io.zenoh.subscriber.Subscriber; +import io.zenoh.pubsub.Subscriber; import java.util.Optional; import java.util.concurrent.BlockingQueue; diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index d7afc00a..bb2bd79c 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -16,7 +16,7 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.subscriber.Subscriber; +import io.zenoh.pubsub.Subscriber; import kotlin.Unit; public class ZSubThr { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 3ce09725..eb990e9a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -14,22 +14,21 @@ package io.zenoh -import io.zenoh.exceptions.ZError import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.QoS -import io.zenoh.publication.Delete -import io.zenoh.publication.Publisher -import io.zenoh.publication.Put +import io.zenoh.pubsub.Delete +import io.zenoh.pubsub.Publisher +import io.zenoh.pubsub.Put import io.zenoh.query.* import io.zenoh.queryable.Query import io.zenoh.queryable.Queryable import io.zenoh.sample.Sample import io.zenoh.selector.Selector import io.zenoh.subscriber.Reliability -import io.zenoh.subscriber.Subscriber +import io.zenoh.pubsub.Subscriber import io.zenoh.value.Value import java.time.Duration import java.util.* diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt similarity index 99% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt index c27ebe80..9c7ea39e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Delete.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.publication +package io.zenoh.pubsub import io.zenoh.Resolvable import io.zenoh.Session diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt similarity index 98% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index c6b64e4d..6e037731 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -12,11 +12,10 @@ // ZettaScale Zenoh Team, // -package io.zenoh.publication +package io.zenoh.pubsub import io.zenoh.* import io.zenoh.exceptions.ZError -import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIPublisher import io.zenoh.keyexpr.KeyExpr import io.zenoh.prelude.CongestionControl diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt similarity index 99% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt index b613fb03..49f8d392 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/publication/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.publication +package io.zenoh.pubsub import io.zenoh.Resolvable import io.zenoh.Session diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt similarity index 98% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index cd24ac24..2ca41065 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -12,17 +12,18 @@ // ZettaScale Zenoh Team, // -package io.zenoh.subscriber +package io.zenoh.pubsub import io.zenoh.* import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler -import io.zenoh.subscriber.Subscriber.Builder +import io.zenoh.pubsub.Subscriber.Builder import io.zenoh.jni.JNISubscriber import io.zenoh.keyexpr.KeyExpr import io.zenoh.sample.Sample +import io.zenoh.subscriber.Reliability import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt index ee5786a9..019e1e57 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt @@ -18,9 +18,9 @@ import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr import io.zenoh.prelude.Encoding import io.zenoh.prelude.SampleKind -import io.zenoh.publication.Publisher +import io.zenoh.pubsub.Publisher import io.zenoh.sample.Sample -import io.zenoh.subscriber.Subscriber +import io.zenoh.pubsub.Subscriber import io.zenoh.value.Value import kotlin.test.* From afe37661bae8eb0da875b70f4989f40d9830d21d Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 14:58:46 -0300 Subject: [PATCH 16/83] Alignment: Publisher & qos package --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 4 +- .../kotlin/io/zenoh/jni/JNISession.kt | 4 - .../commonMain/kotlin/io/zenoh/prelude/QoS.kt | 68 --------------- .../kotlin/io/zenoh/pubsub/Delete.kt | 33 +++---- .../kotlin/io/zenoh/pubsub/Publisher.kt | 85 ++++++++----------- .../commonMain/kotlin/io/zenoh/pubsub/Put.kt | 39 ++++----- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 2 +- .../{prelude => qos}/CongestionControl.kt | 2 +- .../io/zenoh/{prelude => qos}/Priority.kt | 3 +- .../src/commonMain/kotlin/io/zenoh/qos/QoS.kt | 35 ++++++++ .../zenoh/{subscriber => qos}/Reliability.kt | 2 +- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 8 +- .../kotlin/io/zenoh/sample/Sample.kt | 3 +- .../zenoh/{prelude => sample}/SampleKind.kt | 2 +- .../{DeleteTest.kt => DeleteBuilderTest.kt} | 4 +- .../src/commonTest/kotlin/io/zenoh/GetTest.kt | 2 +- .../kotlin/io/zenoh/PublisherTest.kt | 2 +- .../zenoh/{PutTest.kt => PutBuilderTest.kt} | 3 +- .../kotlin/io/zenoh/QueryableTest.kt | 8 +- .../kotlin/io/zenoh/SubscriberTest.kt | 4 +- 20 files changed, 124 insertions(+), 189 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/QoS.kt rename zenoh-java/src/commonMain/kotlin/io/zenoh/{prelude => qos}/CongestionControl.kt (97%) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{prelude => qos}/Priority.kt (97%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt rename zenoh-java/src/commonMain/kotlin/io/zenoh/{subscriber => qos}/Reliability.kt (97%) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{prelude => sample}/SampleKind.kt (96%) rename zenoh-java/src/commonTest/kotlin/io/zenoh/{DeleteTest.kt => DeleteBuilderTest.kt} (95%) rename zenoh-java/src/commonTest/kotlin/io/zenoh/{PutTest.kt => PutBuilderTest.kt} (98%) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index eb990e9a..70023228 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -18,7 +18,7 @@ import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.QoS +import io.zenoh.qos.QoS import io.zenoh.pubsub.Delete import io.zenoh.pubsub.Publisher import io.zenoh.pubsub.Put @@ -27,7 +27,7 @@ import io.zenoh.queryable.Query import io.zenoh.queryable.Queryable import io.zenoh.sample.Sample import io.zenoh.selector.Selector -import io.zenoh.subscriber.Reliability +import io.zenoh.qos.Reliability import io.zenoh.pubsub.Subscriber import io.zenoh.value.Value import java.time.Duration diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 82ce9831..8e1e1659 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -34,11 +34,7 @@ import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.query.* -import io.zenoh.query.Query -import io.zenoh.query.Queryable import io.zenoh.sample.Sample -import io.zenoh.query.Parameters -import io.zenoh.query.Selector import io.zenoh.qos.Reliability import io.zenoh.sample.SampleKind import io.zenoh.pubsub.Subscriber diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/QoS.kt deleted file mode 100644 index 1984006a..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/QoS.kt +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.prelude - -/** - * Quality of service settings used to send zenoh message. - * - * @property express If true, the message is not batched in order to reduce the latency. - * @property congestionControl [CongestionControl] policy used for the message. - * @property priority [Priority] policy used for the message. - */ -class QoS internal constructor( - internal val express: Boolean, - internal val congestionControl: CongestionControl, - internal val priority: Priority -) { - - internal constructor(express: Boolean, congestionControl: Int, priority: Int) : this( - express, CongestionControl.fromInt(congestionControl), Priority.fromInt(priority) - ) - - /** - * Returns priority of the message. - */ - fun priority(): Priority = priority - - /** - * Returns congestion control setting of the message. - */ - fun congestionControl(): CongestionControl = congestionControl - - /** - * Returns express flag. If it is true, the message is not batched to reduce the latency. - */ - fun isExpress(): Boolean = express - - companion object { - fun default() = QoS(false, CongestionControl.default(), Priority.default()) - } - - internal class Builder( - private var express: Boolean = false, - private var congestionControl: CongestionControl = CongestionControl.default(), - private var priority: Priority = Priority.default(), - ) { - - fun express(value: Boolean) = apply { this.express = value } - - fun priority(priority: Priority) = apply { this.priority = priority } - - fun congestionControl(congestionControl: CongestionControl) = - apply { this.congestionControl = congestionControl } - - fun build() = QoS(express, congestionControl, priority) - } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt index 9c7ea39e..fb0649c2 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt @@ -16,11 +16,12 @@ package io.zenoh.pubsub import io.zenoh.Resolvable import io.zenoh.Session +import io.zenoh.bytes.IntoZBytes import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.CongestionControl -import io.zenoh.prelude.Priority -import io.zenoh.prelude.QoS +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS import kotlin.Throws /** @@ -43,7 +44,7 @@ import kotlin.Throws * specifying the sample kind to be `DELETE`. */ class Delete private constructor( - val keyExpr: KeyExpr, val qos: QoS, val attachment: ByteArray? + val keyExpr: KeyExpr, val qos: QoS, val attachment: IntoZBytes? ) { companion object { @@ -71,23 +72,17 @@ class Delete private constructor( val keyExpr: KeyExpr, ) : Resolvable { - private var qosBuilder: QoS.Builder = QoS.Builder() - private var attachment: ByteArray? = null + private var attachment: IntoZBytes? = null - /** Change the [CongestionControl] to apply when routing the data. */ - fun congestionControl(congestionControl: CongestionControl) = - apply { this.qosBuilder.congestionControl(congestionControl) } + private var qos: QoS = QoS.default() - /** Change the [Priority] of the written data. */ - fun priority(priority: Priority) = apply { this.qosBuilder.priority(priority) } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(isExpress: Boolean) = apply { this.qosBuilder.express(isExpress) } + fun attachment(attachment: IntoZBytes) { + this.attachment = attachment + } - /** Set an attachment to the put operation. */ - fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } + fun qos(qos: QoS) { + this.qos = qos + } /** * Performs a DELETE operation on the specified [keyExpr]. @@ -97,7 +92,7 @@ class Delete private constructor( */ @Throws(ZError::class) override fun res() { - val delete = Delete(this.keyExpr, qosBuilder.build(), attachment) + val delete = Delete(this.keyExpr, qos, attachment) session.resolveDelete(keyExpr, delete) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 6e037731..297f9734 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -15,13 +15,14 @@ package io.zenoh.pubsub import io.zenoh.* +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIPublisher import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.CongestionControl -import io.zenoh.prelude.Priority -import io.zenoh.prelude.QoS -import io.zenoh.value.Value +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS import kotlin.Throws /** @@ -62,39 +63,29 @@ import kotlin.Throws class Publisher internal constructor( val keyExpr: KeyExpr, private var qos: QoS, + val encoding: Encoding, private var jniPublisher: JNIPublisher?, ) : SessionDeclaration, AutoCloseable { companion object { - private val ZError = ZError("Publisher is not valid.") + private val publisherNotValid = ZError("Publisher is not valid.") } - /** Performs a PUT operation on the specified [keyExpr] with the specified [value]. */ - fun put(value: Value) = Put(jniPublisher, value) + /** Get the congestion control applied when routing the data. */ + fun congestionControl() = qos.congestionControl - /** Performs a PUT operation on the specified [keyExpr] with the specified string [value]. */ - fun put(value: String) = Put(jniPublisher, Value(value)) + /** Get the priority of the written data. */ + fun priority() = qos.priority + + /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ + fun put(payload: IntoZBytes) = PutBuilder(jniPublisher, payload) /** * Performs a DELETE operation on the specified [keyExpr] * * @return A [Resolvable] operation. */ - fun delete() = Delete(jniPublisher) - - /** Get congestion control policy. */ - fun getCongestionControl(): CongestionControl { - return qos.congestionControl() - } - - /** Get priority policy. */ - fun getPriority(): Priority { - return qos.priority() - } - - override fun isValid(): Boolean { - return jniPublisher != null - } + fun delete() = DeleteBuilder(jniPublisher) override fun close() { undeclare() @@ -110,29 +101,31 @@ class Publisher internal constructor( jniPublisher?.close() } - class Put internal constructor( + class PutBuilder internal constructor( private var jniPublisher: JNIPublisher?, - val value: Value, - var attachment: ByteArray? = null - ) : Resolvable { + val payload: IntoZBytes, + val encoding: Encoding? = null, + var attachment: IntoZBytes? = null + ) { - fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } + fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } - override fun res() { - jniPublisher?.put(value, attachment) ?: throw(ZError) + @Throws(ZError::class) + fun res() { + jniPublisher?.put(payload, encoding, attachment) ?: throw(publisherNotValid) } } - class Delete internal constructor( + class DeleteBuilder internal constructor( private var jniPublisher: JNIPublisher?, - var attachment: ByteArray? = null - ) : Resolvable { + var attachment: IntoZBytes? = null + ) { - fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } + fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } @Throws(ZError::class) - override fun res() { - jniPublisher?.delete(attachment) ?: throw(ZError) + fun res() { + jniPublisher?.delete(attachment) ?: throw(publisherNotValid) } } @@ -147,22 +140,14 @@ class Publisher internal constructor( internal val session: Session, internal val keyExpr: KeyExpr, ) { - private var qosBuilder: QoS.Builder = QoS.Builder() + private var qos = QoS.default() - /** Change the [CongestionControl] to apply when routing the data. */ - fun congestionControl(congestionControl: CongestionControl) = - apply { this.qosBuilder.congestionControl(congestionControl) } - - /** Change the [Priority] of the written data. */ - fun priority(priority: Priority) = apply { this.qosBuilder.priority(priority) } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(isExpress: Boolean) = apply { this.qosBuilder.express(isExpress) } + fun qos(qos: QoS) { + this.qos = qos + } fun res(): Publisher { - return session.run { resolvePublisher(keyExpr, qosBuilder.build()) } + return session.run { resolvePublisher(keyExpr, qos) } } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt index 49f8d392..79c9e125 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt @@ -17,9 +17,10 @@ package io.zenoh.pubsub import io.zenoh.Resolvable import io.zenoh.Session import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.* +import io.zenoh.qos.QoS import io.zenoh.value.Value /** @@ -51,9 +52,10 @@ import io.zenoh.value.Value */ class Put private constructor( val keyExpr: KeyExpr, - val value: Value, + val payload: IntoZBytes, + val encoding: Encoding?, val qos: QoS, - val attachment: ByteArray? + val attachment: IntoZBytes? ) { companion object { @@ -66,8 +68,8 @@ class Put private constructor( * @param value The [Value] to put. * @return A [Put] operation [Builder]. */ - internal fun newBuilder(session: Session, keyExpr: KeyExpr, value: Value): Builder { - return Builder(session, keyExpr, value) + internal fun newBuilder(session: Session, keyExpr: KeyExpr, payload: IntoZBytes): Builder { + return Builder(session, keyExpr, payload) } } @@ -82,36 +84,29 @@ class Put private constructor( class Builder internal constructor( private val session: Session, private val keyExpr: KeyExpr, - private var value: Value, + private val payload: IntoZBytes, ): Resolvable { - private var qosBuilder: QoS.Builder = QoS.Builder() - private var attachment: ByteArray? = null + private var attachment: IntoZBytes? = null + private var qos = QoS.default() + private var encoding: Encoding? = null /** Change the [Encoding] of the written data. */ fun encoding(encoding: Encoding) = apply { - this.value = Value(value.payload, encoding) + this.encoding = encoding } - /** Change the [CongestionControl] to apply when routing the data. */ - fun congestionControl(congestionControl: CongestionControl) = - apply { this.qosBuilder.congestionControl(congestionControl) } - - /** Change the [Priority] of the written data. */ - fun priority(priority: Priority) = apply { this.qosBuilder.priority(priority) } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(isExpress: Boolean) = apply { this.qosBuilder.express(isExpress) } + fun qos(qos: QoS) { + this.qos = qos + } /** Set an attachment to the put operation. */ - fun withAttachment(attachment: ByteArray) = apply { this.attachment = attachment } + fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } /** Resolves the put operation, returning a [Result]. */ @Throws(ZError::class) override fun res() { - val put = Put(keyExpr, value, qosBuilder.build(), attachment) + val put = Put(keyExpr, payload, encoding, qos, attachment) session.run { resolvePut(keyExpr, put) } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index 2ca41065..dccc2bcf 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -23,7 +23,7 @@ import io.zenoh.pubsub.Subscriber.Builder import io.zenoh.jni.JNISubscriber import io.zenoh.keyexpr.KeyExpr import io.zenoh.sample.Sample -import io.zenoh.subscriber.Reliability +import io.zenoh.qos.Reliability import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/CongestionControl.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt similarity index 97% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/CongestionControl.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt index 64d981c1..2a38189b 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/CongestionControl.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.prelude +package io.zenoh.qos /** The congestion control to be applied when routing the data. */ enum class CongestionControl (val value: Int) { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/Priority.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt similarity index 97% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/Priority.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt index 6907565d..4797e0e2 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/Priority.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.prelude +package io.zenoh.qos /** * The Priority of Zenoh messages. @@ -37,4 +37,3 @@ enum class Priority(val value: Int) { fun default() = DATA } } - diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt new file mode 100644 index 00000000..db6b6024 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt @@ -0,0 +1,35 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.qos + +/** + * Quality of service settings used to send zenoh message. + * + * @property congestionControl [CongestionControl] policy used for the message. + * @property priority [Priority] policy used for the message. + * @property express If true, the message is not batched in order to reduce the latency. + */ +data class QoS ( + val congestionControl: CongestionControl = CongestionControl.DROP, + val priority: Priority = Priority.DATA, + val express: Boolean = false +) { + + companion object { + private val defaultQoS = QoS() + + fun default() = defaultQoS + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Reliability.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt similarity index 97% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Reliability.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt index d675758e..d574f27c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/subscriber/Reliability.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.subscriber +package io.zenoh.qos /** * The reliability policy. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index 47f646e3..df044335 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -18,12 +18,12 @@ import io.zenoh.Resolvable import io.zenoh.ZenohType import io.zenoh.exceptions.ZError import io.zenoh.sample.Sample -import io.zenoh.prelude.SampleKind +import io.zenoh.sample.SampleKind import io.zenoh.value.Value import io.zenoh.keyexpr.KeyExpr -import io.zenoh.prelude.CongestionControl -import io.zenoh.prelude.Priority -import io.zenoh.prelude.QoS +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS import io.zenoh.protocol.ZenohID import io.zenoh.queryable.Query import org.apache.commons.net.ntp.TimeStamp diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt index e9420678..1427167a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt @@ -15,8 +15,7 @@ package io.zenoh.sample import io.zenoh.ZenohType -import io.zenoh.prelude.SampleKind -import io.zenoh.prelude.QoS +import io.zenoh.qos.QoS import io.zenoh.keyexpr.KeyExpr import io.zenoh.value.Value import org.apache.commons.net.ntp.TimeStamp diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/SampleKind.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt similarity index 96% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/SampleKind.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt index 6e057c50..cea02a02 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/prelude/SampleKind.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.prelude +package io.zenoh.sample /** The kind of sample. */ enum class SampleKind { diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt similarity index 95% rename from zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteTest.kt rename to zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt index 083e210a..23da1f33 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt @@ -15,13 +15,13 @@ package io.zenoh import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.SampleKind +import io.zenoh.sample.SampleKind import io.zenoh.sample.Sample import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull -class DeleteTest { +class DeleteBuilderTest { @Test fun delete_isProperlyReceivedBySubscriber() { diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt index 89d645b0..e4d5d813 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt @@ -17,7 +17,7 @@ package io.zenoh import io.zenoh.handlers.Handler import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.SampleKind +import io.zenoh.sample.SampleKind import io.zenoh.query.Reply import io.zenoh.queryable.Queryable import io.zenoh.selector.Selector diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt index 019e1e57..f3ff99da 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt @@ -17,7 +17,7 @@ package io.zenoh import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr import io.zenoh.prelude.Encoding -import io.zenoh.prelude.SampleKind +import io.zenoh.sample.SampleKind import io.zenoh.pubsub.Publisher import io.zenoh.sample.Sample import io.zenoh.pubsub.Subscriber diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/PutTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt similarity index 98% rename from zenoh-java/src/commonTest/kotlin/io/zenoh/PutTest.kt rename to zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt index 2c34d2e9..f1e4f335 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/PutTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt @@ -22,7 +22,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull -class PutTest { +class PutBuilderTest { companion object { const val TEST_KEY_EXP = "example/testing/keyexpr" @@ -44,4 +44,3 @@ class PutTest { assertEquals(value, receivedSample!!.value) } } - diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt index f4f724a3..306ea499 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt @@ -17,10 +17,10 @@ package io.zenoh import io.zenoh.handlers.Handler import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.CongestionControl -import io.zenoh.prelude.Priority -import io.zenoh.prelude.QoS -import io.zenoh.prelude.SampleKind +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS +import io.zenoh.sample.SampleKind import io.zenoh.query.Reply import io.zenoh.queryable.Query import io.zenoh.sample.Sample diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt index 051faaab..69bc6ca9 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt @@ -17,9 +17,9 @@ package io.zenoh import io.zenoh.handlers.Handler import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.CongestionControl +import io.zenoh.qos.CongestionControl import io.zenoh.prelude.Encoding -import io.zenoh.prelude.Priority +import io.zenoh.qos.Priority import io.zenoh.sample.Sample import io.zenoh.value.Value import java.util.* From c68cef3b578b000ceaaf77b8c87d2a09e57ff9d4 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 15:49:20 -0300 Subject: [PATCH 17/83] Alignment: query package - wip --- examples/src/main/java/io/zenoh/ZGet.java | 2 +- examples/src/main/java/io/zenoh/ZPubThr.java | 2 +- examples/src/main/java/io/zenoh/ZPut.java | 5 +- .../src/main/java/io/zenoh/ZQueryable.java | 5 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 6 +- .../kotlin/io/zenoh/qos/CongestionControl.kt | 2 - .../kotlin/io/zenoh/qos/Priority.kt | 2 - .../io/zenoh/query/ConsolidationMode.kt | 4 - .../commonMain/kotlin/io/zenoh/query/Get.kt | 1 - .../zenoh/{selector => query}/IntoSelector.kt | 2 +- .../kotlin/io/zenoh/query/Parameters.kt | 145 ++++++++++++++++++ .../io/zenoh/{queryable => query}/Query.kt | 4 +- .../zenoh/{queryable => query}/Queryable.kt | 2 +- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 1 - .../kotlin/io/zenoh/query/ReplyError.kt | 51 ++++++ .../io/zenoh/{selector => query}/Selector.kt | 2 +- .../src/commonTest/kotlin/io/zenoh/GetTest.kt | 4 +- .../kotlin/io/zenoh/QueryableTest.kt | 2 +- .../kotlin/io/zenoh/SelectorTest.kt | 4 +- 19 files changed, 214 insertions(+), 32 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{selector => query}/IntoSelector.kt (97%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt rename zenoh-java/src/commonMain/kotlin/io/zenoh/{queryable => query}/Query.kt (97%) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{queryable => query}/Queryable.kt (99%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt rename zenoh-java/src/commonMain/kotlin/io/zenoh/{selector => query}/Selector.kt (98%) diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index a8dbb262..368b75da 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -16,7 +16,7 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.query.Reply; -import io.zenoh.selector.Selector; +import io.zenoh.query.Selector; import java.util.Optional; import java.util.concurrent.BlockingQueue; diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index 477127c8..177cb35b 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -16,7 +16,7 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.prelude.CongestionControl; +import io.zenoh.qos.CongestionControl; import io.zenoh.prelude.Encoding; import io.zenoh.pubsub.Publisher; import io.zenoh.value.Value; diff --git a/examples/src/main/java/io/zenoh/ZPut.java b/examples/src/main/java/io/zenoh/ZPut.java index 60317b81..3d0caec5 100644 --- a/examples/src/main/java/io/zenoh/ZPut.java +++ b/examples/src/main/java/io/zenoh/ZPut.java @@ -16,9 +16,8 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.prelude.SampleKind; -import io.zenoh.prelude.CongestionControl; -import io.zenoh.prelude.Priority; +import io.zenoh.qos.CongestionControl; +import io.zenoh.qos.Priority; public class ZPut { public static void main(String[] args) throws ZenohException { diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index c5a9c872..d80b916b 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -16,9 +16,8 @@ import io.zenoh.exceptions.ZenohException; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.prelude.SampleKind; -import io.zenoh.queryable.Query; -import io.zenoh.queryable.Queryable; +import io.zenoh.query.Query; +import io.zenoh.query.Queryable; import org.apache.commons.net.ntp.TimeStamp; import java.util.Optional; diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 70023228..d110a0f5 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -23,10 +23,10 @@ import io.zenoh.pubsub.Delete import io.zenoh.pubsub.Publisher import io.zenoh.pubsub.Put import io.zenoh.query.* -import io.zenoh.queryable.Query -import io.zenoh.queryable.Queryable +import io.zenoh.query.Query +import io.zenoh.query.Queryable import io.zenoh.sample.Sample -import io.zenoh.selector.Selector +import io.zenoh.query.Selector import io.zenoh.qos.Reliability import io.zenoh.pubsub.Subscriber import io.zenoh.value.Value diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt index 2a38189b..82b3463a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt @@ -30,7 +30,5 @@ enum class CongestionControl (val value: Int) { companion object { fun fromInt(value: Int) = entries.first { it.value == value } - - fun default() = DROP } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt index 4797e0e2..0e27780e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt @@ -33,7 +33,5 @@ enum class Priority(val value: Int) { companion object { fun fromInt(value: Int) = entries.first { it.value == value } - - fun default() = DATA } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt index a95fa0d3..f4c1b29c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt @@ -35,8 +35,4 @@ enum class ConsolidationMode { /** Holds back samples to only send the set of samples that had the highest timestamp for their key. */ LATEST; - - companion object { - fun default() = AUTO - } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index 04bdace1..461a33e7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -19,7 +19,6 @@ import io.zenoh.Session import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler -import io.zenoh.selector.Selector import io.zenoh.value.Value import java.time.Duration import java.util.* diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt similarity index 97% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt index 8ad604e9..a7ecd360 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/IntoSelector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.selector +package io.zenoh.query import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt new file mode 100644 index 00000000..85d61e68 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt @@ -0,0 +1,145 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.query + +import java.net.URLDecoder + +/** + * Parameters of the [Selector]. + * + * When in string form, the `parameters` should be encoded like the query section of a URL: + * - parameters are separated by `;`, + * - the parameter name and value are separated by the first `=`, + * - in the absence of `=`, the parameter value is considered to be the empty string, + * - both name and value should use percent-encoding to escape characters, + * - defining a value for the same parameter name twice is considered undefined behavior and an + * error result is returned. + * + * @see Selector + */ +data class Parameters internal constructor(private val params: MutableMap) : IntoParameters { + + companion object { + + private const val LIST_SEPARATOR = ";" + private const val FIELD_SEPARATOR = "=" + private const val VALUE_SEPARATOR = "|" + + /** + * Creates an empty Parameters. + */ + fun empty() = Parameters(mutableMapOf()) + + /** + * Creates a [Parameters] instance from the provided map. + */ + fun from(params: Map): Parameters = Parameters(params.toMutableMap()) + + /** + * Attempts to create a [Parameters] from a string. + * + * When in string form, the `parameters` should be encoded like the query section of a URL: + * - parameters are separated by `;`, + * - the parameter name and value are separated by the first `=`, + * - in the absence of `=`, the parameter value is considered to be the empty string, + * - both name and value should use percent-encoding to escape characters, + * - defining a value for the same parameter name twice is considered undefined behavior and an + * error result is returned. + */ + fun from(params: String): Parameters { + if (params.isBlank()) { + return Parameters(mutableMapOf()) + } + return params.split(LIST_SEPARATOR).fold(mutableMapOf()) { parametersMap, parameter -> + val (key, value) = parameter.split(FIELD_SEPARATOR).let { it[0] to it.getOrNull(1) } + require(!parametersMap.containsKey(key)) { "Duplicated parameter `$key` detected." } + parametersMap[key] = value?.let { URLDecoder.decode(it, Charsets.UTF_8.name()) } ?: "" + parametersMap + }.let { Parameters(it) } + } + } + + override fun toString(): String = + params.entries.joinToString(LIST_SEPARATOR) { "${it.key}$FIELD_SEPARATOR${it.value}" } + + override fun into(): Parameters = this + + /** + * Returns empty if no parameters were provided. + */ + fun isEmpty(): Boolean = params.isEmpty() + + /** + * Returns true if the [key] is contained. + */ + fun containsKey(key: String): Boolean = params.containsKey(key) + + /** + * Returns the value of the [key] if present. + */ + fun get(key: String): String? = params[key] + + /** + * Returns the value of the [key] if present, or if not, the [default] value provided. + */ + fun getOrDefault(key: String, default: String): String = params.getOrDefault(key, default) + + /** + * Returns the values of the [key] if present. + * + * Example: + * ```kotlin + * val parameters = Parameters.from("a=1;b=2;c=1|2|3").getOrThrow() + * assertEquals(listOf("1", "2", "3"), parameters.values("c")) + * ``` + */ + fun values(key: String): List? = params[key]?.split(VALUE_SEPARATOR) + + /** + * Inserts the key-value pair into the parameters, returning the old value + * in case of it being already present. + */ + fun insert(key: String, value: String): String? = params.put(key, value) + + /** + * Removes the [key] parameter, returning its value. + */ + fun remove(key: String): String? = params.remove(key) + + /** + * Extends the parameters with the [parameters] provided, overwriting + * any conflicting params. + */ + fun extend(parameters: IntoParameters) { + params.putAll(parameters.into().params) + } + + /** + * Extends the parameters with the [parameters] provided, overwriting + * any conflicting params. + */ + fun extend(parameters: Map) { + params.putAll(parameters) + } + + /** + * Returns a map with the key value pairs of the parameters. + */ + fun toMap(): Map = params +} + +interface IntoParameters { + fun into(): Parameters +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt similarity index 97% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 7001a2ab..31b8089d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -12,16 +12,14 @@ // ZettaScale Zenoh Team, // -package io.zenoh.queryable +package io.zenoh.query import io.zenoh.Resolvable import io.zenoh.ZenohType -import io.zenoh.selector.Selector import io.zenoh.value.Value import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIQuery import io.zenoh.keyexpr.KeyExpr -import io.zenoh.query.Reply /** * Represents a Zenoh Query in Kotlin. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt similarity index 99% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index 4baaf117..47d8ba27 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/queryable/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.queryable +package io.zenoh.query import io.zenoh.* import io.zenoh.exceptions.ZError diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index df044335..898b867d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -25,7 +25,6 @@ import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.protocol.ZenohID -import io.zenoh.queryable.Query import org.apache.commons.net.ntp.TimeStamp /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt new file mode 100644 index 00000000..609f33f4 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt @@ -0,0 +1,51 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.query + +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.ZBytes + +/** + * Reply error class. + * + * When receiving an error reply while performing a get operation, this is the error type returned: + * ```kotlin + * session.get(selector, callback = { reply -> + * reply.result.onSuccess { sample -> + * // ... + * }.onFailure { error -> + * error as ReplyError + * println("Received (ERROR: '${error.payload}' with encoding '${error.encoding}'.)") + * // ... + * } + * }) + * ``` + * + * This class is useful in case you need to apply different logic based on the encoding of the error or + * need to deserialize the [payload] value into something else other than a string. + * + * Otherwise, the error payload can be obtained as a string under the [Throwable.message] parameter: + * ```kotlin + * session.get(selector, callback = { reply -> + * reply.result.onSuccess { sample -> + * // ... + * }.onFailure { error -> + * println("Received (ERROR: '${error.message}')") + * // ... + * } + * }) + * ``` + */ +data class ReplyError(val payload: ZBytes?, val encoding: Encoding?) : Throwable(message = payload.toString()) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt similarity index 98% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt index 6d06f092..1b609344 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/selector/Selector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh.selector +package io.zenoh.query import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt index e4d5d813..f2ebdbf5 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt @@ -19,8 +19,8 @@ import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.intoKeyExpr import io.zenoh.sample.SampleKind import io.zenoh.query.Reply -import io.zenoh.queryable.Queryable -import io.zenoh.selector.Selector +import io.zenoh.query.Queryable +import io.zenoh.query.Selector import io.zenoh.value.Value import org.apache.commons.net.ntp.TimeStamp import java.time.Duration diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt index 306ea499..fb561003 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt @@ -22,7 +22,7 @@ import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.sample.SampleKind import io.zenoh.query.Reply -import io.zenoh.queryable.Query +import io.zenoh.query.Query import io.zenoh.sample.Sample import io.zenoh.value.Value import org.apache.commons.net.ntp.TimeStamp diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt index eab167fd..b0102e70 100644 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt +++ b/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt @@ -1,8 +1,8 @@ package io.zenoh import io.zenoh.exceptions.ZError -import io.zenoh.selector.Selector -import io.zenoh.selector.intoSelector +import io.zenoh.query.Selector +import io.zenoh.query.intoSelector import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith From a643bca58719aa71c2968e907461443ce88353fa Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 16:19:53 -0300 Subject: [PATCH 18/83] Alignment: adding scouting package --- .../kotlin/io/zenoh/scouting/Hello.kt | 29 ++++++++++ .../kotlin/io/zenoh/scouting/Scout.kt | 58 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Hello.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Hello.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Hello.kt new file mode 100644 index 00000000..ec9ccb82 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Hello.kt @@ -0,0 +1,29 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.scouting + +import io.zenoh.ZenohType +import io.zenoh.config.WhatAmI +import io.zenoh.config.ZenohId + +/** + * Hello message received while scouting. + * + * @property whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. + * @property zid [ZenohId] of the node sending the hello message. + * @property locators The locators of this hello message. + * @see Scout + */ +data class Hello(val whatAmI: WhatAmI, val zid: ZenohId, val locators: List): ZenohType diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt new file mode 100644 index 00000000..7c9f98b2 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt @@ -0,0 +1,58 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.scouting + +import io.zenoh.jni.JNIScout + +/** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task. + * + * To launch a scout, use [io.zenoh.Zenoh.scout]: + * ```kotlin + * Zenoh.scout(callback = { hello -> + * println(hello) + * }).getOrThrow() + * ``` + * + * @param R The receiver type. + * @param receiver Receiver to handle incoming hello messages. + */ +class Scout internal constructor( + val receiver: R, + private var jniScout: JNIScout? +) : AutoCloseable { + + /** + * Stops the scouting. + */ + fun stop() { + jniScout?.close() + jniScout = null + } + + /** + * Equivalent to [stop]. + */ + override fun close() { + stop() + } + + protected fun finalize() { + stop() + } +} From 1d2121c120f3e342b96160e37ae54130486f452e Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 22 Oct 2024 16:20:22 -0300 Subject: [PATCH 19/83] Alignment: removing Value --- .../commonMain/kotlin/io/zenoh/value/Value.kt | 66 ------------------- 1 file changed, 66 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt deleted file mode 100644 index 9a68eb0d..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/value/Value.kt +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.value - -import io.zenoh.bytes.Encoding - -/** - * A Zenoh value. - * - * A Value is a pair of a binary payload, and a mime-type-like encoding string. - * - * @property payload The payload of this Value. - * @property encoding An encoding description indicating how the associated payload is encoded. - */ -class Value(val payload: ByteArray, val encoding: Encoding) { - - /** - * Constructs a value with the provided message, using [Encoding.ID.TEXT_PLAIN] for encoding. - */ - constructor(message: String): this(message.toByteArray(), Encoding(Encoding.ID.TEXT_PLAIN)) - - /** - * Constructs a value with the provided message and encoding. - */ - constructor(message: String, encoding: Encoding): this(message.toByteArray(), encoding) - - companion object { - - /** Return an empty value. */ - fun empty(): Value { - return Value(ByteArray(0), Encoding(Encoding.ID.ZENOH_BYTES)) - } - } - - override fun toString(): String { - return payload.decodeToString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Value - - if (!payload.contentEquals(other.payload)) return false - return encoding == other.encoding - } - - override fun hashCode(): Int { - var result = payload.contentHashCode() - result = 31 * result + encoding.hashCode() - return result - } -} From 377661a05d28e1d3b1119d8972097ec7aeb59c33 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 23 Oct 2024 11:24:46 -0300 Subject: [PATCH 20/83] Alignment: logger --- .../src/commonMain/kotlin/io/zenoh/Logger.kt | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt index db25cf2f..540e004c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt @@ -14,14 +14,26 @@ package io.zenoh +import io.zenoh.exceptions.ZError + /** Logger class to redirect the Rust logs from Zenoh to the kotlin environment. */ -class Logger { +internal class Logger { companion object { + + internal const val LOG_ENV: String = "RUST_LOG" + + fun start(filter: String) = runCatching { + startLogsViaJNI(filter) + } + /** * Redirects the rust logs either to logcat for Android systems or to the standard output (for non-android - * systems). @param logLevel must be either "info", "debug", "warn", "trace" or "error". + * systems). + * + * See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format. */ - external fun start(logLevel: String) + @Throws(ZError::class) + private external fun startLogsViaJNI(filter: String) } -} \ No newline at end of file +} From 5d3705cb3d5fb28e466039d34c0a9c27cff6c39a Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 23 Oct 2024 11:25:28 -0300 Subject: [PATCH 21/83] Alignmment: Zenoh.kt - wip --- .../src/androidMain/kotlin/io.zenoh/Zenoh.kt | 18 +- .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 136 ++++++++++- .../src/jvmMain/kotlin/io/zenoh/Zenoh.kt | 225 ++++++++---------- 3 files changed, 238 insertions(+), 141 deletions(-) diff --git a/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt b/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt index c8d9ad08..74d42e51 100644 --- a/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt +++ b/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt @@ -18,24 +18,10 @@ package io.zenoh * Static singleton class to load the Zenoh native library once and only once, as well as the logger in function of the * log level configuration. */ -internal actual class Zenoh private actual constructor() { - - actual companion object { - private const val ZENOH_LIB_NAME = "zenoh_jni" - private const val ZENOH_LOGS_PROPERTY = "zenoh.logger" - - private var instance: Zenoh? = null - - actual fun load() { - instance ?: Zenoh().also { instance = it } - } - } +internal actual object ZenohLoad { + private const val ZENOH_LIB_NAME = "zenoh_jni" init { System.loadLibrary(ZENOH_LIB_NAME) - val logLevel = System.getProperty(ZENOH_LOGS_PROPERTY) - if (logLevel != null) { - Logger.start(logLevel) - } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index ee156130..791bc22d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -14,12 +14,138 @@ package io.zenoh +import io.zenoh.Logger.Companion.LOG_ENV +import io.zenoh.handlers.Callback +import io.zenoh.handlers.Handler +import io.zenoh.jni.JNIScout +import io.zenoh.scouting.Hello +import io.zenoh.scouting.Scout +import io.zenoh.config.WhatAmI +import io.zenoh.config.WhatAmI.* +import io.zenoh.exceptions.ZError + +object Zenoh { + + /** + * Open a [Session] with the provided [Config]. + * + * @param config The configuration for the session. + * @return The [Session] on success. + */ + @Throws(ZError::class) + fun open(config: Config): Session { + return Session.open(config) + } + + /** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + * + * @param callback [Callback] to be run when receiving a [Hello] message. + * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. + * @param config Optional [Config] for the scout. + * @return A result with the [Scout] object. + */ + @Throws(ZError::class) + fun scout( + callback: Callback, + whatAmI: Set = setOf(Peer, Router), + config: Config? = null + ): Scout { + ZenohLoad + return JNIScout.scout(whatAmI = whatAmI, callback = callback, receiver = Unit, config = config) + } + + /** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + * + * @param handler [Handler] to handle incoming [Hello] messages. + * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. + * @param config Optional [Config] for the scout. + * @return A result with the [Scout] object. + */ + @Throws(ZError::class) + fun scout( + handler: Handler, + whatAmI: Set = setOf(Peer, Router), + config: Config? = null + ): Scout { + ZenohLoad + return JNIScout.scout( + whatAmI = whatAmI, + callback = { hello -> handler.handle(hello) }, + receiver = handler.receiver(), + config = config + ) + } + +// /** +// * Scout for routers and/or peers. +// * +// * Scout spawns a task that periodically sends scout messages and waits for Hello replies. +// * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. +// * +// * @param channel [Channel] upon which the incoming [Hello] messages will be piped. +// * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. +// * @param config Optional [Config] for the scout. +// * @return A result with the [Scout] object. +// */ +// fun scout( +// channel: Channel, +// whatAmI: Set = setOf(Peer, Router), +// config: Config? = null +// ): Result>> { +// ZenohLoad +// val handler = ChannelHandler(channel) +// return JNIScout.scout( +// whatAmI = whatAmI, +// callback = { hello -> handler.handle(hello) }, +// receiver = handler.receiver(), +// config = config +// ) +// } + + /** + * Initializes the zenoh runtime logger, using rust environment settings. + * E.g.: `RUST_LOG=info` will enable logging at info level. Similarly, you can set the variable to `error` or `debug`. + * + * Note that if the environment variable is not set, then logging will not be enabled. + * See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format. + * + * @see Logger + */ + fun tryInitLogFromEnv() { + val logEnv = System.getenv(LOG_ENV) + if (logEnv != null) { + ZenohLoad + Logger.start(logEnv) + } + } + + /** + * Initializes the zenoh runtime logger, using rust environment settings or the provided fallback level. + * E.g.: `RUST_LOG=info` will enable logging at info level. Similarly, you can set the variable to `error` or `debug`. + * + * Note that if the environment variable is not set, then [fallbackFilter] will be used instead. + * See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format. + * + * @param fallbackFilter: The fallback filter if the `RUST_LOG` environment variable is not set. + * @see Logger + */ + fun initLogFromEnvOr(fallbackFilter: String): Result = runCatching { + ZenohLoad + val logLevelProp = System.getenv(LOG_ENV) + logLevelProp?.let { Logger.start(it) } ?: Logger.start(fallbackFilter) + } +} + /** * Static singleton class to load the Zenoh native library once and only once, as well as the logger in function of the * log level configuration. */ -internal expect class Zenoh private constructor() { - companion object { - fun load() - } -} +internal expect object ZenohLoad diff --git a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt index d6b7dd9b..11ae638c 100644 --- a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt @@ -15,155 +15,140 @@ package io.zenoh import java.io.File +import java.io.FileInputStream import java.io.FileOutputStream import java.io.InputStream -import java.io.FileInputStream import java.util.zip.ZipInputStream /** * Static singleton class to load the Zenoh native library once and only once, as well as the logger in function of the * log level configuration. */ -internal actual class Zenoh private actual constructor() { - - actual companion object { - private const val ZENOH_LIB_NAME = "zenoh_jni" - private const val ZENOH_LOGS_PROPERTY = "zenoh.logger" - - private var instance: Zenoh? = null +internal actual object ZenohLoad { + private const val ZENOH_LIB_NAME = "zenoh_jni" - actual fun load() { - instance ?: Zenoh().also { instance = it } + init { + // Try first to load the local native library for cases in which the module was built locally, + // otherwise try to load from the JAR. + if (tryLoadingLocalLibrary().isFailure) { + val target = determineTarget().getOrThrow() + tryLoadingLibraryFromJarPackage(target).getOrThrow() } + } - /** - * Determine target - * - * Determines the [Target] corresponding to the machine on top of which the native code will run. - * - * @return A result with the target. - */ - private fun determineTarget(): Result = runCatching { - val osName = System.getProperty("os.name").lowercase() - val osArch = System.getProperty("os.arch") - - val target = when { - osName.contains("win") -> when { - osArch.contains("x86_64") || osArch.contains("amd64") -> Target.WINDOWS_X86_64_MSVC - else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") - } - - osName.contains("mac") -> when { - osArch.contains("x86_64") || osArch.contains("amd64") -> Target.APPLE_X86_64 - osArch.contains("aarch64") -> Target.APPLE_AARCH64 - else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") - } - - osName.contains("nix") || osName.contains("nux") || osName.contains("aix") -> when { - osArch.contains("x86_64") || osArch.contains("amd64") -> Target.LINUX_X86_64 - osArch.contains("aarch64") -> Target.LINUX_AARCH64 - else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") - } - - else -> throw UnsupportedOperationException("Unsupported platform: $osName") + /** + * Determine target + * + * Determines the [Target] corresponding to the machine on top of which the native code will run. + * + * @return A result with the target. + */ + private fun determineTarget(): Result = runCatching { + val osName = System.getProperty("os.name").lowercase() + val osArch = System.getProperty("os.arch") + + val target = when { + osName.contains("win") -> when { + osArch.contains("x86_64") || osArch.contains("amd64") -> Target.WINDOWS_X86_64_MSVC + else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") } - return Result.success(target) - } - /** - * Unzip library. - * - * The Zenoh libraries are stored within the JAR as compressed ZIP files. - * The location of the zipped files is expected to be under target/target.zip. - * It is expected that the zip file only contains the compressed library. - * - * The uncompressed library will be stored temporarily and deleted on exit. - * - * @param compressedLib Input stream pointing to the compressed library. - * @return A result with the uncompressed library file. - */ - private fun unzipLibrary(compressedLib: InputStream): Result = runCatching { - val zipInputStream = ZipInputStream(compressedLib) - val buffer = ByteArray(1024) - val zipEntry = zipInputStream.nextEntry - - val library = File.createTempFile(zipEntry!!.name, ".tmp") - library.deleteOnExit() - - val parent = library.parentFile - if (!parent.exists()) { - parent.mkdirs() + osName.contains("mac") -> when { + osArch.contains("x86_64") || osArch.contains("amd64") -> Target.APPLE_X86_64 + osArch.contains("aarch64") -> Target.APPLE_AARCH64 + else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") } - val fileOutputStream = FileOutputStream(library) - var len: Int - while (zipInputStream.read(buffer).also { len = it } > 0) { - fileOutputStream.write(buffer, 0, len) + osName.contains("nix") || osName.contains("nux") || osName.contains("aix") -> when { + osArch.contains("x86_64") || osArch.contains("amd64") -> Target.LINUX_X86_64 + osArch.contains("aarch64") -> Target.LINUX_AARCH64 + else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") } - fileOutputStream.close() - zipInputStream.closeEntry() - zipInputStream.close() - return Result.success(library) + else -> throw UnsupportedOperationException("Unsupported platform: $osName") } + return Result.success(target) + } - private fun loadLibraryAsInputStream(target: Target): Result = runCatching { - val libUrl = ClassLoader.getSystemClassLoader().getResourceAsStream("$target/$target.zip")!! - val uncompressedLibFile = unzipLibrary(libUrl) - return Result.success(FileInputStream(uncompressedLibFile.getOrThrow())) + /** + * Unzip library. + * + * The Zenoh libraries are stored within the JAR as compressed ZIP files. + * The location of the zipped files is expected to be under target/target.zip. + * It is expected that the zip file only contains the compressed library. + * + * The uncompressed library will be stored temporarily and deleted on exit. + * + * @param compressedLib Input stream pointing to the compressed library. + * @return A result with the uncompressed library file. + */ + private fun unzipLibrary(compressedLib: InputStream): Result = runCatching { + val zipInputStream = ZipInputStream(compressedLib) + val buffer = ByteArray(1024) + val zipEntry = zipInputStream.nextEntry + + val library = File.createTempFile(zipEntry!!.name, ".tmp") + library.deleteOnExit() + + val parent = library.parentFile + if (!parent.exists()) { + parent.mkdirs() } - @Suppress("UnsafeDynamicallyLoadedCode") - private fun loadZenohJNI(inputStream: InputStream) { - val tempLib = File.createTempFile("tempLib", ".tmp") - tempLib.deleteOnExit() + val fileOutputStream = FileOutputStream(library) + var len: Int + while (zipInputStream.read(buffer).also { len = it } > 0) { + fileOutputStream.write(buffer, 0, len) + } + fileOutputStream.close() - FileOutputStream(tempLib).use { output -> - inputStream.copyTo(output) - } + zipInputStream.closeEntry() + zipInputStream.close() + return Result.success(library) + } - System.load(tempLib.absolutePath) - } + private fun loadLibraryAsInputStream(target: Target): Result = runCatching { + val libUrl = ClassLoader.getSystemClassLoader().getResourceAsStream("$target/$target.zip")!! + val uncompressedLibFile = unzipLibrary(libUrl) + return Result.success(FileInputStream(uncompressedLibFile.getOrThrow())) + } - /** - * Load library from jar package. - * - * Attempts to load the library corresponding to the `target` specified from the zenoh kotlin jar. - * - * @param target - */ - private fun tryLoadingLibraryFromJarPackage(target: Target): Result = runCatching { - val lib: Result = loadLibraryAsInputStream(target) - lib.onSuccess { loadZenohJNI(it) }.onFailure { throw Exception("Unable to load Zenoh JNI: $it") } - } + @Suppress("UnsafeDynamicallyLoadedCode") + private fun loadZenohJNI(inputStream: InputStream) { + val tempLib = File.createTempFile("tempLib", ".tmp") + tempLib.deleteOnExit() - /** - * Try loading local library. - * - * This function aims to load the default library that is usually included when building the zenoh kotlin library - * locally. - */ - private fun tryLoadingLocalLibrary(): Result = runCatching { - val lib = ClassLoader.getSystemClassLoader().findLibraryStream(ZENOH_LIB_NAME) - if (lib != null) { - loadZenohJNI(lib) - } else { - throw Exception("Unable to load local Zenoh JNI.") - } + FileOutputStream(tempLib).use { output -> + inputStream.copyTo(output) } + + System.load(tempLib.absolutePath) } - init { - // Try first to load the local native library for cases in which the module was built locally, - // otherwise try to load from the JAR. - if (tryLoadingLocalLibrary().isFailure) { - val target = determineTarget().getOrThrow() - tryLoadingLibraryFromJarPackage(target).getOrThrow() - } + /** + * Load library from jar package. + * + * Attempts to load the library corresponding to the `target` specified from the zenoh kotlin jar. + * + * @param target + */ + private fun tryLoadingLibraryFromJarPackage(target: Target): Result = runCatching { + val lib: Result = loadLibraryAsInputStream(target) + lib.onSuccess { loadZenohJNI(it) }.onFailure { throw Exception("Unable to load Zenoh JNI: $it") } + } - val logLevel = System.getProperty(ZENOH_LOGS_PROPERTY) - if (logLevel != null) { - Logger.start(logLevel) + /** + * Try loading local library. + * + * This function aims to load the default library that is usually included when building the zenoh kotlin library + * locally. + */ + private fun tryLoadingLocalLibrary(): Result = runCatching { + val lib = ClassLoader.getSystemClassLoader().findLibraryStream(ZENOH_LIB_NAME) + if (lib != null) { + loadZenohJNI(lib) + } else { + throw Exception("Unable to load local Zenoh JNI.") } } } From ba0fd31f0579a3a3ed485b2b9d2924e4e34ef42b Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 23 Oct 2024 11:30:48 -0300 Subject: [PATCH 22/83] Alignment: publisher - adding encoding and reliability to builder --- .../commonMain/kotlin/io/zenoh/pubsub/Publisher.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 297f9734..c8818b0d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -23,6 +23,7 @@ import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS +import io.zenoh.qos.Reliability import kotlin.Throws /** @@ -140,14 +141,24 @@ class Publisher internal constructor( internal val session: Session, internal val keyExpr: KeyExpr, ) { + private var reliability: Reliability = Reliability.RELIABLE private var qos = QoS.default() + private var encoding: Encoding = Encoding.default() + + fun encoding(encoding: Encoding) { + this.encoding = encoding + } + + fun reliability(reliability: Reliability) { + this.reliability = reliability + } fun qos(qos: QoS) { this.qos = qos } fun res(): Publisher { - return session.run { resolvePublisher(keyExpr, qos) } + return session.run { resolvePublisher(keyExpr, encoding, qos, reliability) } } } } From 14844c6668e93e3b806e155d1056343d95d2c0dc Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 23 Oct 2024 11:48:10 -0300 Subject: [PATCH 23/83] Alignment: subscriber --- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index dccc2bcf..bd267e32 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -23,7 +23,6 @@ import io.zenoh.pubsub.Subscriber.Builder import io.zenoh.jni.JNISubscriber import io.zenoh.keyexpr.KeyExpr import io.zenoh.sample.Sample -import io.zenoh.qos.Reliability import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque @@ -67,7 +66,7 @@ class Subscriber internal constructor( val keyExpr: KeyExpr, val receiver: R?, private var jniSubscriber: JNISubscriber? ) : AutoCloseable, SessionDeclaration { - override fun isValid(): Boolean { + fun isValid(): Boolean { return jniSubscriber != null } @@ -118,7 +117,6 @@ class Subscriber internal constructor( private var handler: Handler? = null ): Resolvable> { - private var reliability: Reliability = Reliability.BEST_EFFORT private var onClose: (() -> Unit)? = null private constructor(other: Builder<*>, handler: Handler?): this(other.session, other.keyExpr) { @@ -132,25 +130,9 @@ class Subscriber internal constructor( } private fun copyParams(other: Builder<*>) { - this.reliability = other.reliability this.onClose = other.onClose } - /** Sets the [Reliability]. */ - fun reliability(reliability: Reliability): Builder = apply { - this.reliability = reliability - } - - /** Sets the reliability to [Reliability.RELIABLE]. */ - fun reliable(): Builder = apply { - this.reliability = Reliability.RELIABLE - } - - /** Sets the reliability to [Reliability.BEST_EFFORT]. */ - fun bestEffort(): Builder = apply { - this.reliability = Reliability.BEST_EFFORT - } - /** Specify an action to be invoked when the [Subscriber] is undeclared. */ fun onClose(action: () -> Unit): Builder { this.onClose = action @@ -158,7 +140,7 @@ class Subscriber internal constructor( } /** Specify a [Callback]. Overrides any previously specified callback or handler. */ - fun with(callback: Callback): Builder = Builder(this, callback) + fun callback(callback: Callback): Builder = Builder(this, callback) /** Specify a [Handler]. Overrides any previously specified callback or handler. */ fun with(handler: Handler): Builder = Builder(this, handler) @@ -171,6 +153,7 @@ class Subscriber internal constructor( * * @return The newly created [Subscriber]. */ + @Suppress("UNCHECKED_CAST") @Throws(ZError::class) override fun res(): Subscriber { require(callback != null || handler != null) { "Either a callback or a handler must be provided." } @@ -179,7 +162,7 @@ class Subscriber internal constructor( handler?.onClose() onClose?.invoke() } - return session.run { resolveSubscriber(keyExpr, resolvedCallback, resolvedOnClose, handler?.receiver(), reliability) } + return session.run { resolveSubscriber(keyExpr, resolvedCallback, resolvedOnClose, handler?.receiver() ?: Unit as R) } //TODO: double check this cast } } } From 383f86e8c2f00bd9aa58c1c9f378cac8ca3089cb Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 23 Oct 2024 11:56:24 -0300 Subject: [PATCH 24/83] Alignment: sample --- .../kotlin/io/zenoh/sample/Sample.kt | 41 +++++-------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt index 1427167a..98bbf282 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt @@ -17,51 +17,32 @@ package io.zenoh.sample import io.zenoh.ZenohType import io.zenoh.qos.QoS import io.zenoh.keyexpr.KeyExpr -import io.zenoh.value.Value +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.ZBytes import org.apache.commons.net.ntp.TimeStamp /** * Class representing a Zenoh Sample. * - * A sample consists of a [KeyExpr]-[Value] pair, annotated with the [SampleKind] (PUT or DELETE) of the publication - * used to emit it and a timestamp. - * * @property keyExpr The [KeyExpr] of the sample. - * @property value The [Value] of the sample. + * @property payload [ZBytes] with the payload of the sample. + * @property encoding [Encoding] of the payload. * @property kind The [SampleKind] of the sample. * @property timestamp Optional [TimeStamp]. * @property qos The Quality of Service settings used to deliver the sample. * @property attachment Optional attachment. */ -class Sample( +data class Sample( val keyExpr: KeyExpr, - val value: Value, + val payload: ZBytes, + val encoding: Encoding, val kind: SampleKind, val timestamp: TimeStamp?, val qos: QoS, - val attachment: ByteArray? = null + val attachment: ZBytes? = null, ): ZenohType { - override fun toString(): String { - return if (kind == SampleKind.DELETE) "$kind($keyExpr)" else "$kind($keyExpr: $value)" - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Sample - - if (keyExpr != other.keyExpr) return false - if (value != other.value) return false - if (kind != other.kind) return false - return timestamp == other.timestamp - } - override fun hashCode(): Int { - var result = keyExpr.hashCode() - result = 31 * result + value.hashCode() - result = 31 * result + kind.hashCode() - result = 31 * result + (timestamp?.hashCode() ?: 0) - return result - } + val express = qos.express + val congestionControl = qos.congestionControl + val priority = qos.priority } From eb9eeb8b939cafbedc043b550e1d67d9826e3740 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 25 Oct 2024 12:17:23 -0300 Subject: [PATCH 25/83] Alignment: query & reply - wip --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 52 ++-- .../kotlin/io/zenoh/jni/JNIQuery.kt | 4 +- .../kotlin/io/zenoh/jni/JNISession.kt | 13 +- .../kotlin/io/zenoh/protocol/ZenohID.kt | 20 -- .../src/commonMain/kotlin/io/zenoh/qos/QoS.kt | 17 ++ .../commonMain/kotlin/io/zenoh/query/Get.kt | 35 ++- .../commonMain/kotlin/io/zenoh/query/Query.kt | 34 ++- .../kotlin/io/zenoh/query/Queryable.kt | 9 +- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 249 +++++------------- .../kotlin/io/zenoh/query/ReplyError.kt | 51 ---- 10 files changed, 148 insertions(+), 336 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/protocol/ZenohID.kt delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index d110a0f5..3c629a18 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -14,6 +14,8 @@ package io.zenoh +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession @@ -53,23 +55,12 @@ class Session private constructor(private val config: Config) : AutoCloseable { private var jniSession: JNISession? = JNISession() + private var declarations = mutableListOf() + companion object { private val sessionClosedException = ZError("Session is closed.") - /** - * Open a [Session] with the default [Config]. - * - * @return The opened [Session]. - * @throws [ZError] in the case of a failure. - */ - @JvmStatic - @Throws(ZError::class) - fun open(): Session { - val session = Session(Config.default()) - return session.launch() - } - /** * Open a [Session] with the provided [Config]. * @@ -77,18 +68,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { * @return The opened [Session]. * @throws [ZError] in the case of a failure. */ - @JvmStatic @Throws(ZError::class) - fun open(config: Config): Session { + internal fun open(config: Config): Session { val session = Session(config) return session.launch() } } - init { - Zenoh.load() - } - /** * Close the session. * @@ -99,13 +85,18 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) override fun close() { + declarations.removeIf { + it.undeclare() + true + } + jniSession?.close() jniSession = null } @Suppress("removal") protected fun finalize() { - jniSession?.close() + close() } /** @@ -139,7 +130,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Subscriber] on the session. * - * The default receiver is a [BlockingQueue], but can be changed with the [Subscriber.Builder.with] functions. + * The default receiver is a [BlockingQueue], but can be changed with the [Subscriber.Builder.callback] functions. * * Example: * @@ -169,7 +160,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Queryable] on the session. * - * The default receiver is a [BlockingQueue], but can be changed with the [Queryable.Builder.with] functions. + * The default receiver is a [BlockingQueue], but can be changed with the [Queryable.Builder.callback] functions. * * Example: * ```java @@ -355,24 +346,24 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolvePublisher(keyExpr: KeyExpr, qos: QoS): Publisher { + internal fun resolvePublisher(keyExpr: KeyExpr, encoding: Encoding, qos: QoS, reliability: Reliability): Publisher { return jniSession?.run { - declarePublisher(keyExpr, qos) + declarePublisher(keyExpr, qos, encoding, reliability) } ?: throw(sessionClosedException) } @Throws(ZError::class) internal fun resolveSubscriber( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, reliability: Reliability + keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R ): Subscriber { return jniSession?.run { - declareSubscriber(keyExpr, callback, onClose, receiver, reliability) + declareSubscriber(keyExpr, callback, onClose, receiver) } ?: throw (sessionClosedException) } @Throws(ZError::class) internal fun resolveQueryable( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R?, complete: Boolean + keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R, complete: Boolean ): Queryable { return jniSession?.run { declareQueryable(keyExpr, callback, onClose, receiver, complete) @@ -388,13 +379,14 @@ class Session private constructor(private val config: Config) : AutoCloseable { timeout: Duration, target: QueryTarget, consolidation: ConsolidationMode, - value: Value?, - attachment: ByteArray?, + payload: IntoZBytes?, + encoding: Encoding?, + attachment: IntoZBytes?, ): R? { if (jniSession == null) { throw sessionClosedException } - return jniSession?.performGet(selector, callback, onClose, receiver, timeout, target, consolidation, value, attachment) + return jniSession?.performGet(selector, callback, onClose, receiver, timeout, target, consolidation, payload, encoding, attachment) } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt index 1a0a9090..afda43e7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt @@ -31,7 +31,7 @@ import org.apache.commons.net.ntp.TimeStamp */ internal class JNIQuery(private val ptr: Long) { - fun replySuccess(sample: Sample): Result = runCatching { + fun replySuccess(sample: Sample) { val timestampEnabled = sample.timestamp != null replySuccessViaJNI( ptr, @@ -49,12 +49,10 @@ internal class JNIQuery(private val ptr: Long) { ) } - @Throws(ZError::class) fun replyError(error: IntoZBytes, encoding: Encoding) { replyErrorViaJNI(ptr, error.into().bytes, encoding.id, encoding.schema) } - @Throws(ZError::class) fun replyDelete(keyExpr: KeyExpr, timestamp: TimeStamp?, attachment: IntoZBytes?, qos: QoS) { val timestampEnabled = timestamp != null replyDeleteViaJNI( diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 8e1e1659..9912d7fe 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -177,15 +177,12 @@ internal class JNISession { QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), attachmentBytes?.into() ) - reply = Reply(replierId?.let { ZenohId(it) }, Result.success(sample)) + reply = Reply.Success(replierId?.let { ZenohId(it) }, sample) } else { - reply = Reply( - replierId?.let { ZenohId(it) }, Result.failure( - ReplyError( - payload.into(), - Encoding(encodingId, schema = encodingSchema) - ) - ) + reply = Reply.Error( + replierId?.let { ZenohId(it) }, + payload.into(), + Encoding(encodingId, schema = encodingSchema) ) } callback.run(reply) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/protocol/ZenohID.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/protocol/ZenohID.kt deleted file mode 100644 index 953fb226..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/protocol/ZenohID.kt +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.protocol - -/** - * The global unique id of a Zenoh peer. - */ -class ZenohID(val id: String) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt index db6b6024..f669c542 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt @@ -32,4 +32,21 @@ data class QoS ( fun default() = defaultQoS } + + internal class Builder( + private var express: Boolean = false, + private var congestionControl: CongestionControl = CongestionControl.DROP, + private var priority: Priority = Priority.REALTIME, + ) { + + fun express(value: Boolean) = apply { this.express = value } + + fun priority(priority: Priority) = apply { this.priority = priority } + + fun congestionControl(congestionControl: CongestionControl) = + apply { this.congestionControl = congestionControl } + + fun build() = QoS(congestionControl, priority, express) + } + } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index 461a33e7..e85d154a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -16,10 +16,12 @@ package io.zenoh.query import io.zenoh.handlers.Callback import io.zenoh.Session +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes +import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler -import io.zenoh.value.Value import java.time.Duration import java.util.* import java.util.concurrent.BlockingQueue @@ -80,9 +82,10 @@ class Get private constructor() { private var timeout = Duration.ofMillis(10000) private var target: QueryTarget = QueryTarget.BEST_MATCHING - private var consolidation: ConsolidationMode = ConsolidationMode.default() - private var value: Value? = null - private var attachment: ByteArray? = null + private var consolidation: ConsolidationMode = ConsolidationMode.AUTO + private var payload: ZBytes? = null + private var encoding: Encoding? = null + private var attachment: ZBytes? = null private var onClose: (() -> Unit)? = null private constructor(other: Builder<*>, handler: Handler?) : this(other.session, other.selector) { @@ -99,7 +102,8 @@ class Get private constructor() { this.timeout = other.timeout this.target = other.target this.consolidation = other.consolidation - this.value = other.value + this.payload = other.payload + this.encoding = other.encoding this.attachment = other.attachment this.onClose = other.onClose } @@ -122,24 +126,14 @@ class Get private constructor() { return this } - /** - * Specify a string value. A [Value] is generated with the provided message, therefore - * this method is equivalent to calling `withValue(Value(message))`. - */ - fun withValue(message: String): Builder { - this.value = Value(message) - return this - } - - /** Specify a [Value]. */ - fun withValue(value: Value): Builder { - this.value = value + fun payload(payload: IntoZBytes): Builder { + this.payload = payload.into() return this } /** Specify an attachment. */ - fun withAttachment(attachment: ByteArray): Builder { - this.attachment = attachment + fun withAttachment(attachment: IntoZBytes): Builder { + this.attachment = attachment.into() return this } @@ -184,7 +178,8 @@ class Get private constructor() { timeout, target, consolidation, - value, + payload, + encoding, attachment ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 31b8089d..7266d854 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -16,10 +16,13 @@ package io.zenoh.query import io.zenoh.Resolvable import io.zenoh.ZenohType -import io.zenoh.value.Value +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes +import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIQuery import io.zenoh.keyexpr.KeyExpr +import io.zenoh.sample.SampleKind /** * Represents a Zenoh Query in Kotlin. @@ -28,7 +31,8 @@ import io.zenoh.keyexpr.KeyExpr * * @property keyExpr The key expression to which the query is associated. * @property selector The selector - * @property value Optional value in case the received query was declared using "with query". + * @property payload Optional payload in case the received query was declared using "with query". + * @property encoding Encoding of the [payload]. * @property attachment Optional attachment. * @property jniQuery Delegate object in charge of communicating with the underlying native code. * @constructor Instances of Query objects are only meant to be created through the JNI upon receiving @@ -37,8 +41,9 @@ import io.zenoh.keyexpr.KeyExpr class Query internal constructor( val keyExpr: KeyExpr, val selector: Selector, - val value: Value?, - val attachment: ByteArray?, + val payload: ZBytes?, + val encoding: Encoding?, + val attachment: ZBytes?, private var jniQuery: JNIQuery? ) : AutoCloseable, ZenohType { @@ -50,9 +55,13 @@ class Query internal constructor( * * @param keyExpr Key expression to reply to. This parameter must not be necessarily the same * as the key expression from the Query, however it must intersect with the query key. - * @return a [Reply.Builder] + * @return a [ReplySuccess.Builder] */ - fun reply(keyExpr: KeyExpr) = Reply.Builder(this, keyExpr) + fun reply(keyExpr: KeyExpr, payload: IntoZBytes) = ReplyBuilder(this, keyExpr, payload.into(), SampleKind.PUT) + + fun replyDel(keyExpr: KeyExpr) = ReplyBuilder(this, keyExpr, ZBytes(byteArrayOf()), SampleKind.DELETE) //TODO: refactor + + fun replyErr(payload: IntoZBytes) = ReplyErrBuilder(this, payload.into()) override fun close() { jniQuery?.apply { @@ -75,17 +84,18 @@ class Query internal constructor( * @param reply The [Reply] to the Query. * @return A [Resolvable] that returns a [Result] with the status of the reply operation. */ - internal fun reply(reply: Reply): Resolvable = Resolvable { + internal fun resolveReply(reply: Reply): Resolvable = Resolvable { jniQuery?.apply { val result = when (reply) { is Reply.Success -> { - replySuccess(reply.sample) + if (reply.sample.kind == SampleKind.PUT) { + replySuccess(reply.sample) + } else { + replyDelete(reply.sample.keyExpr, reply.sample.timestamp, reply.sample.attachment, reply.sample.qos) + } } is Reply.Error -> { - replyError(reply.error) - } - is Reply.Delete -> { - replyDelete(reply.keyExpr, reply.timestamp, reply.attachment, reply.qos) + replyError(reply.error, reply.encoding) } } jniQuery = null diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index 47d8ba27..d7d0c6e4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -71,7 +71,7 @@ class Queryable internal constructor( val keyExpr: KeyExpr, val receiver: R?, private var jniQueryable: JNIQueryable? ) : AutoCloseable, SessionDeclaration { - override fun isValid(): Boolean { + fun isValid(): Boolean { return jniQueryable != null } @@ -148,7 +148,7 @@ class Queryable internal constructor( } /** Specify a [Callback]. Overrides any previously specified callback or handler. */ - fun with(callback: Callback): Builder = Builder(this, callback) + fun callback(callback: Callback): Builder = Builder(this, callback) /** Specify a [Handler]. Overrides any previously specified callback or handler. */ fun with(handler: Handler): Builder = Builder(this, handler) @@ -169,7 +169,10 @@ class Queryable internal constructor( handler?.onClose() onClose?.invoke() } - return session.run { resolveQueryable(keyExpr, resolvedCallback, resolvedOnClose, handler?.receiver(), complete) } + return session.run { + @Suppress("UNCHECKED_CAST") + resolveQueryable(keyExpr, resolvedCallback, resolvedOnClose, handler?.receiver() ?: Unit as R, complete) // TODO: double check cast + } } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index 898b867d..a34349c8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -16,15 +16,17 @@ package io.zenoh.query import io.zenoh.Resolvable import io.zenoh.ZenohType +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.IntoZBytes +import io.zenoh.bytes.ZBytes +import io.zenoh.config.ZenohId import io.zenoh.exceptions.ZError import io.zenoh.sample.Sample import io.zenoh.sample.SampleKind -import io.zenoh.value.Value import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS -import io.zenoh.protocol.ZenohID import org.apache.commons.net.ntp.TimeStamp /** @@ -53,121 +55,10 @@ import org.apache.commons.net.ntp.TimeStamp * * @property replierId: unique ID identifying the replier. */ -sealed class Reply private constructor(val replierId: ZenohID?) : ZenohType { - /** - * Builder to construct a [Reply]. - * - * This builder allows you to construct [Success] and [Error] replies. - * - * @property query The received [Query] to reply to. - * @property keyExpr The [KeyExpr] from the queryable, which is at least an intersection of the query's key expression. - * @constructor Create empty Builder - */ - class Builder internal constructor(val query: Query, val keyExpr: KeyExpr) { - - /** - * Returns a [Success.Builder] with the provided [value]. - * - * @param value The [Value] of the reply. - */ - fun success(value: Value) = Success.Builder(query, keyExpr, value) - - /** - * Returns a [Success.Builder] with a [Value] containing the provided [message]. - * - * It is equivalent to calling `success(Value(message))`. - * - * @param message A string message for the reply. - */ - fun success(message: String) = success(Value(message)) - - /** - * Returns an [Error.Builder] with the provided [value]. - * - * @param value The [Value] of the error reply. - */ - fun error(value: Value) = Error.Builder(query, value) - - /** - * Returns an [Error.Builder] with a [Value] containing the provided [message]. - * - * It is equivalent to calling `error(Value(message))`. - * - * @param message A string message for the error reply. - */ - fun error(message: String) = error(Value(message)) +sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { - /** - * Returns a [Delete.Builder]. - */ - fun delete() = Delete.Builder(query, keyExpr) - - } - - /** - * A successful [Reply]. - * - * @property sample The [Sample] of the reply. - * @constructor Internal constructor, since replies are only meant to be generated upon receiving a remote reply - * or by calling [Query.reply] to reply to the specified [Query]. - * - * @param replierId The replierId of the remotely generated reply. - */ - class Success internal constructor(replierId: ZenohID?, val sample: Sample) : Reply(replierId) { - - /** - * Builder for the [Success] reply. - * - * @property query The [Query] to reply to. - * @property keyExpr The [KeyExpr] of the queryable. - * @property value The [Value] with the reply information. - */ - class Builder internal constructor(val query: Query, val keyExpr: KeyExpr, val value: Value) : - Resolvable { - - private val kind = SampleKind.PUT - private var timeStamp: TimeStamp? = null - private var attachment: ByteArray? = null - private var qosBuilder = QoS.Builder() - - /** - * Sets the [TimeStamp] of the replied [Sample]. - */ - fun timestamp(timeStamp: TimeStamp) = apply { this.timeStamp = timeStamp } - - /** - * Appends an attachment to the reply. - */ - fun attachment(attachment: ByteArray) = apply { this.attachment = attachment } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(express: Boolean) = apply { qosBuilder.express(express) } - - /** - * Sets the [Priority] of the reply. - */ - fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } - - /** - * Sets the [CongestionControl] of the reply. - * - * @param congestionControl - */ - fun congestionControl(congestionControl: CongestionControl) = - apply { qosBuilder.congestionControl(congestionControl) } - - /** - * Constructs the reply sample with the provided parameters and triggers the reply to the query. - */ - @Throws(ZError::class) - override fun res() { - val sample = Sample(keyExpr, value, kind, timeStamp, qosBuilder.build(), attachment) - return query.reply(Success(null, sample)).res() - } - } + class Success internal constructor(replierId: ZenohId?, val sample: Sample) : Reply(replierId) { override fun toString(): String { return "Success(sample=$sample)" @@ -176,40 +67,17 @@ sealed class Reply private constructor(val replierId: ZenohID?) : ZenohType { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Success) return false - return sample == other.sample } override fun hashCode(): Int { return sample.hashCode() } - } - /** - * An Error reply. - * - * @property error: value with the error information. - * @constructor The constructor is private since reply instances are created through JNI when receiving a reply to a query. - * - * @param replierId: unique ID identifying the replier. - */ - class Error internal constructor(replierId: ZenohID?, val error: Value) : Reply(replierId) { - - /** - * Builder for the [Error] reply. - * - * @property query The [Query] to reply to. - * @property value The [Value] with the reply information. - */ - class Builder internal constructor(val query: Query, val value: Value) : Resolvable { + } - /** - * Triggers the error reply. - */ - override fun res() { - return query.reply(Error(null, value)).res() - } - } + class Error internal constructor(replierId: ZenohId?, val error: ZBytes, val encoding: Encoding) : + Reply(replierId) { override fun toString(): String { return "Error(error=$error)" @@ -226,64 +94,67 @@ sealed class Reply private constructor(val replierId: ZenohID?) : ZenohType { return error.hashCode() } } +} + +class ReplyBuilder internal constructor(val query: Query, val keyExpr: KeyExpr, val payload: ZBytes, val kind: SampleKind): Resolvable { + + private var encoding: Encoding = Encoding.default() + private var timeStamp: TimeStamp? = null + private var attachment: ZBytes? = null + private var qosBuilder = QoS.Builder() + + + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } /** - * A Delete reply. - * - * @property keyExpr - * @constructor - * - * @param replierId + * Sets the [TimeStamp] of the replied [Sample]. + */ + fun timestamp(timeStamp: TimeStamp) = apply { this.timeStamp = timeStamp } + + /** + * Appends an attachment to the reply. */ - class Delete internal constructor( - replierId: ZenohID?, - val keyExpr: KeyExpr, - val timestamp: TimeStamp?, - val attachment: ByteArray?, - val qos: QoS - ) : Reply(replierId) { + fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment.into() } - class Builder internal constructor(val query: Query, val keyExpr: KeyExpr) : Resolvable { + /** + * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. + */ + fun express(express: Boolean) = apply { qosBuilder.express(express) } - private val kind = SampleKind.DELETE - private var timeStamp: TimeStamp? = null - private var attachment: ByteArray? = null - private var qosBuilder = QoS.Builder() + /** + * Sets the [Priority] of the reply. + */ + fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } - /** - * Sets the [TimeStamp] of the replied [Sample]. - */ - fun timestamp(timeStamp: TimeStamp) = apply { this.timeStamp = timeStamp } + /** + * Sets the [CongestionControl] of the reply. + * + * @param congestionControl + */ + fun congestionControl(congestionControl: CongestionControl) = + apply { qosBuilder.congestionControl(congestionControl) } - /** - * Appends an attachment to the reply. - */ - fun attachment(attachment: ByteArray) = apply { this.attachment = attachment } + /** + * Constructs the reply sample with the provided parameters and triggers the reply to the query. + */ + @Throws(ZError::class) + override fun res() { + val sample = Sample(keyExpr, payload, encoding, kind, timeStamp, qosBuilder.build(), attachment) + return query.resolveReply(Reply.Success(null, sample)).res() + } +} - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(express: Boolean) = apply { qosBuilder.express(express) } +class ReplyErrBuilder internal constructor(val query: Query, val payload: ZBytes): Resolvable { - /** - * Sets the [Priority] of the reply. - */ - fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } + private var encoding: Encoding = Encoding.default() - /** - * Sets the [CongestionControl] of the reply. - * - * @param congestionControl - */ - fun congestionControl(congestionControl: CongestionControl) = - apply { qosBuilder.congestionControl(congestionControl) } + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } - /** - * Triggers the delete reply. - */ - override fun res() { - return query.reply(Delete(null, keyExpr, timeStamp, attachment, qosBuilder.build())).res() - } - } + /** + * Constructs the reply sample with the provided parameters and triggers the reply to the query. + */ + @Throws(ZError::class) + override fun res() { + return query.resolveReply(Reply.Error(null, payload, encoding)).res() } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt deleted file mode 100644 index 609f33f4..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyError.kt +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.query - -import io.zenoh.bytes.Encoding -import io.zenoh.bytes.ZBytes - -/** - * Reply error class. - * - * When receiving an error reply while performing a get operation, this is the error type returned: - * ```kotlin - * session.get(selector, callback = { reply -> - * reply.result.onSuccess { sample -> - * // ... - * }.onFailure { error -> - * error as ReplyError - * println("Received (ERROR: '${error.payload}' with encoding '${error.encoding}'.)") - * // ... - * } - * }) - * ``` - * - * This class is useful in case you need to apply different logic based on the encoding of the error or - * need to deserialize the [payload] value into something else other than a string. - * - * Otherwise, the error payload can be obtained as a string under the [Throwable.message] parameter: - * ```kotlin - * session.get(selector, callback = { reply -> - * reply.result.onSuccess { sample -> - * // ... - * }.onFailure { error -> - * println("Received (ERROR: '${error.message}')") - * // ... - * } - * }) - * ``` - */ -data class ReplyError(val payload: ZBytes?, val encoding: Encoding?) : Throwable(message = payload.toString()) From 1f9b13de5c93c3398fc0f62b5cd1b76906acafa6 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Sun, 27 Oct 2024 21:37:24 -0300 Subject: [PATCH 26/83] Alignment: Put & Session --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 64 +++++-------------- .../kotlin/io/zenoh/jni/JNISession.kt | 21 +++--- .../kotlin/io/zenoh/keyexpr/KeyExpr.kt | 9 ++- .../kotlin/io/zenoh/pubsub/Delete.kt | 34 ++++++++-- .../kotlin/io/zenoh/pubsub/Publisher.kt | 1 + .../commonMain/kotlin/io/zenoh/pubsub/Put.kt | 42 +++++++++--- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 1 + .../kotlin/io/zenoh/query/Queryable.kt | 1 + .../kotlin/io/zenoh/query/Selector.kt | 64 ++++++++++--------- .../zenoh/{ => session}/SessionDeclaration.kt | 2 +- .../kotlin/io/zenoh/session/SessionInfo.kt | 45 +++++++++++++ 11 files changed, 174 insertions(+), 110 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/{ => session}/SessionDeclaration.kt (97%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 3c629a18..1ea0e8ba 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -16,6 +16,7 @@ package io.zenoh import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes +import io.zenoh.config.ZenohId import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession @@ -31,7 +32,7 @@ import io.zenoh.sample.Sample import io.zenoh.query.Selector import io.zenoh.qos.Reliability import io.zenoh.pubsub.Subscriber -import io.zenoh.value.Value +import io.zenoh.session.SessionDeclaration import java.time.Duration import java.util.* import java.util.concurrent.BlockingQueue @@ -253,31 +254,12 @@ class Session private constructor(private val config: Config) : AutoCloseable { * @param selector The [KeyExpr] to be used for the get operation. * @return a resolvable [Get.Builder] with a [BlockingQueue] receiver. */ - fun get(selector: Selector): Get.Builder>> = Get.newBuilder(this, selector) + fun get(selector: IntoSelector): Get.Builder>> = Get.newBuilder(this, selector.into()) - /** - * Declare a [Get] with a [BlockingQueue] receiver as default. - * - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/java/example")) { - * session.get(keyExpr) - * .consolidation(ConsolidationMode.NONE) - * .withValue("Get value example") - * .with(reply -> System.out.println("Received reply " + reply)) - * .res() - * } - * } - * ``` - * - * @param keyExpr The [KeyExpr] to be used for the get operation. - * @return a resolvable [Get.Builder] with a [BlockingQueue] receiver. - */ - fun get(keyExpr: KeyExpr): Get.Builder>> = Get.newBuilder(this, Selector(keyExpr)) /** * Declare a [Put] with the provided value on the specified key expression. - * + * //TODO update * Example: * ```java * try (Session session = Session.open()) { @@ -293,33 +275,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { * ``` * * @param keyExpr The [KeyExpr] to be used for the put operation. - * @param value The [Value] to be put. * @return A resolvable [Put.Builder]. */ - fun put(keyExpr: KeyExpr, value: Value): Put.Builder = Put.newBuilder(this, keyExpr, value) - - /** - * Declare a [Put] with the provided value on the specified key expression. - * - * Example: - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/greeting")) { - * session.put(keyExpr, "Hello!") - * .congestionControl(CongestionControl.BLOCK) - * .priority(Priority.REALTIME) - * .kind(SampleKind.PUT) - * .res(); - * System.out.println("Put 'Hello' on " + keyExpr + "."); - * } - * } - * ``` - * - * @param keyExpr The [KeyExpr] to be used for the put operation. - * @param message The message to be put. - * @return A resolvable [Put.Builder]. - */ - fun put(keyExpr: KeyExpr, message: String): Put.Builder = Put.newBuilder(this, keyExpr, Value(message)) + fun put(keyExpr: KeyExpr, payload: IntoZBytes): Put.Builder = Put.newBuilder(this, keyExpr, payload) /** * Declare a [Delete]. @@ -399,6 +357,18 @@ class Session private constructor(private val config: Config) : AutoCloseable { jniSession?.run { performDelete(keyExpr, delete) } } + internal fun zid(): Result { + return jniSession?.zid() ?: Result.failure(sessionClosedException) + } + + internal fun getPeersId(): Result> { + return jniSession?.peersZid() ?: Result.failure(sessionClosedException) + } + + internal fun getRoutersId(): Result> { + return jniSession?.routersZid() ?: Result.failure(sessionClosedException) + } + /** Launches the session through the jni session, returning the [Session] on success. */ @Throws(ZError::class) private fun launch(): Session { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 9912d7fe..a05de0e1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -119,7 +119,7 @@ internal class JNISession { val selector = if (selectorParams.isEmpty()) { Selector(keyExpr2) } else { - Selector(keyExpr2, Parameters.from(selectorParams).getOrThrow()) + Selector(keyExpr2, Parameters.from(selectorParams)) } val query = Query( keyExpr2, @@ -235,7 +235,7 @@ internal class JNISession { put.qos.congestionControl.value, put.qos.priority.value, put.qos.express, - put.attachment?.bytes, + put.attachment?.into()?.bytes, put.reliability.ordinal ) } @@ -252,24 +252,21 @@ internal class JNISession { delete.qos.congestionControl.value, delete.qos.priority.value, delete.qos.express, - delete.attachment?.bytes, + delete.attachment?.into()?.bytes, delete.reliability.ordinal ) } - @Throws(ZError::class) - fun zid(): ZenohId { - return ZenohId(getZidViaJNI(sessionPtr.get())) + fun zid(): Result = runCatching { + ZenohId(getZidViaJNI(sessionPtr.get())) } - @Throws(ZError::class) - fun peersZid(): List { - return getPeersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } + fun peersZid(): Result> = runCatching { + getPeersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } } - @Throws(ZError::class) - fun routersZid(): List { - return getRoutersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } + fun routersZid(): Result> = runCatching { + getRoutersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt index f4727096..24ea7cd6 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt @@ -14,11 +14,12 @@ package io.zenoh.keyexpr -import io.zenoh.Resolvable import io.zenoh.Session -import io.zenoh.SessionDeclaration +import io.zenoh.session.SessionDeclaration import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIKeyExpr +import io.zenoh.query.IntoSelector +import io.zenoh.query.Selector /** * # Address space @@ -61,7 +62,7 @@ import io.zenoh.jni.JNIKeyExpr * @param jniKeyExpr An optional [JNIKeyExpr] instance, present when the key expression was declared through [Session.declareKeyExpr], * it represents the native instance of the key expression. */ -class KeyExpr internal constructor(internal val keyExpr: String, internal var jniKeyExpr: JNIKeyExpr? = null): AutoCloseable, +class KeyExpr internal constructor(internal val keyExpr: String, internal var jniKeyExpr: JNIKeyExpr? = null): AutoCloseable, IntoSelector, SessionDeclaration { companion object { @@ -169,6 +170,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn jniKeyExpr = null } + override fun into(): Selector = Selector(this) + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt index fb0649c2..2741a7d7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt @@ -22,6 +22,7 @@ import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS +import io.zenoh.qos.Reliability import kotlin.Throws /** @@ -44,7 +45,7 @@ import kotlin.Throws * specifying the sample kind to be `DELETE`. */ class Delete private constructor( - val keyExpr: KeyExpr, val qos: QoS, val attachment: IntoZBytes? + val keyExpr: KeyExpr, val qos: QoS, val reliability: Reliability, val attachment: IntoZBytes? ) { companion object { @@ -73,16 +74,35 @@ class Delete private constructor( ) : Resolvable { private var attachment: IntoZBytes? = null - - private var qos: QoS = QoS.default() + private var reliability: Reliability = Reliability.RELIABLE + private var qosBuilder = QoS.Builder() fun attachment(attachment: IntoZBytes) { this.attachment = attachment } - fun qos(qos: QoS) { - this.qos = qos - } + /** + * The [Reliability] wished to be obtained from the network. + */ + fun reliability(reliability: Reliability) = apply { this.reliability = reliability } + + /** + * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. + */ + fun express(express: Boolean) = apply { qosBuilder.express(express) } + + /** + * Sets the [Priority] of the reply. + */ + fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } + + /** + * Sets the [CongestionControl] of the reply. + * + * @param congestionControl + */ + fun congestionControl(congestionControl: CongestionControl) = + apply { qosBuilder.congestionControl(congestionControl) } /** * Performs a DELETE operation on the specified [keyExpr]. @@ -92,7 +112,7 @@ class Delete private constructor( */ @Throws(ZError::class) override fun res() { - val delete = Delete(this.keyExpr, qos, attachment) + val delete = Delete(this.keyExpr, qosBuilder.build(), reliability, attachment) session.resolveDelete(keyExpr, delete) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index c8818b0d..91135a7f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -24,6 +24,7 @@ import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.qos.Reliability +import io.zenoh.session.SessionDeclaration import kotlin.Throws /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt index 79c9e125..3c5319b8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt @@ -18,10 +18,13 @@ import io.zenoh.Resolvable import io.zenoh.Session import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes +import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority import io.zenoh.qos.QoS -import io.zenoh.value.Value +import io.zenoh.qos.Reliability /** * Put operation. @@ -52,9 +55,10 @@ import io.zenoh.value.Value */ class Put private constructor( val keyExpr: KeyExpr, - val payload: IntoZBytes, - val encoding: Encoding?, + val payload: ZBytes, + val encoding: Encoding, val qos: QoS, + val reliability: Reliability, val attachment: IntoZBytes? ) { @@ -65,7 +69,7 @@ class Put private constructor( * * @param session The [Session] from which the put will be performed. * @param keyExpr The [KeyExpr] upon which the put will be performed. - * @param value The [Value] to put. + * // todo * @return A [Put] operation [Builder]. */ internal fun newBuilder(session: Session, keyExpr: KeyExpr, payload: IntoZBytes): Builder { @@ -87,18 +91,38 @@ class Put private constructor( private val payload: IntoZBytes, ): Resolvable { + private var qosBuilder = QoS.Builder() private var attachment: IntoZBytes? = null - private var qos = QoS.default() private var encoding: Encoding? = null + private var reliability: Reliability = Reliability.RELIABLE /** Change the [Encoding] of the written data. */ fun encoding(encoding: Encoding) = apply { this.encoding = encoding } - fun qos(qos: QoS) { - this.qos = qos - } + /** + * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. + */ + fun express(express: Boolean) = apply { qosBuilder.express(express) } + + /** + * Sets the [Priority] of the reply. + */ + fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } + + /** + * Sets the [CongestionControl] of the reply. + * + * @param congestionControl + */ + fun congestionControl(congestionControl: CongestionControl) = + apply { qosBuilder.congestionControl(congestionControl) } + + /** + * The [Reliability] wished to be obtained from the network. + */ + fun reliability(reliability: Reliability) = apply { this.reliability = reliability } /** Set an attachment to the put operation. */ fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } @@ -106,7 +130,7 @@ class Put private constructor( /** Resolves the put operation, returning a [Result]. */ @Throws(ZError::class) override fun res() { - val put = Put(keyExpr, payload, encoding, qos, attachment) + val put = Put(keyExpr, payload.into(), encoding ?: Encoding.default(), qosBuilder.build(), reliability, attachment) session.run { resolvePut(keyExpr, put) } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index bd267e32..13732324 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -23,6 +23,7 @@ import io.zenoh.pubsub.Subscriber.Builder import io.zenoh.jni.JNISubscriber import io.zenoh.keyexpr.KeyExpr import io.zenoh.sample.Sample +import io.zenoh.session.SessionDeclaration import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index d7d0c6e4..b0794ba9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -21,6 +21,7 @@ import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler import io.zenoh.jni.JNIQueryable import io.zenoh.keyexpr.KeyExpr +import io.zenoh.session.SessionDeclaration import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt index 1b609344..289a84f8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt @@ -14,48 +14,46 @@ package io.zenoh.query -import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr /** * A selector is the combination of a [KeyExpr], which defines the - * set of keys that are relevant to an operation, and a [parameters], a set of key-value pairs with a few uses: + * set of keys that are relevant to an operation, and a set of parameters + * with a few intended uses: + * - specifying arguments to a queryable, allowing the passing of Remote Procedure Call parameters + * - filtering by value, + * - filtering by metadata, such as the timestamp of a value, + * - specifying arguments to zenoh when using the REST API. * - * * specifying arguments to a queryable, allowing the passing of Remote Procedure Call parameters - * * filtering by value, - * * filtering by metadata, such as the timestamp of a value + * When in string form, selectors look a lot like a URI, with similar semantics: + * - the `key_expr` before the first `?` must be a valid key expression. + * - the `parameters` after the first `?` should be encoded like the query section of a URL: + * - parameters are separated by `;`, + * - the parameter name and value are separated by the first `=`, + * - in the absence of `=`, the parameter value is considered to be the empty string, + * - both name and value should use percent-encoding to escape characters, + * - defining a value for the same parameter name twice is considered undefined behavior, + * with the encouraged behaviour being to reject operations when a duplicate parameter is detected. + * + * Zenoh intends to standardize the usage of a set of parameter names. To avoid conflicting with RPC parameters, + * the Zenoh team has settled on reserving the set of parameter names that start with non-alphanumeric characters. + * + * The full specification for selectors is available [here](https://github.com/eclipse-zenoh/roadmap/tree/main/rfcs/ALL/Selectors), + * it includes standardized parameters. + * + * Queryable implementers are encouraged to prefer these standardized parameter names when implementing their + * associated features, and to prefix their own parameter names to avoid having conflicting parameter names with other + * queryables. * * @property keyExpr The [KeyExpr] of the selector. - * @property parameters The parameters of the selector. + * @property parameters The [Parameters] of the selector. */ -class Selector(val keyExpr: KeyExpr, val parameters: String = ""): AutoCloseable { +data class Selector(val keyExpr: KeyExpr, val parameters: Parameters? = null) : AutoCloseable, IntoSelector { - companion object { - - /** - * Try from. - * - * Equivalent constructor to [String.intoSelector], generates a selector from a string. - * - * @param expression A string with the form "?". - * @return A [Selector] in case of success. - * @throws ZError in case of failure generating the key expression. - */ - @JvmStatic - @Throws(ZError::class) - fun tryFrom(expression: String): Selector { - if (expression.isEmpty()) { - throw(ZError("Attempting to create a KeyExpr from an empty string.")) - } - val result = expression.split('?', limit = 2) - val keyExpr = KeyExpr.autocanonize(result[0]) - val params = if (result.size == 2) result[1] else "" - return Selector(keyExpr, params) - } - } + override fun into(): Selector = this override fun toString(): String { - return if (parameters.isEmpty()) "$keyExpr" else "$keyExpr?$parameters" + return parameters?.let { "$keyExpr?$parameters" } ?: keyExpr.toString() } /** Closes the selector's [KeyExpr]. */ @@ -63,3 +61,7 @@ class Selector(val keyExpr: KeyExpr, val parameters: String = ""): AutoCloseable keyExpr.close() } } + +interface IntoSelector { + fun into(): Selector +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt similarity index 97% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt index db4115a8..79041640 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/SessionDeclaration.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -package io.zenoh +package io.zenoh.session /** * Session declaration. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt new file mode 100644 index 00000000..66b57d2f --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt @@ -0,0 +1,45 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.session + +import io.zenoh.Session +import io.zenoh.config.ZenohId + +/** + * Class allowing to obtain the information of a [Session]. + */ +class SessionInfo(private val session: Session) { + + /** + * Return the [ZenohId] of the current Zenoh [Session] + */ + fun zid(): Result { + return session.zid() + } + + /** + * Return the [ZenohId] of the zenoh peers the session is currently connected to. + */ + fun peersZid(): Result> { + return session.getPeersId() + } + + /** + * Return the [ZenohId] of the zenoh routers the session is currently connected to. + */ + fun routersZid(): Result> { + return session.getRoutersId() + } +} From 283c1f35374d0f77760e0ccb66e198343058f05e Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Sun, 27 Oct 2024 22:39:17 -0300 Subject: [PATCH 27/83] Alignment: fix 'IntoSelector' --- zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt index a7ecd360..4c2ede28 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt @@ -24,6 +24,6 @@ fun String.intoSelector(): Selector { } val result = this.split('?', limit = 2) val keyExpr = KeyExpr.autocanonize(result[0]) - val params = if (result.size == 2) result[1] else "" + val params = if (result.size == 2) Parameters.from(result[1]) else null return Selector(keyExpr, params) } From 6dcfe699b409e01aaa87c4e06056d27f11d46b77 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 29 Oct 2024 16:47:30 -0300 Subject: [PATCH 28/83] Alignment: updating zenoh-jni --- zenoh-jni/Cargo.lock | 706 ++++++++++++++++++------------------- zenoh-jni/Cargo.toml | 10 +- zenoh-jni/src/config.rs | 185 ++++++++++ zenoh-jni/src/errors.rs | 63 +--- zenoh-jni/src/key_expr.rs | 161 +++++++-- zenoh-jni/src/lib.rs | 5 + zenoh-jni/src/logger.rs | 28 +- zenoh-jni/src/publisher.rs | 13 +- zenoh-jni/src/query.rs | 22 +- zenoh-jni/src/queryable.rs | 2 +- zenoh-jni/src/scouting.rs | 109 ++++++ zenoh-jni/src/session.rs | 384 ++++++++++++-------- zenoh-jni/src/utils.rs | 72 ++-- zenoh-jni/src/zbytes.rs | 571 ++++++++++++++++++++++++++++++ zenoh-jni/src/zenoh_id.rs | 42 +++ 15 files changed, 1720 insertions(+), 653 deletions(-) create mode 100644 zenoh-jni/src/config.rs create mode 100644 zenoh-jni/src/scouting.rs create mode 100644 zenoh-jni/src/zbytes.rs create mode 100644 zenoh-jni/src/zenoh_id.rs diff --git a/zenoh-jni/Cargo.lock b/zenoh-jni/Cargo.lock index 068de54a..96736838 100644 --- a/zenoh-jni/Cargo.lock +++ b/zenoh-jni/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aes" @@ -43,24 +43,24 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-logd-logger" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fe8042a3174caeafdad8ee1337788db51833e7f8649c07c6d6de70048adef4" +checksum = "0483169d5fac0887f85c2fa8fecfe08669791712d8260de1a6ec30630a62932f" dependencies = [ "bytes", "env_logger", @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "array-init" @@ -88,9 +88,9 @@ checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" [[package]] name = "asn1-rs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -104,13 +104,13 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "synstructure", ] @@ -122,7 +122,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -133,13 +133,13 @@ checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -155,30 +155,30 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] name = "base64" -version = "0.21.4" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" @@ -209,9 +209,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -227,15 +227,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -251,11 +251,11 @@ checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "45bcde016d64c21da4be18b655631e5ab6d3107607e71a73a9f53eb48aae23fb" dependencies = [ - "libc", + "shlex", ] [[package]] @@ -331,24 +331,24 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -367,15 +367,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -398,15 +398,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -471,20 +471,20 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "dyn-clone" -version = "1.0.13" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" @@ -621,7 +621,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -666,9 +666,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -679,9 +679,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "git-version" @@ -700,15 +700,9 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - [[package]] name = "hashbrown" version = "0.12.3" @@ -760,9 +754,9 @@ dependencies = [ [[package]] name = "http" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -771,9 +765,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "humantime" @@ -803,9 +797,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -829,12 +823,6 @@ dependencies = [ "serde", ] -[[package]] -name = "iter-read" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c397ca3ea05ad509c4ec451fea28b4771236a376ca1c69fd5143aae0cf8f93c4" - [[package]] name = "itertools" version = "0.13.0" @@ -846,9 +834,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jni" @@ -888,9 +876,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -908,9 +896,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -933,6 +921,12 @@ dependencies = [ "spin", ] +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.158" @@ -941,25 +935,35 @@ checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.6", ] [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -967,15 +971,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lz4_flex" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea9b256699eda7b0387ffbc776dd625e28bde3918446381781245b7a50349d8" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" dependencies = [ "twox-hash", ] @@ -1003,11 +1007,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -1037,7 +1041,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -1071,11 +1075,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -1145,18 +1148,18 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "oid-registry" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ "asn1-rs", ] @@ -1193,15 +1196,15 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1209,15 +1212,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.5.4", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -1243,9 +1246,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.3" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", "thiserror", @@ -1254,9 +1257,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.3" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" dependencies = [ "pest", "pest_generator", @@ -1264,22 +1267,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.3" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "pest_meta" -version = "2.7.3" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" dependencies = [ "once_cell", "pest", @@ -1293,7 +1296,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.5.0", ] [[package]] @@ -1326,7 +1329,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -1340,29 +1343,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1431,9 +1434,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" @@ -1446,9 +1452,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", @@ -1482,15 +1488,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1534,39 +1540,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -1616,16 +1613,17 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "ring" -version = "0.17.6" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1644,24 +1642,22 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64 0.21.4", - "bitflags 2.5.0", + "base64 0.21.7", + "bitflags 2.6.0", "serde", "serde_derive", ] [[package]] name = "rsa" -version = "0.9.2" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ - "byteorder", "const-oid", "digest", "num-bigint-dig", "num-integer", - "num-iter", "num-traits", "pkcs1", "pkcs8", @@ -1674,9 +1670,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -1704,9 +1700,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "log", "once_cell", @@ -1719,9 +1715,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -1748,9 +1744,9 @@ checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-platform-verifier" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ "core-foundation", "core-foundation-sys", @@ -1769,15 +1765,15 @@ dependencies = [ [[package]] name = "rustls-platform-verifier-android" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -1786,9 +1782,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1801,11 +1797,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1830,7 +1826,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -1851,11 +1847,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -1865,9 +1861,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -1875,51 +1871,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-pickle" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762ad136a26407c6a80825813600ceeab5e613660d93d79a41f0ec877171e71" -dependencies = [ - "byteorder", - "iter-read", - "num-bigint", - "num-traits", - "serde", -] - -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -1930,14 +1903,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -1951,7 +1924,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "itoa", "ryu", "serde", @@ -1960,9 +1933,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1971,9 +1944,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -2008,11 +1981,17 @@ dependencies = [ "dirs", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", @@ -2060,9 +2039,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -2082,9 +2061,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2099,9 +2078,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -2116,7 +2095,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -2136,22 +2115,22 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -2197,9 +2176,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2221,9 +2200,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -2243,7 +2222,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] @@ -2259,9 +2238,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", @@ -2271,9 +2250,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2286,11 +2265,10 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2299,20 +2277,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2362,9 +2340,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", @@ -2390,9 +2368,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -2422,9 +2400,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" @@ -2437,9 +2415,9 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unsafe-libyaml" @@ -2453,12 +2431,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "unwrap-infallible" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" - [[package]] name = "unzip-n" version = "0.1.2" @@ -2534,15 +2506,15 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2556,34 +2528,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2591,28 +2564,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] @@ -2635,11 +2608,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -2672,7 +2645,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -2707,17 +2689,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2734,9 +2717,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -2752,9 +2735,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -2770,9 +2753,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -2788,9 +2777,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -2806,9 +2795,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -2824,9 +2813,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -2842,9 +2831,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "x509-parser" @@ -2866,7 +2855,7 @@ dependencies = [ [[package]] name = "zenoh" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "ahash", "async-trait", @@ -2875,6 +2864,7 @@ dependencies = [ "futures", "git-version", "itertools", + "json5", "lazy_static", "once_cell", "paste", @@ -2883,16 +2873,12 @@ dependencies = [ "rand", "rustc_version", "serde", - "serde-pickle", - "serde_cbor", "serde_json", - "serde_yaml", "socket2", "tokio", "tokio-util", "tracing", "uhlc", - "unwrap-infallible", "vec_map", "zenoh-buffers", "zenoh-codec", @@ -2915,7 +2901,7 @@ dependencies = [ [[package]] name = "zenoh-buffers" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "zenoh-collections", ] @@ -2923,7 +2909,7 @@ dependencies = [ [[package]] name = "zenoh-codec" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "tracing", "uhlc", @@ -2934,14 +2920,13 @@ dependencies = [ [[package]] name = "zenoh-collections" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" [[package]] name = "zenoh-config" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ - "flume 0.11.0", "json5", "num_cpus", "secrecy", @@ -2961,7 +2946,7 @@ dependencies = [ [[package]] name = "zenoh-core" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "lazy_static", "tokio", @@ -2972,7 +2957,7 @@ dependencies = [ [[package]] name = "zenoh-crypto" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "aes", "hmac", @@ -2985,11 +2970,12 @@ dependencies = [ [[package]] name = "zenoh-ext" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "bincode", "flume 0.11.0", "futures", + "leb128", "serde", "tokio", "tracing", @@ -3001,7 +2987,7 @@ dependencies = [ [[package]] name = "zenoh-keyexpr" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "hashbrown 0.14.5", "keyed-set", @@ -3015,7 +3001,7 @@ dependencies = [ [[package]] name = "zenoh-link" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "zenoh-config", "zenoh-link-commons", @@ -3032,7 +3018,7 @@ dependencies = [ [[package]] name = "zenoh-link-commons" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "flume 0.11.0", @@ -3055,7 +3041,7 @@ dependencies = [ [[package]] name = "zenoh-link-quic" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "base64 0.22.1", @@ -3080,7 +3066,7 @@ dependencies = [ [[package]] name = "zenoh-link-tcp" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "socket2", @@ -3097,7 +3083,7 @@ dependencies = [ [[package]] name = "zenoh-link-tls" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "base64 0.22.1", @@ -3124,7 +3110,7 @@ dependencies = [ [[package]] name = "zenoh-link-udp" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "socket2", @@ -3143,7 +3129,7 @@ dependencies = [ [[package]] name = "zenoh-link-unixsock_stream" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "nix", @@ -3161,7 +3147,7 @@ dependencies = [ [[package]] name = "zenoh-link-ws" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "futures-util", @@ -3181,23 +3167,24 @@ dependencies = [ [[package]] name = "zenoh-macros" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", "zenoh-keyexpr", ] [[package]] name = "zenoh-plugin-trait" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "git-version", "libloading", "serde", "tracing", + "zenoh-config", "zenoh-keyexpr", "zenoh-macros", "zenoh-result", @@ -3207,7 +3194,7 @@ dependencies = [ [[package]] name = "zenoh-protocol" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "const_format", "rand", @@ -3221,7 +3208,7 @@ dependencies = [ [[package]] name = "zenoh-result" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "anyhow", ] @@ -3229,7 +3216,7 @@ dependencies = [ [[package]] name = "zenoh-runtime" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "lazy_static", "ron", @@ -3242,7 +3229,7 @@ dependencies = [ [[package]] name = "zenoh-sync" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "event-listener", "futures", @@ -3255,7 +3242,7 @@ dependencies = [ [[package]] name = "zenoh-task" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "futures", "tokio", @@ -3268,7 +3255,7 @@ dependencies = [ [[package]] name = "zenoh-transport" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "crossbeam-utils", @@ -3301,7 +3288,7 @@ dependencies = [ [[package]] name = "zenoh-util" version = "1.0.0-dev" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#e72e4d46cc21f3eea7d9f25591407d66c96265b7" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#1a4a295098cf4c8d65b252883e9692b8c4dd7d1b" dependencies = [ "async-trait", "const_format", @@ -3334,35 +3321,36 @@ dependencies = [ "jni 0.21.1", "json5", "rustc_version", + "serde_yaml", "tracing", "uhlc", "zenoh", "zenoh-ext", - "zenoh-protocol", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.77", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/zenoh-jni/Cargo.toml b/zenoh-jni/Cargo.toml index c5f62f83..08246e28 100644 --- a/zenoh-jni/Cargo.toml +++ b/zenoh-jni/Cargo.toml @@ -24,7 +24,7 @@ description = "Zenoh: Zero Overhead Pub/sub, Store/Query and Compute." name = "zenoh_jni" [features] -default = ["zenoh/default", "zenoh-ext/default"] +default = ["zenoh/default", "zenoh-ext"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -35,10 +35,10 @@ jni = "0.21.1" flume = "0.10.14" uhlc = "0.8.0" json5 = "0.4.1" -zenoh = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", default-features = false } -zenoh-ext = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", default-features = false } -zenoh-protocol = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", default-features = false } -tracing = "0.1" +serde_yaml = "0.9.19" +zenoh = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = ["unstable", "internal"], default-features = false } +zenoh-ext = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = ["internal"], default-features = false, optional = true } +tracing = { version = "0.1" , features = ["log"] } [lib] name = "zenoh_jni" crate_type = ["staticlib", "dylib"] diff --git a/zenoh-jni/src/config.rs b/zenoh-jni/src/config.rs new file mode 100644 index 00000000..0ada1340 --- /dev/null +++ b/zenoh-jni/src/config.rs @@ -0,0 +1,185 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{ptr::null, sync::Arc}; + +use jni::{ + objects::{JClass, JString}, + sys::jstring, + JNIEnv, +}; +use zenoh::Config; + +use crate::{errors::ZResult, zerror}; +use crate::{throw_exception, utils::decode_string}; + +/// Loads the default configuration, returning a raw pointer to it. +/// +/// The pointer to the config is expected to be freed later on upon the destruction of the +/// Kotlin Config instance. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadDefaultConfigViaJNI( + _env: JNIEnv, + _class: JClass, +) -> *const Config { + let config = Config::default(); + Arc::into_raw(Arc::new(config)) +} + +/// Loads the config from a file, returning a pointer to the loaded config in case of success. +/// In case of failure, an exception is thrown via JNI. +/// +/// The pointer to the config is expected to be freed later on upon the destruction of the +/// Kotlin Config instance. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadConfigFileViaJNI( + mut env: JNIEnv, + _class: JClass, + config_path: JString, +) -> *const Config { + || -> ZResult<*const Config> { + let config_file_path = decode_string(&mut env, &config_path)?; + let config = Config::from_file(config_file_path).map_err(|err| zerror!(err))?; + Ok(Arc::into_raw(Arc::new(config))) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + null() + }) +} + +/// Loads the config from a json/json5 formatted string, returning a pointer to the loaded config +/// in case of success. In case of failure, an exception is thrown via JNI. +/// +/// The pointer to the config is expected to be freed later on upon the destruction of the +/// Kotlin Config instance. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadJsonConfigViaJNI( + mut env: JNIEnv, + _class: JClass, + json_config: JString, +) -> *const Config { + || -> ZResult<*const Config> { + let json_config = decode_string(&mut env, &json_config)?; + let mut deserializer = + json5::Deserializer::from_str(&json_config).map_err(|err| zerror!(err))?; + let config = Config::from_deserializer(&mut deserializer).map_err(|err| match err { + Ok(c) => zerror!("Invalid configuration: {}", c), + Err(e) => zerror!("JSON error: {}", e), + })?; + Ok(Arc::into_raw(Arc::new(config))) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + null() + }) +} + +/// Loads the config from a yaml-formatted string, returning a pointer to the loaded config +/// in case of success. In case of failure, an exception is thrown via JNI. +/// +/// The pointer to the config is expected to be freed later on upon the destruction of the +/// Kotlin Config instance. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadYamlConfigViaJNI( + mut env: JNIEnv, + _class: JClass, + yaml_config: JString, +) -> *const Config { + || -> ZResult<*const Config> { + let yaml_config = decode_string(&mut env, &yaml_config)?; + let deserializer = serde_yaml::Deserializer::from_str(&yaml_config); + let config = Config::from_deserializer(deserializer).map_err(|err| match err { + Ok(c) => zerror!("Invalid configuration: {}", c), + Err(e) => zerror!("YAML error: {}", e), + })?; + Ok(Arc::into_raw(Arc::new(config))) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + null() + }) +} + +/// Returns the json value associated to the provided [key]. May throw an exception in case of failure, which must be handled +/// on the kotlin layer. +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_getJsonViaJNI( + mut env: JNIEnv, + _class: JClass, + cfg_ptr: *const Config, + key: JString, +) -> jstring { + let arc_cfg: Arc = Arc::from_raw(cfg_ptr); + let result = || -> ZResult { + let key = decode_string(&mut env, &key)?; + let json = arc_cfg.get_json(&key).map_err(|err| zerror!(err))?; + let java_json = env.new_string(json).map_err(|err| zerror!(err))?; + Ok(java_json.as_raw()) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + JString::default().as_raw() + }); + std::mem::forget(arc_cfg); + result +} + +/// Inserts a json5 value associated to the provided [key]. May throw an exception in case of failure, which must be handled +/// on the kotlin layer. +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_insertJson5ViaJNI( + mut env: JNIEnv, + _class: JClass, + cfg_ptr: *const Config, + key: JString, + value: JString, +) { + || -> ZResult<()> { + let key = decode_string(&mut env, &key)?; + let value = decode_string(&mut env, &value)?; + let mut config = core::ptr::read(cfg_ptr); + let insert_result = config + .insert_json5(&key, &value) + .map_err(|err| zerror!(err)); + core::ptr::write(cfg_ptr as *mut _, config); + insert_result + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + }) +} + +/// Frees the pointer to the config. The pointer should be valid and should have been obtained through +/// one of the preceding `load` functions. This function should be called upon destruction of the kotlin +/// Config instance. +#[no_mangle] +#[allow(non_snake_case)] +pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_freePtrViaJNI( + _env: JNIEnv, + _: JClass, + config_ptr: *const Config, +) { + Arc::from_raw(config_ptr); +} diff --git a/zenoh-jni/src/errors.rs b/zenoh-jni/src/errors.rs index edca4ab8..23687d4c 100644 --- a/zenoh-jni/src/errors.rs +++ b/zenoh-jni/src/errors.rs @@ -26,71 +26,34 @@ macro_rules! throw_exception { } #[macro_export] -macro_rules! jni_error { +macro_rules! zerror { ($arg:expr) => { - Error::Jni($arg.to_string()) + $crate::errors::ZError($arg.to_string()) }; ($fmt:expr, $($arg:tt)*) => { - Error::Jni(format!($fmt, $($arg)*)) + $crate::errors::ZError(format!($fmt, $($arg)*)) }; } -#[macro_export] -macro_rules! session_error { - ($arg:expr) => { - $crate::errors::Error::Session($arg.to_string()) - }; - ($fmt:expr, $($arg:tt)*) => { - Error::Session(format!($fmt, $($arg)*)) - }; - -} - -#[macro_export] -macro_rules! key_expr_error { - ($arg:expr) => { - Error::KeyExpr($arg.to_string()) - }; - ($fmt:expr, $($arg:tt)*) => { - Error::KeyExpr(format!($fmt, $($arg)*)) - }; -} - -pub(crate) type Result = core::result::Result; +pub(crate) type ZResult = core::result::Result; #[derive(Debug)] -pub(crate) enum Error { - Session(String), - KeyExpr(String), - Jni(String), -} +pub(crate) struct ZError(pub String); -impl fmt::Display for Error { +impl fmt::Display for ZError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::Session(msg) => write!(f, "{}", msg), - Error::KeyExpr(msg) => write!(f, "{}", msg), - Error::Jni(msg) => write!(f, "{}", msg), - } + write!(f, "{}", self.0) } } -impl Error { - fn get_associated_kotlin_exception(&self) -> String { - let class = match self { - Error::Session(_) => "io/zenoh/exceptions/SessionException", - Error::KeyExpr(_) => "io/zenoh/exceptions/KeyExprException", - Error::Jni(_) => "io/zenoh/exceptions/JNIException", - }; - class.to_string() - } +impl ZError { + const KOTLIN_EXCEPTION_NAME: &'static str = "io/zenoh/exceptions/ZError"; - pub fn throw_on_jvm(&self, env: &mut JNIEnv) -> Result<()> { - let exception_name = self.get_associated_kotlin_exception(); + pub fn throw_on_jvm(&self, env: &mut JNIEnv) -> ZResult<()> { let exception_class = env - .find_class(&exception_name) - .map_err(|err| jni_error!("Failed to retrieve exception class: {}", err))?; + .find_class(Self::KOTLIN_EXCEPTION_NAME) + .map_err(|err| zerror!("Failed to retrieve exception class: {}", err))?; env.throw_new(exception_class, self.to_string()) - .map_err(|err| jni_error!("Failed to throw exception: {}", err)) + .map_err(|err| zerror!("Failed to throw exception: {}", err)) } } diff --git a/zenoh-jni/src/key_expr.rs b/zenoh-jni/src/key_expr.rs index b4fd0fe9..06a1b6c6 100644 --- a/zenoh-jni/src/key_expr.rs +++ b/zenoh-jni/src/key_expr.rs @@ -16,14 +16,13 @@ use std::ops::Deref; use std::sync::Arc; use jni::objects::JClass; -use jni::sys::{jboolean, jstring}; +use jni::sys::{jboolean, jint, jstring}; use jni::{objects::JString, JNIEnv}; use zenoh::key_expr::KeyExpr; -use crate::errors::Error; -use crate::errors::Result; +use crate::errors::ZResult; use crate::utils::decode_string; -use crate::{jni_error, key_expr_error, throw_exception}; +use crate::{throw_exception, zerror}; /// Validates the provided `key_expr` to be a valid key expression, returning it back /// in case of success or throwing an exception in case of failure. @@ -40,7 +39,7 @@ pub extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_tryFromViaJNI( _class: JClass, key_expr: JString, ) -> jstring { - decode_key_expr(&mut env, &key_expr) + validate_key_expr(&mut env, &key_expr) .map(|_| **key_expr) .unwrap_or_else(|err| { throw_exception!(env, err); @@ -67,7 +66,7 @@ pub extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_autocanonizeViaJNI .and_then(|key_expr| { env.new_string(key_expr.to_string()) .map(|kexp| kexp.as_raw()) - .map_err(|err| jni_error!(err)) + .map_err(|err| zerror!(err)) }) .unwrap_or_else(|err| { throw_exception!(env, err); @@ -79,9 +78,9 @@ pub extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_autocanonizeViaJNI /// /// # Params: /// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_ptr_1`: String representation of the key expression 1. +/// - `key_expr_str_1`: String representation of the key expression 1. /// - `key_expr_ptr_2`: Pointer to the key expression 2, differs from null only if it's a declared key expr. -/// - `key_expr_ptr_2`: String representation of the key expression 2. +/// - `key_expr_str_2`: String representation of the key expression 2. /// /// # Safety /// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing @@ -99,7 +98,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_intersectsV key_expr_ptr_2: /*nullable*/ *const KeyExpr<'static>, key_expr_str_2: JString, ) -> jboolean { - || -> Result { + || -> ZResult { let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; let key_expr_2 = process_kotlin_key_expr(&mut env, &key_expr_str_2, key_expr_ptr_2)?; Ok(key_expr_1.intersects(&key_expr_2) as jboolean) @@ -114,9 +113,9 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_intersectsV /// /// # Params: /// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_ptr_1`: String representation of the key expression 1. +/// - `key_expr_str_1`: String representation of the key expression 1. /// - `key_expr_ptr_2`: Pointer to the key expression 2, differs from null only if it's a declared key expr. -/// - `key_expr_ptr_2`: String representation of the key expression 2. +/// - `key_expr_str_2`: String representation of the key expression 2. /// /// # Safety /// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing @@ -134,7 +133,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_includesVia key_expr_ptr_2: /*nullable*/ *const KeyExpr<'static>, key_expr_str_2: JString, ) -> jboolean { - || -> Result { + || -> ZResult { let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; let key_expr_2 = process_kotlin_key_expr(&mut env, &key_expr_str_2, key_expr_ptr_2)?; Ok(key_expr_1.includes(&key_expr_2) as jboolean) @@ -145,6 +144,120 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_includesVia }) } +/// Returns the integer representation of the intersection level of the key expression 1 and key expression 2, +/// from the perspective of key expression 1. +/// +/// # Params: +/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. +/// - `key_expr_str_1`: String representation of the key expression 1. +/// - `key_expr_ptr_2`: Pointer to the key expression 2, differs from null only if it's a declared key expr. +/// - `key_expr_str_2`: String representation of the key expression 2. +/// +/// # Safety +/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing +/// key expressions that were declared from a session (in that case the key expression has a pointer associated). +/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers +/// remain valid after the call to this function. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_relationToViaJNI( + mut env: JNIEnv, + _: JClass, + key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, + key_expr_str_1: JString, + key_expr_ptr_2: /*nullable*/ *const KeyExpr<'static>, + key_expr_str_2: JString, +) -> jint { + || -> ZResult { + let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; + let key_expr_2 = process_kotlin_key_expr(&mut env, &key_expr_str_2, key_expr_ptr_2)?; + Ok(key_expr_1.relation_to(&key_expr_2) as jint) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + -1 as jint + }) +} + +/// Joins key expression 1 with key expression 2, where key_expr_2 is a string. Returns the string representation +/// of the result, or throws an exception in case of failure. +/// +/// # Params: +/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. +/// - `key_expr_ptr_1`: String representation of the key expression 1. +/// - `key_expr_2`: String representation of the key expression 2. +/// +/// # Safety +/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing +/// key expressions that were declared from a session (in that case the key expression has a pointer associated). +/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers +/// remain valid after the call to this function. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_joinViaJNI( + mut env: JNIEnv, + _class: JClass, + key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, + key_expr_str_1: JString, + key_expr_2: JString, +) -> jstring { + || -> ZResult { + let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; + let key_expr_2_str = decode_string(&mut env, &key_expr_2)?; + let result = key_expr_1 + .join(key_expr_2_str.as_str()) + .map_err(|err| zerror!(err))?; + env.new_string(result.to_string()) + .map(|kexp| kexp.as_raw()) + .map_err(|err| zerror!(err)) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + JString::default().as_raw() + }) +} + +/// Concats key_expr_1 with key_expr_2, where key_expr_2 is a string. Returns the string representation +/// of the result, or throws an exception in case of failure. +/// +/// # Params: +/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. +/// - `key_expr_ptr_1`: String representation of the key expression 1. +/// - `key_expr_2`: String representation of the key expression 2. +/// +/// # Safety +/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing +/// key expressions that were declared from a session (in that case the key expression has a pointer associated). +/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers +/// remain valid after the call to this function. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_concatViaJNI( + mut env: JNIEnv, + _class: JClass, + key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, + key_expr_str_1: JString, + key_expr_2: JString, +) -> jstring { + || -> ZResult { + let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; + let key_expr_2_str = decode_string(&mut env, &key_expr_2)?; + let result = key_expr_1 + .concat(key_expr_2_str.as_str()) + .map_err(|err| zerror!(err))?; + env.new_string(result.to_string()) + .map(|kexp| kexp.as_raw()) + .map_err(|err| zerror!(err)) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + JString::default().as_raw() + }) +} + /// Frees a declared key expression. /// /// # Parameters @@ -167,20 +280,20 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_freePtrViaJNI( Arc::from_raw(key_expr_ptr); } -fn decode_key_expr(env: &mut JNIEnv, key_expr: &JString) -> Result> { +fn validate_key_expr(env: &mut JNIEnv, key_expr: &JString) -> ZResult> { let key_expr_str = decode_string(env, key_expr) - .map_err(|err| jni_error!("Unable to get key expression string value: '{}'.", err))?; + .map_err(|err| zerror!("Unable to get key expression string value: '{}'.", err))?; KeyExpr::try_from(key_expr_str) - .map_err(|err| key_expr_error!("Unable to create key expression: '{}'.", err)) + .map_err(|err| zerror!("Unable to create key expression: '{}'.", err)) } -fn autocanonize_key_expr(env: &mut JNIEnv, key_expr: &JString) -> Result> { +fn autocanonize_key_expr(env: &mut JNIEnv, key_expr: &JString) -> ZResult> { decode_string(env, key_expr) - .map_err(|err| jni_error!("Unable to get key expression string value: '{}'.", err)) + .map_err(|err| zerror!("Unable to get key expression string value: '{}'.", err)) .and_then(|key_expr_str| { KeyExpr::autocanonize(key_expr_str) - .map_err(|err| key_expr_error!("Unable to create key expression: '{}'", err)) + .map_err(|err| zerror!("Unable to create key expression: '{}'", err)) }) } @@ -192,14 +305,20 @@ fn autocanonize_key_expr(env: &mut JNIEnv, key_expr: &JString) -> Result, -) -> Result> { +) -> ZResult> { if key_expr_ptr.is_null() { - decode_key_expr(env, key_expr_str) - .map_err(|err| jni_error!("Unable to process key expression: '{}'.", err)) + let key_expr = decode_string(env, key_expr_str) + .map_err(|err| zerror!("Unable to get key expression string value: '{}'.", err))?; + Ok(KeyExpr::from_string_unchecked(key_expr)) } else { let key_expr = Arc::from_raw(key_expr_ptr); let key_expr_clone = key_expr.deref().clone(); diff --git a/zenoh-jni/src/lib.rs b/zenoh-jni/src/lib.rs index edfba47a..6661ee55 100644 --- a/zenoh-jni/src/lib.rs +++ b/zenoh-jni/src/lib.rs @@ -12,15 +12,20 @@ // ZettaScale Zenoh Team, // +mod config; mod errors; mod key_expr; mod logger; mod publisher; mod query; mod queryable; +mod scouting; mod session; mod subscriber; mod utils; +#[cfg(feature = "zenoh-ext")] +mod zbytes; +mod zenoh_id; // Test should be runned with `cargo test --no-default-features` #[test] diff --git a/zenoh-jni/src/logger.rs b/zenoh-jni/src/logger.rs index 780e693e..73f5112c 100644 --- a/zenoh-jni/src/logger.rs +++ b/zenoh-jni/src/logger.rs @@ -17,34 +17,32 @@ use jni::{ JNIEnv, }; -use crate::{ - errors::{Error, Result}, - jni_error, throw_exception, -}; +use crate::{errors::ZResult, throw_exception, zerror}; /// Redirects the Rust logs either to logcat for Android systems or to the standard output (for non-Android systems). /// -/// This function is meant to be called from Java/Kotlin code through JNI. It takes a `log_level` -/// indicating the desired log level, which must be one of the following: "info", "debug", "warn", -/// "trace", or "error". +/// This function is meant to be called from Java/Kotlin code through JNI. It takes a `filter` +/// indicating the desired log level. +/// +/// See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format. /// /// # Parameters: /// - `env`: The JNI environment. /// - `_class`: The JNI class. -/// - `log_level`: The log level java string indicating the desired log level. +/// - `filter`: The logs filter. /// /// # Errors: /// - If there is an error parsing the log level string, a `JNIException` is thrown on the JVM. /// #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_Logger_00024Companion_start( +pub extern "C" fn Java_io_zenoh_Logger_00024Companion_startLogsViaJNI( mut env: JNIEnv, _class: JClass, - log_level: JString, + filter: JString, ) { - || -> Result<()> { - let log_level = parse_log_level(&mut env, log_level)?; + || -> ZResult<()> { + let log_level = parse_filter(&mut env, filter)?; android_logd_logger::builder() .parse_filters(log_level.as_str()) .tag_target_strip() @@ -55,10 +53,10 @@ pub extern "C" fn Java_io_zenoh_Logger_00024Companion_start( .unwrap_or_else(|err| throw_exception!(env, err)) } -fn parse_log_level(env: &mut JNIEnv, log_level: JString) -> Result { - let log_level = env.get_string(&log_level).map_err(|err| jni_error!(err))?; +fn parse_filter(env: &mut JNIEnv, log_level: JString) -> ZResult { + let log_level = env.get_string(&log_level).map_err(|err| zerror!(err))?; log_level .to_str() .map(|level| Ok(level.to_string())) - .map_err(|err| jni_error!(err))? + .map_err(|err| zerror!(err))? } diff --git a/zenoh-jni/src/publisher.rs b/zenoh-jni/src/publisher.rs index c6607cd0..ead60c3f 100644 --- a/zenoh-jni/src/publisher.rs +++ b/zenoh-jni/src/publisher.rs @@ -21,11 +21,12 @@ use jni::{ }; use zenoh::{pubsub::Publisher, Wait}; +use crate::throw_exception; use crate::{ - errors::Result, + errors::ZResult, utils::{decode_byte_array, decode_encoding}, + zerror, }; -use crate::{session_error, throw_exception}; /// Performs a PUT operation on a Zenoh publisher via JNI. /// @@ -56,7 +57,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIPublisher_putViaJNI( publisher_ptr: *const Publisher<'static>, ) { let publisher = Arc::from_raw(publisher_ptr); - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let payload = decode_byte_array(&env, payload)?; let mut publication = publisher.put(payload); let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; @@ -65,7 +66,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIPublisher_putViaJNI( let attachment = decode_byte_array(&env, attachment)?; publication = publication.attachment::>(attachment) }; - publication.wait().map_err(|err| session_error!(err)) + publication.wait().map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); std::mem::forget(publisher); @@ -94,13 +95,13 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIPublisher_deleteViaJNI( publisher_ptr: *const Publisher<'static>, ) { let publisher = Arc::from_raw(publisher_ptr); - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let mut delete = publisher.delete(); if !attachment.is_null() { let attachment = decode_byte_array(&env, attachment)?; delete = delete.attachment::>(attachment) }; - delete.wait().map_err(|err| session_error!(err)) + delete.wait().map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); std::mem::forget(publisher) diff --git a/zenoh-jni/src/query.rs b/zenoh-jni/src/query.rs index f7b557ec..031b1d93 100644 --- a/zenoh-jni/src/query.rs +++ b/zenoh-jni/src/query.rs @@ -14,11 +14,9 @@ use std::sync::Arc; -use crate::{errors::Result, key_expr::process_kotlin_key_expr, throw_exception}; -use crate::{ - session_error, - utils::{decode_byte_array, decode_encoding}, -}; +use crate::utils::{decode_byte_array, decode_encoding}; +use crate::zerror; +use crate::{errors::ZResult, key_expr::process_kotlin_key_expr, throw_exception}; use jni::{ objects::{JByteArray, JClass, JString}, sys::{jboolean, jint, jlong}, @@ -27,10 +25,10 @@ use jni::{ use uhlc::ID; use zenoh::{ key_expr::KeyExpr, - prelude::Wait, qos::{CongestionControl, Priority}, query::Query, time::{Timestamp, NTP64}, + Wait, }; /// Replies with `success` to a Zenoh [Query] via JNI, freeing the query in the process. @@ -76,7 +74,7 @@ pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replySuccessViaJNI( qos_priority: jint, qos_congestion_control: jint, ) { - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let query = Arc::from_raw(query_ptr); let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; let payload = decode_byte_array(&env, payload)?; @@ -97,7 +95,7 @@ pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replySuccessViaJNI( } else { reply_builder.congestion_control(CongestionControl::Drop) }; - reply_builder.wait().map_err(|err| session_error!(err)) + reply_builder.wait().map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); } @@ -129,14 +127,14 @@ pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replyErrorViaJNI( encoding_id: jint, encoding_schema: /*nullable*/ JString, ) { - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let query = Arc::from_raw(query_ptr); let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; query .reply_err(decode_byte_array(&env, payload)?) .encoding(encoding) .wait() - .map_err(|err| session_error!(err)) + .map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); } @@ -178,7 +176,7 @@ pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replyDeleteViaJNI( qos_priority: jint, qos_congestion_control: jint, ) { - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let query = Arc::from_raw(query_ptr); let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; let mut reply_builder = query.reply_del(key_expr); @@ -196,7 +194,7 @@ pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replyDeleteViaJNI( } else { reply_builder.congestion_control(CongestionControl::Drop) }; - reply_builder.wait().map_err(|err| session_error!(err)) + reply_builder.wait().map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); } diff --git a/zenoh-jni/src/queryable.rs b/zenoh-jni/src/queryable.rs index 07ed6e1b..5d2ddb1d 100644 --- a/zenoh-jni/src/queryable.rs +++ b/zenoh-jni/src/queryable.rs @@ -35,7 +35,7 @@ use zenoh::query::Queryable; pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQueryable_freePtrViaJNI( _env: JNIEnv, _: JClass, - queryable_ptr: *const Queryable<'_, ()>, + queryable_ptr: *const Queryable<()>, ) { Arc::from_raw(queryable_ptr); } diff --git a/zenoh-jni/src/scouting.rs b/zenoh-jni/src/scouting.rs new file mode 100644 index 00000000..e334e954 --- /dev/null +++ b/zenoh-jni/src/scouting.rs @@ -0,0 +1,109 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{ptr::null, sync::Arc}; + +use jni::{ + objects::{JClass, JList, JObject, JValue}, + sys::jint, + JNIEnv, +}; +use zenoh::{config::WhatAmIMatcher, Wait}; +use zenoh::{scouting::Scout, Config}; + +use crate::utils::{get_callback_global_ref, get_java_vm}; +use crate::{errors::ZResult, throw_exception, zerror}; + +/// Start a scout. +/// +/// # Params +/// - `whatAmI`: Ordinal value of the WhatAmI enum. +/// - `callback`: Callback to be executed whenever a hello message is received. +/// - `config_ptr`: Optional config pointer. +/// +/// Returns a pointer to the scout, which must be freed afterwards. +/// If starting the scout fails, an exception is thrown on the JVM, and a null pointer is returned. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNIScout_00024Companion_scoutViaJNI( + mut env: JNIEnv, + _class: JClass, + whatAmI: jint, + callback: JObject, + config_ptr: /*nullable=*/ *const Config, +) -> *const Scout<()> { + || -> ZResult<*const Scout<()>> { + let callback_global_ref = get_callback_global_ref(&mut env, callback)?; + let java_vm = Arc::new(get_java_vm(&mut env)?); + let whatAmIMatcher: WhatAmIMatcher = (whatAmI as u8).try_into().unwrap(); // The validity of the operation is guaranteed on the kotlin layer. + let config = if config_ptr.is_null() { + Config::default() + } else { + let arc_cfg = Arc::from_raw(config_ptr); + let config_clone = arc_cfg.as_ref().clone(); + std::mem::forget(arc_cfg); + config_clone + }; + zenoh::scout(whatAmIMatcher, config) + .callback(move |hello| { + tracing::debug!("Received hello: {hello}"); + let _ = || -> jni::errors::Result<()> { + let mut env = java_vm.attach_current_thread_as_daemon()?; + let whatami = hello.whatami() as jint; + let zenoh_id = env + .byte_array_from_slice(&hello.zid().to_le_bytes()) + .map(|it| env.auto_local(it))?; + let locators = env + .new_object("java/util/ArrayList", "()V", &[]) + .map(|it| env.auto_local(it))?; + let jlist = JList::from_env(&mut env, &locators)?; + for value in hello.locators() { + let locator = env.new_string(value.as_str())?; + jlist.add(&mut env, &locator)?; + } + env.call_method( + &callback_global_ref, + "run", + "(I[BLjava/util/List;)V", + &[ + JValue::from(whatami), + JValue::from(&zenoh_id), + JValue::from(&locators), + ], + )?; + Ok(()) + }() + .map_err(|err| tracing::error!("Error while scouting: ${err}")); + }) + .wait() + .map(|scout| Arc::into_raw(Arc::new(scout))) + .map_err(|err| zerror!(err)) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + null() + }) +} + +/// Frees the scout. +#[no_mangle] +#[allow(non_snake_case)] +pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIScout_00024Companion_freePtrViaJNI( + _env: JNIEnv, + _: JClass, + scout_ptr: *const Scout<()>, +) { + Arc::from_raw(scout_ptr); +} diff --git a/zenoh-jni/src/session.rs b/zenoh-jni/src/session.rs index 9240d82a..4521fe4b 100644 --- a/zenoh-jni/src/session.rs +++ b/zenoh-jni/src/session.rs @@ -12,26 +12,26 @@ // ZettaScale Zenoh Team, // -use crate::errors::{Error, Result}; -use crate::key_expr::process_kotlin_key_expr; -use crate::{jni_error, utils::*}; -use crate::{session_error, throw_exception}; - -use jni::objects::{GlobalRef, JByteArray, JClass, JObject, JString, JValue}; -use jni::sys::{jboolean, jint, jlong}; -use jni::JNIEnv; -use std::mem; -use std::ops::Deref; -use std::ptr::null; -use std::sync::Arc; -use std::time::Duration; -use zenoh::config::{Config, ZenohId}; -use zenoh::key_expr::KeyExpr; -use zenoh::prelude::Wait; -use zenoh::pubsub::{Publisher, Subscriber}; -use zenoh::query::{Query, Queryable, ReplyError, Selector}; -use zenoh::sample::Sample; -use zenoh::session::{Session, SessionDeclarations}; +use std::{mem, ops::Deref, ptr::null, sync::Arc, time::Duration}; + +use jni::{ + objects::{GlobalRef, JByteArray, JClass, JList, JObject, JString, JValue}, + sys::{jboolean, jbyteArray, jint, jlong, jobject}, + JNIEnv, +}; +use zenoh::{ + config::Config, + key_expr::KeyExpr, + pubsub::{Publisher, Subscriber}, + query::{Query, Queryable, ReplyError, Selector}, + sample::Sample, + session::{Session, ZenohId}, + Wait, +}; + +use crate::{ + errors::ZResult, key_expr::process_kotlin_key_expr, throw_exception, utils::*, zerror, +}; /// Open a Zenoh session via JNI. /// @@ -48,17 +48,17 @@ use zenoh::session::{Session, SessionDeclarations}; /// #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionViaJNI( +pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_openSessionViaJNI( mut env: JNIEnv, _class: JClass, - config_path: /*nullable*/ JString, + config_ptr: *const Config, ) -> *const Session { - let session = open_session(&mut env, config_path); + let session = open_session(config_ptr); match session { Ok(session) => Arc::into_raw(Arc::new(session)), Err(err) => { tracing::error!("Unable to open session: {}", err); - throw_exception!(env, session_error!(err)); + throw_exception!(env, zerror!(err)); null() } } @@ -68,16 +68,13 @@ pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionViaJNI( /// /// If the config path provided is null then the default configuration is loaded. /// -fn open_session(env: &mut JNIEnv, config_path: JString) -> Result { - let config = if config_path.is_null() { - Config::default() - } else { - let config_file_path = decode_string(env, &config_path)?; - Config::from_file(config_file_path).map_err(|err| session_error!(err))? - }; - zenoh::open(config) +unsafe fn open_session(config_ptr: *const Config) -> ZResult { + let config = Arc::from_raw(config_ptr); + let result = zenoh::open(config.as_ref().clone()) .wait() - .map_err(|err| session_error!(err)) + .map_err(|err| zerror!(err)); + mem::forget(config); + result } /// Open a Zenoh session with a JSON configuration. @@ -91,7 +88,7 @@ fn open_session(env: &mut JNIEnv, config_path: JString) -> Result { /// # Parameters: /// - `env`: The JNI environment. /// - `_class`: The JNI class (parameter required by the JNI interface but unused). -/// - `json_config`: Nullable configuration as a JSON string. If null, the default configuration will be loaded. +/// - `json_config`: Configuration as a JSON string. /// #[no_mangle] #[allow(non_snake_case)] @@ -105,7 +102,7 @@ pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionWithJsonConfigViaJNI( Ok(session) => Arc::into_raw(Arc::new(session)), Err(err) => { tracing::error!("Unable to open session: {}", err); - throw_exception!(env, session_error!(err)); + throw_exception!(env, zerror!(err)); null() } } @@ -113,23 +110,58 @@ pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionWithJsonConfigViaJNI( /// Open a Zenoh session with the provided json configuration. /// -/// If the provided json config is null, then the default config is loaded. +fn open_session_with_json_config(env: &mut JNIEnv, json_config: JString) -> ZResult { + let json_config = decode_string(env, &json_config)?; + let mut deserializer = + json5::Deserializer::from_str(&json_config).map_err(|err| zerror!(err))?; + let config = Config::from_deserializer(&mut deserializer).map_err(|err| match err { + Ok(c) => zerror!("Invalid configuration: {}", c), + Err(e) => zerror!("JSON error: {}", e), + })?; + zenoh::open(config).wait().map_err(|err| zerror!(err)) +} + +/// Open a Zenoh session with a YAML configuration. /// -fn open_session_with_json_config(env: &mut JNIEnv, json_config: JString) -> Result { - let config = if json_config.is_null() { - Config::default() - } else { - let json_config = decode_string(env, &json_config)?; - let mut deserializer = - json5::Deserializer::from_str(&json_config).map_err(|err| session_error!(err))?; - Config::from_deserializer(&mut deserializer).map_err(|err| match err { - Ok(c) => session_error!("Invalid configuration: {}", c), - Err(e) => session_error!("JSON error: {}", e), - })? - }; - zenoh::open(config) - .wait() - .map_err(|err| session_error!(err)) +/// It returns an [Arc] raw pointer to the Zenoh Session, which should be stored as a private read-only attribute +/// of the session object in the Java/Kotlin code. Subsequent calls to other session functions will require +/// this raw pointer to retrieve the [Session] using `Arc::from_raw`. +/// +/// If opening the session fails, an exception is thrown on the JVM, and a null pointer is returned. +/// +/// # Parameters: +/// - `env`: The JNI environment. +/// - `_class`: The JNI class (parameter required by the JNI interface but unused). +/// - `yaml_config`: Configuration as a YAML string. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionWithYamlConfigViaJNI( + mut env: JNIEnv, + _class: JClass, + yaml_config: JString, +) -> *const Session { + let session = open_session_with_yaml_config(&mut env, yaml_config); + match session { + Ok(session) => Arc::into_raw(Arc::new(session)), + Err(err) => { + tracing::error!("Unable to open session: {}", err); + throw_exception!(env, zerror!(err)); + null() + } + } +} + +/// Open a Zenoh session with the provided yaml configuration. +/// +fn open_session_with_yaml_config(env: &mut JNIEnv, yaml_config: JString) -> ZResult { + let yaml_config = decode_string(env, &yaml_config)?; + let deserializer = serde_yaml::Deserializer::from_str(&yaml_config); + let config = Config::from_deserializer(deserializer).map_err(|err| match err { + Ok(c) => zerror!("Invalid configuration: {}", c), + Err(e) => zerror!("YAML error: {}", e), + })?; + zenoh::open(config).wait().map_err(|err| zerror!(err)) } /// Closes a Zenoh session via JNI. @@ -152,21 +184,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_closeSessionViaJNI( _class: JClass, session_ptr: *const Session, ) { - let ptr = Arc::try_unwrap(Arc::from_raw(session_ptr)); - match ptr { - Ok(session) => { - // Do nothing, the pointer will be freed. - } - Err(arc_session) => { - let ref_count = Arc::strong_count(&arc_session); - throw_exception!(env, session_error!( - "Attempted to close the session, but at least one strong reference to it is still alive - (ref count: {}). All the declared publishers, subscribers, and queryables need to be - dropped first.", - ref_count - )); - } - }; + Arc::from_raw(session_ptr); } /// Declare a Zenoh publisher via JNI. @@ -182,6 +200,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_closeSessionViaJNI( /// - `congestion_control`: The [zenoh::publisher::CongestionControl] configuration as an ordinal. /// - `priority`: The [zenoh::core::Priority] configuration as an ordinal. /// - `is_express`: The express config of the publisher (see [zenoh::prelude::QoSBuilderTrait]). +/// - `reliability`: The reliability value as an ordinal. /// /// # Returns: /// - A raw pointer to the declared Zenoh publisher or null in case of failure. @@ -204,21 +223,24 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declarePublisherViaJNI( congestion_control: jint, priority: jint, is_express: jboolean, + reliability: jint, ) -> *const Publisher<'static> { let session = Arc::from_raw(session_ptr); - let publisher_ptr = || -> Result<*const Publisher<'static>> { + let publisher_ptr = || -> ZResult<*const Publisher<'static>> { let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; let congestion_control = decode_congestion_control(congestion_control)?; let priority = decode_priority(priority)?; + let reliability = decode_reliability(reliability)?; let result = session .declare_publisher(key_expr) .congestion_control(congestion_control) .priority(priority) .express(is_express != 0) + .reliability(reliability) .wait(); match result { Ok(publisher) => Ok(Arc::into_raw(Arc::new(publisher))), - Err(err) => Err(session_error!(err)), + Err(err) => Err(zerror!(err)), } }() .unwrap_or_else(|err| { @@ -246,6 +268,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declarePublisherViaJNI( /// - `priority`: The [Priority] mechanism specified. /// - `is_express`: The express flag. /// - `attachment`: Optional attachment encoded into a byte array. May be null. +/// - `reliability`: The reliability value as an ordinal. /// /// Safety: /// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. @@ -269,21 +292,24 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_putViaJNI( priority: jint, is_express: jboolean, attachment: JByteArray, + reliability: jint, ) { let session = Arc::from_raw(session_ptr); - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; let payload = decode_byte_array(&env, payload)?; let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; let congestion_control = decode_congestion_control(congestion_control)?; let priority = decode_priority(priority)?; + let reliability = decode_reliability(reliability)?; let mut put_builder = session .put(&key_expr, payload) .congestion_control(congestion_control) .encoding(encoding) .express(is_express != 0) - .priority(priority); + .priority(priority) + .reliability(reliability); if !attachment.is_null() { let attachment = decode_byte_array(&env, attachment)?; @@ -293,7 +319,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_putViaJNI( put_builder .wait() .map(|_| tracing::trace!("Put on '{key_expr}'")) - .map_err(|err| session_error!(err)) + .map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); std::mem::forget(session); @@ -313,6 +339,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_putViaJNI( /// - `priority`: The [Priority] mechanism specified. /// - `is_express`: The express flag. /// - `attachment`: Optional attachment encoded into a byte array. May be null. +/// - `reliability`: The reliability value as an ordinal. /// /// Safety: /// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. @@ -334,18 +361,21 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_deleteViaJNI( priority: jint, is_express: jboolean, attachment: JByteArray, + reliability: jint, ) { let session = Arc::from_raw(session_ptr); - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; let congestion_control = decode_congestion_control(congestion_control)?; let priority = decode_priority(priority)?; + let reliability = decode_reliability(reliability)?; let mut delete_builder = session .delete(&key_expr) .congestion_control(congestion_control) .express(is_express != 0) - .priority(priority); + .priority(priority) + .reliability(reliability); if !attachment.is_null() { let attachment = decode_byte_array(&env, attachment)?; @@ -355,7 +385,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_deleteViaJNI( delete_builder .wait() .map(|_| tracing::trace!("Delete on '{key_expr}'")) - .map_err(|err| session_error!(err)) + .map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); std::mem::forget(session); @@ -373,7 +403,6 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_deleteViaJNI( /// - `session_ptr`: The raw pointer to the Zenoh session. /// - `callback`: The callback function as an instance of the `JNISubscriberCallback` interface in Java/Kotlin. /// - `on_close`: A Java/Kotlin `JNIOnCloseCallback` function interface to be called upon closing the subscriber. -/// - `reliability`: The reliability value as an ordinal. /// /// Returns: /// - A raw pointer to the declared Zenoh subscriber. In case of failure, an exception is thrown and null is returned. @@ -397,14 +426,12 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareSubscriberViaJNI( session_ptr: *const Session, callback: JObject, on_close: JObject, - reliability: jint, -) -> *const Subscriber<'static, ()> { +) -> *const Subscriber<()> { let session = Arc::from_raw(session_ptr); - || -> Result<*const Subscriber<'static, ()>> { + || -> ZResult<*const Subscriber<()>> { let java_vm = Arc::new(get_java_vm(&mut env)?); let callback_global_ref = get_callback_global_ref(&mut env, callback)?; let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let reliability = decode_reliability(reliability)?; let on_close = load_on_close(&java_vm, on_close_global_ref); let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; @@ -412,11 +439,11 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareSubscriberViaJNI( let result = session .declare_subscriber(key_expr.to_owned()) - .callback(move |sample| { + .callback(move |sample: Sample| { on_close.noop(); // Moves `on_close` inside the closure so it gets destroyed with the closure - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - jni_error!("Unable to attach thread for subscriber: {}", err) + zerror!("Unable to attach thread for subscriber: {}", err) })?; let byte_array = bytes_to_java_array(&env, sample.payload()) .map(|array| env.auto_local(array))?; @@ -439,12 +466,12 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareSubscriberViaJNI( |attachment| bytes_to_java_array(&env, attachment), ) .map(|array| env.auto_local(array)) - .map_err(|err| jni_error!("Error processing attachment: {}", err))?; + .map_err(|err| zerror!("Error processing attachment: {}", err))?; - let key_expr_str = - env.auto_local(env.new_string(sample.key_expr().to_string()).map_err( - |err| jni_error!("Error processing sample key expr: {}", err), - )?); + let key_expr_str = env.auto_local( + env.new_string(sample.key_expr().to_string()) + .map_err(|err| zerror!("Error processing sample key expr: {}", err))?, + ); let express = sample.express(); let priority = sample.priority() as jint; @@ -468,22 +495,16 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareSubscriberViaJNI( JValue::from(cc), ], ) - .map_err(|err| jni_error!(err))?; + .map_err(|err| zerror!(err))?; Ok(()) }() .map_err(|err| tracing::error!("On subscriber callback error: {err}")); }) - .reliability(reliability) .wait(); - let subscriber = - result.map_err(|err| session_error!("Unable to declare subscriber: {}", err))?; + let subscriber = result.map_err(|err| zerror!("Unable to declare subscriber: {}", err))?; - tracing::debug!( - "Subscriber declared on '{}' with reliability '{:?}'.", - key_expr, - reliability - ); + tracing::debug!("Subscriber declared on '{}'.", key_expr); std::mem::forget(session); Ok(Arc::into_raw(Arc::new(subscriber))) }() @@ -532,9 +553,9 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareQueryableViaJNI( callback: JObject, on_close: JObject, complete: jboolean, -) -> *const Queryable<'static, ()> { +) -> *const Queryable<()> { let session = Arc::from_raw(session_ptr); - let query_ptr = || -> Result<*const Queryable<'static, ()>> { + let query_ptr = || -> ZResult<*const Queryable<()>> { let java_vm = Arc::new(get_java_vm(&mut env)?); let callback_global_ref = get_callback_global_ref(&mut env, callback)?; let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; @@ -544,7 +565,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareQueryableViaJNI( tracing::debug!("Declaring queryable through JNI on {}", key_expr); let builder = session .declare_queryable(key_expr) - .callback(move |query| { + .callback(move |query: Query| { on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure let env = match java_vm.attach_current_thread_as_daemon() { Ok(env) => env, @@ -564,7 +585,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareQueryableViaJNI( let queryable = builder .wait() - .map_err(|err| session_error!("Error declaring queryable: {}", err))?; + .map_err(|err| zerror!("Error declaring queryable: {}", err))?; Ok(Arc::into_raw(Arc::new(queryable))) }() .unwrap_or_else(|err| { @@ -575,19 +596,18 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareQueryableViaJNI( query_ptr } -fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> Result<()> { +fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> ZResult<()> { let selector_params_jstr = env .new_string(query.parameters().to_string()) .map(|value| env.auto_local(value)) .map_err(|err| { - jni_error!( + zerror!( "Could not create a JString through JNI for the Query key expression. {}", err ) })?; - let (with_value, payload, encoding_id, encoding_schema) = if let Some(payload) = query.payload() - { + let (payload, encoding_id, encoding_schema) = if let Some(payload) = query.payload() { let encoding = query.encoding().unwrap(); //If there is payload, there is encoding. let encoding_id = encoding.id() as jint; let encoding_schema = encoding @@ -598,10 +618,9 @@ fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> R ) .map(|value| env.auto_local(value))?; let byte_array = bytes_to_java_array(&env, payload).map(|value| env.auto_local(value))?; - (true, byte_array, encoding_id, encoding_schema) + (byte_array, encoding_id, encoding_schema) } else { ( - false, env.auto_local(JByteArray::default()), 0, env.auto_local(JString::default()), @@ -615,13 +634,13 @@ fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> R |attachment| bytes_to_java_array(&env, attachment), ) .map(|value| env.auto_local(value)) - .map_err(|err| jni_error!("Error processing attachment of reply: {}.", err))?; + .map_err(|err| zerror!("Error processing attachment of reply: {}.", err))?; let key_expr_str = env .new_string(&query.key_expr().to_string()) .map(|key_expr| env.auto_local(key_expr)) .map_err(|err| { - jni_error!( + zerror!( "Could not create a JString through JNI for the Query key expression: {}.", err ) @@ -633,11 +652,10 @@ fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> R .call_method( callback_global_ref, "run", - "(Ljava/lang/String;Ljava/lang/String;Z[BILjava/lang/String;[BJ)V", + "(Ljava/lang/String;Ljava/lang/String;[BILjava/lang/String;[BJ)V", &[ JValue::from(&key_expr_str), JValue::from(&selector_params_jstr), - JValue::from(with_value), JValue::from(&payload), JValue::from(encoding_id), JValue::from(&encoding_schema), @@ -655,7 +673,7 @@ fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> R Arc::from_raw(query_ptr); }; _ = env.exception_describe(); - jni_error!(err) + zerror!(err) }); result } @@ -687,13 +705,13 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareKeyExprViaJNI( key_expr_str: JString, ) -> *const KeyExpr<'static> { let session: Arc = Arc::from_raw(session_ptr); - let key_expr_ptr = || -> Result<*const KeyExpr<'static>> { + let key_expr_ptr = || -> ZResult<*const KeyExpr<'static>> { let key_expr_str = decode_string(&mut env, &key_expr_str)?; let key_expr = session .declare_keyexpr(key_expr_str.to_owned()) .wait() .map_err(|err| { - session_error!( + zerror!( "Unable to declare key expression '{}': {}", key_expr_str, err @@ -745,7 +763,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_undeclareKeyExprViaJNI( Err(err) => { throw_exception!( env, - session_error!("Unable to declare key expression '{}': {}", key_expr, err) + zerror!("Unable to declare key expression '{}': {}", key_expr, err) ); } } @@ -762,7 +780,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_undeclareKeyExprViaJNI( /// of using a non declared key expression, in which case the `key_expr_str` parameter will be used instead. /// - `key_expr_str`: String representation of the key expression to be used to declare the query. It is not /// considered if a `key_expr_ptr` is provided. -/// - `selector_params`: Parameters of the selector. +/// - `selector_params`: Optional parameters of the selector. /// - `session_ptr`: A raw pointer to the Zenoh [Session]. /// - `callback`: A Java/Kotlin callback to be called upon receiving a reply. /// - `on_close`: A Java/Kotlin `JNIOnCloseCallback` function interface to be called when no more replies will be received. @@ -770,11 +788,9 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_undeclareKeyExprViaJNI( /// - `target`: The query target as the ordinal of the enum. /// - `consolidation`: The consolidation mode as the ordinal of the enum. /// - `attachment`: An optional attachment encoded into a byte array. -/// - `with_value`: Boolean value to tell if a value must be included in the get operation. If true, -/// then the next params are valid. -/// - `payload`: The payload of the value. -/// - `encoding_id`: The encoding of the value payload. -/// - `encoding_schema`: The encoding schema of the value payload, may be null. +/// - `payload`: Optional payload for the query. +/// - `encoding_id`: The encoding of the payload. +/// - `encoding_schema`: The encoding schema of the payload, may be null. /// /// Safety: /// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. @@ -793,7 +809,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getViaJNI( _class: JClass, key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, key_expr_str: JString, - selector_params: JString, + selector_params: /*nullable*/ JString, session_ptr: *const Session, callback: JObject, on_close: JObject, @@ -801,31 +817,34 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getViaJNI( target: jint, consolidation: jint, attachment: /*nullable*/ JByteArray, - with_value: jboolean, payload: /*nullable*/ JByteArray, encoding_id: jint, encoding_schema: /*nullable*/ JString, ) { let session = Arc::from_raw(session_ptr); - let _ = || -> Result<()> { + let _ = || -> ZResult<()> { let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; let java_vm = Arc::new(get_java_vm(&mut env)?); let callback_global_ref = get_callback_global_ref(&mut env, callback)?; let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; let query_target = decode_query_target(target)?; let consolidation = decode_consolidation(consolidation)?; - let selector_params = decode_string(&mut env, &selector_params)?; let timeout = Duration::from_millis(timeout_ms as u64); let on_close = load_on_close(&java_vm, on_close_global_ref); - let selector = Selector::owned(&key_expr, &*selector_params); + let selector_params = if selector_params.is_null() { + String::new() + } else { + decode_string(&mut env, &selector_params)? + }; + let selector = Selector::owned(&key_expr, selector_params); let mut get_builder = session .get(selector) .callback(move |reply| { - || -> Result<()> { + || -> ZResult<()> { on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure tracing::debug!("Receiving reply through JNI: {:?}", reply); let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - jni_error!("Unable to attach thread for GET query callback: {}.", err) + zerror!("Unable to attach thread for GET query callback: {}.", err) })?; match reply.result() { @@ -849,7 +868,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getViaJNI( .timeout(timeout) .consolidation(consolidation); - if with_value != 0 { + if !payload.is_null() { let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; get_builder = get_builder.encoding(encoding); get_builder = get_builder.payload(decode_byte_array(&env, payload)?); @@ -863,7 +882,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getViaJNI( get_builder .wait() .map(|_| tracing::trace!("Performing get on '{key_expr}'.",)) - .map_err(|err| session_error!(err)) + .map_err(|err| zerror!(err)) }() .map_err(|err| throw_exception!(env, err)); std::mem::forget(session); @@ -874,13 +893,13 @@ fn on_reply_success( replier_id: Option, sample: &Sample, callback_global_ref: &GlobalRef, -) -> Result<()> { +) -> ZResult<()> { let zenoh_id = replier_id .map_or_else( - || Ok(JString::default()), + || Ok(JByteArray::default()), |replier_id| { - env.new_string(replier_id.to_string()) - .map_err(|err| jni_error!(err)) + env.byte_array_from_slice(&replier_id.to_le_bytes()) + .map_err(|err| zerror!(err)) }, ) .map(|value| env.auto_local(value))?; @@ -910,13 +929,13 @@ fn on_reply_success( |attachment| bytes_to_java_array(env, attachment), ) .map(|value| env.auto_local(value)) - .map_err(|err| jni_error!("Error processing attachment of reply: {}.", err))?; + .map_err(|err| zerror!("Error processing attachment of reply: {}.", err))?; let key_expr_str = env .new_string(sample.key_expr().to_string()) .map(|value| env.auto_local(value)) .map_err(|err| { - jni_error!( + zerror!( "Could not create a JString through JNI for the Sample key expression. {}", err ) @@ -929,7 +948,7 @@ fn on_reply_success( let result = match env.call_method( callback_global_ref, "run", - "(Ljava/lang/String;ZLjava/lang/String;[BILjava/lang/String;IJZ[BZII)V", + "([BZLjava/lang/String;[BILjava/lang/String;IJZ[BZII)V", &[ JValue::from(&zenoh_id), JValue::from(true), @@ -949,7 +968,7 @@ fn on_reply_success( Ok(_) => Ok(()), Err(err) => { _ = env.exception_describe(); - Err(jni_error!("On GET callback error: {}", err)) + Err(zerror!("On GET callback error: {}", err)) } }; result @@ -960,13 +979,13 @@ fn on_reply_error( replier_id: Option, reply_error: &ReplyError, callback_global_ref: &GlobalRef, -) -> Result<()> { +) -> ZResult<()> { let zenoh_id = replier_id .map_or_else( - || Ok(JString::default()), + || Ok(JByteArray::default()), |replier_id| { - env.new_string(replier_id.to_string()) - .map_err(|err| jni_error!(err)) + env.byte_array_from_slice(&replier_id.to_le_bytes()) + .map_err(|err| zerror!(err)) }, ) .map(|value| env.auto_local(value))?; @@ -985,7 +1004,7 @@ fn on_reply_error( let result = match env.call_method( callback_global_ref, "run", - "(Ljava/lang/String;ZLjava/lang/String;[BILjava/lang/String;IJZ[BZII)V", + "([BZLjava/lang/String;[BILjava/lang/String;IJZ[BZII)V", &[ JValue::from(&zenoh_id), JValue::from(false), @@ -1006,8 +1025,87 @@ fn on_reply_error( Ok(_) => Ok(()), Err(err) => { _ = env.exception_describe(); - Err(jni_error!("On GET callback error: {}", err)) + Err(zerror!("On GET callback error: {}", err)) } }; result } + +/// Returns a list of zenoh ids as byte arrays corresponding to the peers connected to the session provided. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getPeersZidViaJNI( + mut env: JNIEnv, + _class: JClass, + session_ptr: *const Session, +) -> jobject { + let session = Arc::from_raw(session_ptr); + let ids = { + let peers_zid = session.info().peers_zid().wait(); + let ids = peers_zid.collect::>(); + ids_to_java_list(&mut env, ids).map_err(|err| zerror!(err)) + } + .unwrap_or_else(|err| { + throw_exception!(env, err); + JObject::default().as_raw() + }); + std::mem::forget(session); + ids +} + +/// Returns a list of zenoh ids as byte arrays corresponding to the routers connected to the session provided. +/// +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getRoutersZidViaJNI( + mut env: JNIEnv, + _class: JClass, + session_ptr: *const Session, +) -> jobject { + let session = Arc::from_raw(session_ptr); + let ids = { + let peers_zid = session.info().routers_zid().wait(); + let ids = peers_zid.collect::>(); + ids_to_java_list(&mut env, ids).map_err(|err| zerror!(err)) + } + .unwrap_or_else(|err| { + throw_exception!(env, err); + JObject::default().as_raw() + }); + std::mem::forget(session); + ids +} + +/// Returns the Zenoh ID as a byte array of the session. +#[no_mangle] +#[allow(non_snake_case)] +pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getZidViaJNI( + mut env: JNIEnv, + _class: JClass, + session_ptr: *const Session, +) -> jbyteArray { + let session = Arc::from_raw(session_ptr); + let ids = { + let zid = session.info().zid().wait(); + env.byte_array_from_slice(&zid.to_le_bytes()) + .map(|x| x.as_raw()) + .map_err(|err| zerror!(err)) + } + .unwrap_or_else(|err| { + throw_exception!(env, err); + JByteArray::default().as_raw() + }); + std::mem::forget(session); + ids +} + +fn ids_to_java_list(env: &mut JNIEnv, ids: Vec) -> jni::errors::Result { + let array_list = env.new_object("java/util/ArrayList", "()V", &[])?; + let jlist = JList::from_env(env, &array_list)?; + for id in ids { + let value = &mut env.byte_array_from_slice(&id.to_le_bytes())?; + jlist.add(env, value)?; + } + Ok(array_list.as_raw()) +} diff --git a/zenoh-jni/src/utils.rs b/zenoh-jni/src/utils.rs index 96c705f9..aa8d0176 100644 --- a/zenoh-jni/src/utils.rs +++ b/zenoh-jni/src/utils.rs @@ -14,10 +14,7 @@ use std::sync::Arc; -use crate::{ - errors::{Error, Result}, - jni_error, session_error, throw_exception, -}; +use crate::{errors::ZResult, throw_exception, zerror}; use jni::{ objects::{JByteArray, JObject, JString}, sys::jint, @@ -26,19 +23,18 @@ use jni::{ use zenoh::{ bytes::{Encoding, ZBytes}, internal::buffers::ZSlice, - pubsub::Reliability, - qos::{CongestionControl, Priority}, + qos::{CongestionControl, Priority, Reliability}, query::{ConsolidationMode, QueryTarget}, }; /// Converts a JString into a rust String. -pub(crate) fn decode_string(env: &mut JNIEnv, string: &JString) -> Result { +pub(crate) fn decode_string(env: &mut JNIEnv, string: &JString) -> ZResult { let binding = env .get_string(string) - .map_err(|err| jni_error!("Error while retrieving JString: {}", err))?; + .map_err(|err| zerror!("Error while retrieving JString: {}", err))?; let value = binding .to_str() - .map_err(|err| jni_error!("Error decoding JString: {}", err))?; + .map_err(|err| zerror!("Error decoding JString: {}", err))?; Ok(value.to_string()) } @@ -46,99 +42,93 @@ pub(crate) fn decode_encoding( env: &mut JNIEnv, encoding: jint, schema: &JString, -) -> Result { +) -> ZResult { let schema: Option = if schema.is_null() { None } else { Some(decode_string(env, schema)?.into_bytes().into()) }; let encoding_id = - u16::try_from(encoding).map_err(|err| jni_error!("Failed to decode encoding: {}", err))?; + u16::try_from(encoding).map_err(|err| zerror!("Failed to decode encoding: {}", err))?; Ok(Encoding::new(encoding_id, schema)) } -pub(crate) fn get_java_vm(env: &mut JNIEnv) -> Result { +pub(crate) fn get_java_vm(env: &mut JNIEnv) -> ZResult { env.get_java_vm() - .map_err(|err| jni_error!("Unable to retrieve JVM reference: {}", err)) + .map_err(|err| zerror!("Unable to retrieve JVM reference: {}", err)) } pub(crate) fn get_callback_global_ref( env: &mut JNIEnv, callback: JObject, -) -> crate::errors::Result { +) -> crate::errors::ZResult { env.new_global_ref(callback) - .map_err(|err| jni_error!("Unable to get reference to the provided callback: {}", err)) + .map_err(|err| zerror!("Unable to get reference to the provided callback: {}", err)) } /// Helper function to convert a JByteArray into a Vec. -pub(crate) fn decode_byte_array(env: &JNIEnv<'_>, payload: JByteArray) -> Result> { +pub(crate) fn decode_byte_array(env: &JNIEnv<'_>, payload: JByteArray) -> ZResult> { let payload_len = env .get_array_length(&payload) .map(|length| length as usize) - .map_err(|err| jni_error!(err))?; + .map_err(|err| zerror!(err))?; let mut buff = vec![0; payload_len]; env.get_byte_array_region(payload, 0, &mut buff[..]) - .map_err(|err| jni_error!(err))?; + .map_err(|err| zerror!(err))?; let buff: Vec = unsafe { std::mem::transmute::, Vec>(buff) }; Ok(buff) } -pub(crate) fn decode_priority(priority: jint) -> Result { - Priority::try_from(priority as u8) - .map_err(|err| session_error!("Error retrieving priority: {}.", err)) +pub(crate) fn decode_priority(priority: jint) -> ZResult { + Priority::try_from(priority as u8).map_err(|err| zerror!("Error retrieving priority: {}.", err)) } -pub(crate) fn decode_congestion_control(congestion_control: jint) -> Result { +pub(crate) fn decode_congestion_control(congestion_control: jint) -> ZResult { match congestion_control { 1 => Ok(CongestionControl::Block), 0 => Ok(CongestionControl::Drop), - value => Err(session_error!("Unknown congestion control '{}'.", value)), + value => Err(zerror!("Unknown congestion control '{}'.", value)), } } -pub(crate) fn decode_query_target(target: jint) -> Result { +pub(crate) fn decode_query_target(target: jint) -> ZResult { match target { 0 => Ok(QueryTarget::BestMatching), 1 => Ok(QueryTarget::All), 2 => Ok(QueryTarget::AllComplete), - value => Err(session_error!("Unable to decode QueryTarget '{}'.", value)), + value => Err(zerror!("Unable to decode QueryTarget '{}'.", value)), } } -pub(crate) fn decode_consolidation(consolidation: jint) -> Result { +pub(crate) fn decode_consolidation(consolidation: jint) -> ZResult { match consolidation { 0 => Ok(ConsolidationMode::Auto), 1 => Ok(ConsolidationMode::None), 2 => Ok(ConsolidationMode::Monotonic), 3 => Ok(ConsolidationMode::Latest), - value => Err(session_error!("Unable to decode consolidation '{}'", value)), + value => Err(zerror!("Unable to decode consolidation '{}'", value)), } } -pub(crate) fn decode_reliability(reliability: jint) -> Result { +pub(crate) fn decode_reliability(reliability: jint) -> ZResult { match reliability { 0 => Ok(Reliability::BestEffort), 1 => Ok(Reliability::Reliable), - value => Err(session_error!("Unable to decode reliability '{}'", value)), + value => Err(zerror!("Unable to decode reliability '{}'", value)), } } -pub(crate) fn bytes_to_java_array<'a>(env: &JNIEnv<'a>, slice: &ZBytes) -> Result> { - env.byte_array_from_slice( - slice - .deserialize::>() - .map_err(|err| session_error!("Unable to deserialize slice: {}", err))? - .as_ref(), - ) - .map_err(|err| jni_error!(err)) +pub(crate) fn bytes_to_java_array<'a>(env: &JNIEnv<'a>, slice: &ZBytes) -> ZResult> { + env.byte_array_from_slice(&slice.to_bytes()) + .map_err(|err| zerror!(err)) } -pub(crate) fn slice_to_java_string<'a>(env: &JNIEnv<'a>, slice: &ZSlice) -> Result> { +pub(crate) fn slice_to_java_string<'a>(env: &JNIEnv<'a>, slice: &ZSlice) -> ZResult> { env.new_string( String::from_utf8(slice.to_vec()) - .map_err(|err| session_error!("Unable to decode string: {}", err))?, + .map_err(|err| zerror!("Unable to decode string: {}", err))?, ) - .map_err(|err| jni_error!(err)) + .map_err(|err| zerror!(err)) } /// A type that calls a function when dropped @@ -182,7 +172,7 @@ pub(crate) fn load_on_close( _ = env.exception_describe(); throw_exception!( env, - jni_error!("Error while running 'onClose' callback: {}", err) + zerror!("Error while running 'onClose' callback: {}", err) ); } } diff --git a/zenoh-jni/src/zbytes.rs b/zenoh-jni/src/zbytes.rs new file mode 100644 index 00000000..0a1b0443 --- /dev/null +++ b/zenoh-jni/src/zbytes.rs @@ -0,0 +1,571 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use jni::{ + objects::{AutoLocal, JByteArray, JClass, JList, JMap, JObject, JString, JValue}, + sys::jobject, + JNIEnv, +}; +use zenoh::bytes::ZBytes; +use zenoh_ext::{VarInt, ZDeserializeError, ZDeserializer, ZSerializer}; + +use crate::{ + errors::ZResult, + throw_exception, + utils::{bytes_to_java_array, decode_byte_array}, + zerror, +}; + +enum KotlinType { + Boolean, + String, + ByteArray, + Byte, + Short, + Int, + Long, + Float, + Double, + UByte, + UShort, + UInt, + ULong, + List(Box), + Map(Box, Box), + Pair(Box, Box), + Triple(Box, Box, Box), +} + +fn decode_ktype(env: &mut JNIEnv, ktype: JObject) -> ZResult { + let classifier_obj = env + .call_method( + &ktype, + "getClassifier", + "()Lkotlin/reflect/KClassifier;", + &[], + ) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + let classifier_obj = AutoLocal::new(classifier_obj, env); + + let kclass_class = env + .find_class("kotlin/reflect/KClass") + .map_err(|err| zerror!(err))?; + let is_kclass = env + .is_instance_of(&classifier_obj, kclass_class) + .map_err(|err| zerror!(err))?; + if is_kclass { + let qualified_name_jobject = env + .call_method( + &classifier_obj, + "getQualifiedName", + "()Ljava/lang/String;", + &[], + ) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + + let qualified_name: String = env + .get_string(&JString::from(qualified_name_jobject)) + .map_err(|err| zerror!(err))? + .into(); + + match qualified_name.as_str() { + "kotlin.Boolean" => Ok(KotlinType::Boolean), + "kotlin.String" => Ok(KotlinType::String), + "kotlin.ByteArray" => Ok(KotlinType::ByteArray), + "kotlin.Byte" => Ok(KotlinType::Byte), + "kotlin.Short" => Ok(KotlinType::Short), + "kotlin.Int" => Ok(KotlinType::Int), + "kotlin.Long" => Ok(KotlinType::Long), + "kotlin.Float" => Ok(KotlinType::Float), + "kotlin.Double" => Ok(KotlinType::Double), + "kotlin.UByte" => Ok(KotlinType::UByte), + "kotlin.UShort" => Ok(KotlinType::UShort), + "kotlin.UInt" => Ok(KotlinType::UInt), + "kotlin.ULong" => Ok(KotlinType::ULong), + "kotlin.collections.List" => Ok(KotlinType::List(Box::new(decode_ktype_arg( + env, &ktype, 0, + )?))), + "kotlin.collections.Map" => Ok(KotlinType::Map( + Box::new(decode_ktype_arg(env, &ktype, 0)?), + Box::new(decode_ktype_arg(env, &ktype, 1)?), + )), + "kotlin.Pair" => Ok(KotlinType::Pair( + Box::new(decode_ktype_arg(env, &ktype, 0)?), + Box::new(decode_ktype_arg(env, &ktype, 1)?), + )), + "kotlin.Triple" => Ok(KotlinType::Triple( + Box::new(decode_ktype_arg(env, &ktype, 0)?), + Box::new(decode_ktype_arg(env, &ktype, 1)?), + Box::new(decode_ktype_arg(env, &ktype, 2)?), + )), + _ => Err(zerror!("Unsupported type: {}", qualified_name)), + } + } else { + Err(zerror!("Classifier is not a KClass")) + } +} + +fn decode_ktype_arg(env: &mut JNIEnv, ktype: &JObject, idx: i32) -> ZResult { + let arguments = env + .call_method(ktype, "getArguments", "()Ljava/util/List;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + let arg = env + .call_method( + &arguments, + "get", + "(I)Ljava/lang/Object;", + &[JValue::Int(idx)], + ) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + let ktype = env + .call_method(arg, "getType", "()Lkotlin/reflect/KType;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + decode_ktype(env, ktype) +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIZBytes_serializeViaJNI( + mut env: JNIEnv, + _class: JClass, + any: JObject, + ktype: JObject, +) -> jobject { + || -> ZResult { + let mut serializer = ZSerializer::new(); + let ktype = decode_ktype(&mut env, ktype)?; + serialize(&mut env, &mut serializer, any, &ktype)?; + let zbytes = serializer.finish(); + + let byte_array = bytes_to_java_array(&env, &zbytes).map_err(|err| zerror!(err))?; + let zbytes_obj = env + .new_object( + "io/zenoh/bytes/ZBytes", + "([B)V", + &[JValue::Object(&JObject::from(byte_array))], + ) + .map_err(|err| zerror!(err))?; + + Ok(zbytes_obj.as_raw()) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + JObject::default().as_raw() + }) +} + +fn serialize( + env: &mut JNIEnv, + serializer: &mut ZSerializer, + any: JObject, + ktype: &KotlinType, +) -> ZResult<()> { + match ktype { + KotlinType::Byte => { + let byte_value = env + .call_method(any, "byteValue", "()B", &[]) + .map_err(|err| zerror!(err))? + .b() + .map_err(|err| zerror!(err))?; + serializer.serialize(byte_value); + } + KotlinType::Short => { + let short_value = env + .call_method(any, "shortValue", "()S", &[]) + .map_err(|err| zerror!(err))? + .s() + .map_err(|err| zerror!(err))?; + serializer.serialize(short_value); + } + KotlinType::Int => { + let int_value = env + .call_method(any, "intValue", "()I", &[]) + .map_err(|err| zerror!(err))? + .i() + .map_err(|err| zerror!(err))?; + serializer.serialize(int_value); + } + KotlinType::Long => { + let long_value = env + .call_method(any, "longValue", "()J", &[]) + .map_err(|err| zerror!(err))? + .j() + .map_err(|err| zerror!(err))?; + serializer.serialize(long_value); + } + KotlinType::Float => { + let float_value = env + .call_method(any, "floatValue", "()F", &[]) + .map_err(|err| zerror!(err))? + .f() + .map_err(|err| zerror!(err))?; + serializer.serialize(float_value); + } + KotlinType::Double => { + let double_value = env + .call_method(any, "doubleValue", "()D", &[]) + .map_err(|err| zerror!(err))? + .d() + .map_err(|err| zerror!(err))?; + serializer.serialize(double_value); + } + KotlinType::Boolean => { + let boolean_value = env + .call_method(any, "booleanValue", "()Z", &[]) + .map_err(|err| zerror!(err))? + .z() + .map_err(|err| zerror!(err))?; + serializer.serialize(boolean_value); + } + KotlinType::String => { + let jstring = JString::from(any); + let string_value: String = env.get_string(&jstring).map_err(|err| zerror!(err))?.into(); + serializer.serialize(string_value); + } + KotlinType::ByteArray => { + let jbyte_array = JByteArray::from(any); + let bytes = decode_byte_array(env, jbyte_array).map_err(|err| zerror!(err))?; + serializer.serialize(bytes); + } + KotlinType::UByte => { + let byte = env + .get_field(any, "data", "B") + .map_err(|err| zerror!(err))? + .b() + .map_err(|err| zerror!(err))?; + serializer.serialize(byte as u8); + } + KotlinType::UShort => { + let short = env + .get_field(any, "data", "S") + .map_err(|err| zerror!(err))? + .s() + .map_err(|err| zerror!(err))?; + serializer.serialize(short as u16); + } + KotlinType::UInt => { + let int = env + .get_field(any, "data", "I") + .map_err(|err| zerror!(err))? + .i() + .map_err(|err| zerror!(err))?; + serializer.serialize(int as u32); + } + KotlinType::ULong => { + let long = env + .get_field(any, "data", "J") + .map_err(|err| zerror!(err))? + .j() + .map_err(|err| zerror!(err))?; + serializer.serialize(long as u64); + } + KotlinType::List(kotlin_type) => { + let jlist: JList<'_, '_, '_> = + JList::from_env(env, &any).map_err(|err| zerror!(err))?; + let mut iterator = jlist.iter(env).map_err(|err| zerror!(err))?; + let list_size = jlist.size(env).unwrap(); + serializer.serialize(zenoh_ext::VarInt(list_size as usize)); + while let Some(value) = iterator.next(env).map_err(|err| zerror!(err))? { + serialize(env, serializer, value, kotlin_type)?; + } + } + KotlinType::Map(key_type, value_type) => { + let jmap = JMap::from_env(env, &any).map_err(|err| zerror!(err))?; + + let map_size = env + .call_method(&jmap, "size", "()I", &[]) + .map_err(|err| zerror!(err))? + .i() + .map_err(|err| zerror!(err))?; + + serializer.serialize(zenoh_ext::VarInt(map_size as usize)); + + let mut iterator = jmap.iter(env).map_err(|err| zerror!(err))?; + while let Some((key, value)) = iterator.next(env).map_err(|err| zerror!(err))? { + serialize(env, serializer, key, key_type)?; + serialize(env, serializer, value, value_type)?; + } + } + KotlinType::Pair(first_type, second_type) => { + let first = env + .call_method(&any, "getFirst", "()Ljava/lang/Object;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + let second = env + .call_method(&any, "getSecond", "()Ljava/lang/Object;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + serialize(env, serializer, first, first_type)?; + serialize(env, serializer, second, second_type)?; + } + KotlinType::Triple(first_type, second_type, third_type) => { + let first = env + .call_method(&any, "getFirst", "()Ljava/lang/Object;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + let second = env + .call_method(&any, "getSecond", "()Ljava/lang/Object;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + let third = env + .call_method(&any, "getThird", "()Ljava/lang/Object;", &[]) + .map_err(|err| zerror!(err))? + .l() + .map_err(|err| zerror!(err))?; + serialize(env, serializer, first, first_type)?; + serialize(env, serializer, second, second_type)?; + serialize(env, serializer, third, third_type)?; + } + } + Ok(()) +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIZBytes_deserializeViaJNI( + mut env: JNIEnv, + _class: JClass, + zbytes: JObject, + ktype: JObject, +) -> jobject { + || -> ZResult { + let payload = env + .get_field(zbytes, "bytes", "[B") + .map_err(|err| zerror!(err))?; + let decoded_bytes: Vec = + decode_byte_array(&env, JByteArray::from(payload.l().unwrap()))?; + let zbytes = ZBytes::from(decoded_bytes); + let mut deserializer = ZDeserializer::new(&zbytes); + let ktype = decode_ktype(&mut env, ktype)?; + let obj = deserialize(&mut env, &mut deserializer, &ktype)?; + if !deserializer.done() { + return Err(zerror!(ZDeserializeError)); + } + Ok(obj) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + JObject::default().as_raw() + }) +} + +fn deserialize( + env: &mut JNIEnv, + deserializer: &mut ZDeserializer, + ktype: &KotlinType, +) -> ZResult { + match ktype { + KotlinType::Byte => { + let byte = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let byte_obj = env + .new_object("java/lang/Byte", "(B)V", &[JValue::Byte(byte)]) + .map_err(|err| zerror!(err))?; + Ok(byte_obj.as_raw()) + } + KotlinType::Short => { + let short = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let short_obj = env + .new_object("java/lang/Short", "(S)V", &[JValue::Short(short)]) + .map_err(|err| zerror!(err))?; + Ok(short_obj.as_raw()) + } + KotlinType::Int => { + let integer = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let integer_obj = env + .new_object("java/lang/Integer", "(I)V", &[JValue::Int(integer)]) + .map_err(|err| zerror!(err))?; + Ok(integer_obj.as_raw()) + } + KotlinType::Long => { + let long = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let long_obj = env + .new_object("java/lang/Long", "(J)V", &[JValue::Long(long)]) + .map_err(|err| zerror!(err))?; + Ok(long_obj.as_raw()) + } + KotlinType::Float => { + let float = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let float_obj = env + .new_object("java/lang/Float", "(F)V", &[JValue::Float(float)]) + .map_err(|err| zerror!(err))?; + Ok(float_obj.as_raw()) + } + KotlinType::Double => { + let double = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let double_obj = env + .new_object("java/lang/Double", "(D)V", &[JValue::Double(double)]) + .map_err(|err| zerror!(err))?; + Ok(double_obj.as_raw()) + } + KotlinType::Boolean => { + let boolean_value = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let jboolean = if boolean_value { 1u8 } else { 0u8 }; + let boolean_obj = env + .new_object("java/lang/Boolean", "(Z)V", &[JValue::Bool(jboolean)]) + .map_err(|err| zerror!(err))?; + Ok(boolean_obj.as_raw()) + } + KotlinType::String => { + let deserialized_string = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let jstring = env + .new_string(&deserialized_string) + .map_err(|err| zerror!(err))?; + Ok(jstring.into_raw()) + } + KotlinType::ByteArray => { + let deserialized_bytes = deserializer + .deserialize::>() + .map_err(|err| zerror!(err))?; + let jbytes = env + .byte_array_from_slice(deserialized_bytes.as_slice()) + .map_err(|err| zerror!(err))?; + Ok(jbytes.into_raw()) + } + KotlinType::UByte => { + let ubyte = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let ubyte_obj = env + .new_object("kotlin/UByte", "(B)V", &[JValue::Byte(ubyte as i8)]) + .map_err(|err| zerror!(err))?; + Ok(ubyte_obj.as_raw()) + } + KotlinType::UShort => { + let ushort = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let ushort_obj = env + .new_object("kotlin/UShort", "(S)V", &[JValue::Short(ushort as i16)]) + .map_err(|err| zerror!(err))?; + Ok(ushort_obj.as_raw()) + } + KotlinType::UInt => { + let uint = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let uint_obj = env + .new_object("kotlin/UInt", "(I)V", &[JValue::Int(uint as i32)]) + .map_err(|err| zerror!(err))?; + Ok(uint_obj.as_raw()) + } + KotlinType::ULong => { + let ulong = deserializer + .deserialize::() + .map_err(|err| zerror!(err))?; + let ulong_obj = env + .new_object("kotlin/ULong", "(J)V", &[JValue::Long(ulong as i64)]) + .map_err(|err| zerror!(err))?; + Ok(ulong_obj.as_raw()) + } + KotlinType::List(kotlin_type) => { + let list_size = deserializer + .deserialize::>() + .map_err(|err| zerror!(err))? + .0; + let array_list = env + .new_object("java/util/ArrayList", "()V", &[]) + .map_err(|err| zerror!(err))?; + let jlist = JList::from_env(env, &array_list).map_err(|err| zerror!(err))?; + + for _ in 0..list_size { + let item = deserialize(env, deserializer, kotlin_type)?; + let item_obj = unsafe { JObject::from_raw(item) }; + jlist.add(env, &item_obj).map_err(|err| zerror!(err))?; + } + Ok(array_list.as_raw()) + } + KotlinType::Map(key_type, value_type) => { + let map_size = deserializer + .deserialize::>() + .map_err(|err| zerror!(err))? + .0; + let map = env + .new_object("java/util/HashMap", "()V", &[]) + .map_err(|err| zerror!(err))?; + let jmap = JMap::from_env(env, &map).map_err(|err| zerror!(err))?; + + for _ in 0..map_size { + let key = deserialize(env, deserializer, key_type)?; + let key_obj = unsafe { JObject::from_raw(key) }; + let value = deserialize(env, deserializer, value_type)?; + let value_obj = unsafe { JObject::from_raw(value) }; + jmap.put(env, &key_obj, &value_obj) + .map_err(|err| zerror!(err))?; + } + Ok(map.as_raw()) + } + KotlinType::Pair(first_type, second_type) => { + let first = deserialize(env, deserializer, first_type)?; + let second = deserialize(env, deserializer, second_type)?; + let pair = env + .new_object( + "kotlin/Pair", + "(Ljava/lang/Object;Ljava/lang/Object;)V", + &[ + JValue::Object(&unsafe { JObject::from_raw(first) }), + JValue::Object(&unsafe { JObject::from_raw(second) }), + ], + ) + .map_err(|err| zerror!(err))?; + Ok(pair.as_raw()) + } + KotlinType::Triple(first_type, second_type, third_type) => { + let first = deserialize(env, deserializer, first_type)?; + let second = deserialize(env, deserializer, second_type)?; + let third = deserialize(env, deserializer, third_type)?; + let triple = env + .new_object( + "kotlin/Triple", + "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", + &[ + JValue::Object(&unsafe { JObject::from_raw(first) }), + JValue::Object(&unsafe { JObject::from_raw(second) }), + JValue::Object(&unsafe { JObject::from_raw(third) }), + ], + ) + .map_err(|err| zerror!(err))?; + Ok(triple.as_raw()) + } + } +} diff --git a/zenoh-jni/src/zenoh_id.rs b/zenoh-jni/src/zenoh_id.rs new file mode 100644 index 00000000..6647f86f --- /dev/null +++ b/zenoh-jni/src/zenoh_id.rs @@ -0,0 +1,42 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use crate::{errors::ZResult, throw_exception, utils::decode_byte_array, zerror}; +use jni::{ + objects::{JByteArray, JClass, JString}, + sys::jstring, + JNIEnv, +}; +use zenoh::session::ZenohId; + +/// Returns the string representation of a ZenohID. +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNIZenohId_toStringViaJNI( + mut env: JNIEnv, + _class: JClass, + zenoh_id: JByteArray, +) -> jstring { + || -> ZResult { + let bytes = decode_byte_array(&env, zenoh_id)?; + let zenohid = ZenohId::try_from(bytes.as_slice()).map_err(|err| zerror!(err))?; + env.new_string(zenohid.to_string()) + .map_err(|err| zerror!(err)) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + JString::default() + }) + .as_raw() +} From 68b18cf31614b148cdf4a38f5e82b5e52679b09f Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 12 Nov 2024 10:49:48 -0300 Subject: [PATCH 29/83] Alignment: wip - converting tests to java tests. Added config tests. --- examples/src/main/java/io/zenoh/ZDelete.java | 6 +- examples/src/main/java/io/zenoh/ZGet.java | 8 +- examples/src/main/java/io/zenoh/ZPub.java | 9 +- examples/src/main/java/io/zenoh/ZPubThr.java | 15 +- examples/src/main/java/io/zenoh/ZPut.java | 9 +- .../src/main/java/io/zenoh/ZQueryable.java | 11 +- examples/src/main/java/io/zenoh/ZSub.java | 14 +- examples/src/main/java/io/zenoh/ZSubThr.java | 8 +- zenoh-java/build.gradle.kts | 1 + .../src/commonMain/kotlin/io/zenoh/Config.kt | 28 +- .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 7 +- .../kotlin/io/zenoh/bytes/ZBytes.kt | 2 + .../commonMain/kotlin/io/zenoh/pubsub/Put.kt | 1 + .../kotlin/io/zenoh/query/IntoSelector.kt | 29 -- .../kotlin/io/zenoh/query/Selector.kt | 38 ++ .../kotlin/io/zenoh/DeleteBuilderTest.kt | 39 -- .../kotlin/io/zenoh/EncodingTest.kt | 168 --------- .../src/commonTest/kotlin/io/zenoh/GetTest.kt | 121 ------ .../commonTest/kotlin/io/zenoh/KeyExprTest.kt | 126 ------- .../kotlin/io/zenoh/PublisherTest.kt | 77 ---- .../kotlin/io/zenoh/PutBuilderTest.kt | 46 --- .../kotlin/io/zenoh/QueryableTest.kt | 241 ------------ .../kotlin/io/zenoh/SelectorTest.kt | 30 -- .../commonTest/kotlin/io/zenoh/SessionTest.kt | 65 ---- .../kotlin/io/zenoh/SubscriberTest.kt | 150 -------- .../src/jvmTest/java/io/zenoh/ConfigTest.java | 355 ++++++++++++++++++ 26 files changed, 464 insertions(+), 1140 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/EncodingTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt delete mode 100644 zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java diff --git a/examples/src/main/java/io/zenoh/ZDelete.java b/examples/src/main/java/io/zenoh/ZDelete.java index 7f7e726c..49bae297 100644 --- a/examples/src/main/java/io/zenoh/ZDelete.java +++ b/examples/src/main/java/io/zenoh/ZDelete.java @@ -14,13 +14,13 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; public class ZDelete { - public static void main(String[] args) throws ZenohException { + public static void main(String[] args) throws ZError { System.out.println("Opening session..."); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { System.out.println("Deleting resources matching '" + keyExpr + "'..."); session.delete(keyExpr).res(); diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index 368b75da..1b5be58e 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -14,7 +14,7 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.exceptions.ZError; import io.zenoh.query.Reply; import io.zenoh.query.Selector; @@ -23,9 +23,9 @@ public class ZGet { - public static void main(String[] args) throws ZenohException, InterruptedException { + public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening session..."); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (Selector selector = Selector.tryFrom("demo/example/**")) { System.out.println("Performing Get on '" + selector + "'..."); BlockingQueue> receiver = session.get(selector).res(); @@ -38,7 +38,7 @@ public static void main(String[] args) throws ZenohException, InterruptedExcepti Reply reply = wrapper.get(); if (reply instanceof Reply.Success) { Reply.Success successReply = (Reply.Success) reply; - System.out.println("Received ('" + successReply.getSample().getKeyExpr() + "': '" + successReply.getSample().getValue() + "')"); + System.out.println("Received ('" + successReply.getSample().getKeyExpr() + "': '" + successReply.getSample().getPayload() + "')"); } else { Reply.Error errorReply = (Reply.Error) reply; System.out.println("Received (ERROR: '" + errorReply.getError() + "')"); diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index 23bd021a..adfe7757 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -14,14 +14,15 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; public class ZPub { - public static void main(String[] args) throws ZenohException, InterruptedException { + public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening session..."); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-pub")) { System.out.println("Declaring publisher on '" + keyExpr + "'..."); try (Publisher publisher = session.declarePublisher(keyExpr).res()) { @@ -31,7 +32,7 @@ public static void main(String[] args) throws ZenohException, InterruptedExcepti Thread.sleep(1000); String payload = String.format("[%4s] Pub from Java!", idx); System.out.println("Putting Data ('" + keyExpr + "': '"+payload+"')..."); - publisher.put(payload).res(); + publisher.put(ZBytes.from(payload)).res(); idx++; } } diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index 177cb35b..ebe530c1 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -14,29 +14,26 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.qos.CongestionControl; -import io.zenoh.prelude.Encoding; import io.zenoh.pubsub.Publisher; -import io.zenoh.value.Value; public class ZPubThr { - public static void main(String[] args) throws ZenohException { + public static void main(String[] args) throws ZError { int size = 8; byte[] data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = (byte) (i % 10); } - Value value = new Value(data, new Encoding(Encoding.ID.ZENOH_BYTES, null)); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Publisher publisher = session.declarePublisher(keyExpr).congestionControl(CongestionControl.BLOCK).res()) { + try (Publisher publisher = session.declarePublisher(keyExpr).res()) { System.out.println("Publisher declared on test/thr."); System.out.println("Press CTRL-C to quit..."); while (true) { - publisher.put(value).res(); + publisher.put(ZBytes.from(data)).res(); } } } diff --git a/examples/src/main/java/io/zenoh/ZPut.java b/examples/src/main/java/io/zenoh/ZPut.java index 3d0caec5..e5a7d48b 100644 --- a/examples/src/main/java/io/zenoh/ZPut.java +++ b/examples/src/main/java/io/zenoh/ZPut.java @@ -14,18 +14,19 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; public class ZPut { - public static void main(String[] args) throws ZenohException { + public static void main(String[] args) throws ZError { System.out.println("Opening session..."); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { String value = "Put from Java!"; - session.put(keyExpr, value) + session.put(keyExpr, ZBytes.from(value)) .congestionControl(CongestionControl.BLOCK) .priority(Priority.REALTIME) .res(); diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index d80b916b..fc42103d 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -14,7 +14,8 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.query.Query; import io.zenoh.query.Queryable; @@ -25,9 +26,9 @@ public class ZQueryable { - public static void main(String[] args) throws ZenohException, InterruptedException { + public static void main(String[] args) throws ZError, InterruptedException { String keyExprString = "demo/example/zenoh-java-queryable"; - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom(keyExprString)) { System.out.println("Declaring Queryable on " + keyExprString + "..."); try (Queryable>> queryable = session.declareQueryable(keyExpr).res()) { @@ -47,10 +48,10 @@ private static void handleRequests(BlockingQueue> receiver, KeyE break; } Query query = wrapper.get(); - String valueInfo = query.getValue() != null ? " with value '" + query.getValue() + "'" : ""; + String valueInfo = query.getPayload() != null ? " with value '" + query.getPayload() + "'" : ""; System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); try { - query.reply(keyExpr).success("Queryable from Java!").timestamp(TimeStamp.getCurrentTime()).res(); + query.reply(keyExpr, ZBytes.from("Queryable from Java!")).timestamp(TimeStamp.getCurrentTime()).res(); } catch (Exception e) { System.out.println(">> [Queryable] Error sending reply: " + e); } diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index 88220e31..e5424c50 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -14,7 +14,7 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.sample.Sample; import io.zenoh.pubsub.Subscriber; @@ -24,9 +24,9 @@ public class ZSub { - public static void main(String[] args) throws ZenohException, InterruptedException { + public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening session..."); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/**")) { System.out.println("Declaring Subscriber on '" + keyExpr + "'..."); try (Subscriber>> subscriber = session.declareSubscriber(keyExpr).res()) { @@ -39,10 +39,16 @@ public static void main(String[] args) throws ZenohException, InterruptedExcepti break; } Sample sample = wrapper.get(); - System.out.println(">> [Subscriber] Received " + sample.getKind() + " ('" + sample.getKeyExpr() + "': '" + sample.getValue() + "')"); + System.out.println(">> [Subscriber] Received " + sample.getKind() + " ('" + sample.getKeyExpr() + "': '" + sample.getPayload() + "')"); } + } catch (ZError e) { + throw new RuntimeException(e); } } } } + + public static void handleSample(Sample sample) { + + } } diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index bb2bd79c..f4cceceb 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -14,7 +14,7 @@ package io.zenoh; -import io.zenoh.exceptions.ZenohException; +import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; import kotlin.Unit; @@ -58,11 +58,11 @@ public static void report() { ": averaged " + avg + " msgs/sec"); } - public static void main(String[] args) throws ZenohException, InterruptedException { + public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening Session"); - try (Session session = Session.open()) { + try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Subscriber subscriber = session.declareSubscriber(keyExpr).with(sample -> listener()).res()) { + try (Subscriber subscriber = session.declareSubscriber(keyExpr).callback(sample -> listener()).res()) { System.out.println("Press CTRL-C to quit..."); while (true) { Thread.sleep(1000); diff --git a/zenoh-java/build.gradle.kts b/zenoh-java/build.gradle.kts index f5841d0a..0b582541 100644 --- a/zenoh-java/build.gradle.kts +++ b/zenoh-java/build.gradle.kts @@ -46,6 +46,7 @@ kotlin { val zenohPaths = "../zenoh-jni/target/$buildMode" jvmArgs("-Djava.library.path=$zenohPaths") } + withJava() } if (androidEnabled) { androidTarget { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt index e331d03c..9abddf27 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt @@ -132,7 +132,8 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { /** * Returns the default config. */ - fun default(): Config { + @JvmStatic + fun loadDefault(): Config { return JNIConfig.loadDefaultConfig() } @@ -143,6 +144,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { * Note the format is determined after the file extension. * @return The [Config]. */ + @JvmStatic @Throws(ZError::class) fun fromFile(file: File): Config { return JNIConfig.loadConfigFile(file) @@ -155,6 +157,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { * Note the format is determined after the file extension. * @return The [Config]. */ + @JvmStatic @Throws(ZError::class) fun fromFile(path: Path): Config { return JNIConfig.loadConfigFile(path) @@ -192,6 +195,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { * @param config Json formatted config. * @return The [Config]. */ + @JvmStatic @Throws(ZError::class) fun fromJson(config: String): Config { return JNIConfig.loadJsonConfig(config) @@ -229,6 +233,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { * @param config Json5 formatted config * @return The [Config]. */ + @JvmStatic @Throws(ZError::class) fun fromJson5(config: String): Config { return JNIConfig.loadJson5Config(config) @@ -262,26 +267,29 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { * @param config Yaml formatted config * @return The [Config]. */ + @JvmStatic @Throws(ZError::class) fun fromYaml(config: String): Config { return JNIConfig.loadYamlConfig(config) } - /** - * Loads the configuration from the [jsonElement] specified. - * - * @param jsonElement The zenoh config as a [JsonElement]. - */ - @Throws(ZError::class) - fun fromJsonElement(jsonElement: JsonElement): Config { - return JNIConfig.loadJsonConfig(jsonElement.toString()) - } +// /** TODO +// * Loads the configuration from the [jsonElement] specified. +// * +// * @param jsonElement The zenoh config as a [JsonElement]. +// */ +// @JvmStatic +// @Throws(ZError::class) +// fun fromJsonElement(jsonElement: JsonElement): Config { +// return JNIConfig.loadJsonConfig(jsonElement.toString()) +// } /** * Loads the configuration from the env variable [CONFIG_ENV]. * * @return The config. */ + @JvmStatic @Throws(ZError::class) fun fromEnv(): Config { val envValue = System.getenv(CONFIG_ENV) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index 791bc22d..fe708b4a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -32,6 +32,7 @@ object Zenoh { * @param config The configuration for the session. * @return The [Session] on success. */ + @JvmStatic @Throws(ZError::class) fun open(config: Config): Session { return Session.open(config) @@ -48,6 +49,7 @@ object Zenoh { * @param config Optional [Config] for the scout. * @return A result with the [Scout] object. */ + @JvmStatic @Throws(ZError::class) fun scout( callback: Callback, @@ -69,6 +71,7 @@ object Zenoh { * @param config Optional [Config] for the scout. * @return A result with the [Scout] object. */ + @JvmStatic @Throws(ZError::class) fun scout( handler: Handler, @@ -84,7 +87,7 @@ object Zenoh { ) } -// /** +// /** TODO // * Scout for routers and/or peers. // * // * Scout spawns a task that periodically sends scout messages and waits for Hello replies. @@ -119,6 +122,7 @@ object Zenoh { * * @see Logger */ + @JvmStatic fun tryInitLogFromEnv() { val logEnv = System.getenv(LOG_ENV) if (logEnv != null) { @@ -137,6 +141,7 @@ object Zenoh { * @param fallbackFilter: The fallback filter if the `RUST_LOG` environment variable is not set. * @see Logger */ + @JvmStatic fun initLogFromEnvOr(fallbackFilter: String): Result = runCatching { ZenohLoad val logLevelProp = System.getenv(LOG_ENV) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt index 35cd9d52..a4462396 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt @@ -38,11 +38,13 @@ class ZBytes internal constructor(internal val bytes: ByteArray) : IntoZBytes { /** * Creates a [ZBytes] instance from a [String]. */ + @JvmStatic fun from(string: String) = ZBytes(string.encodeToByteArray()) /** * Creates a [ZBytes] instance from a [ByteArray]. */ + @JvmStatic fun from(bytes: ByteArray) = ZBytes(bytes) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt index 3c5319b8..8368974f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt @@ -130,6 +130,7 @@ class Put private constructor( /** Resolves the put operation, returning a [Result]. */ @Throws(ZError::class) override fun res() { + // TODO: rename res() to put() val put = Put(keyExpr, payload.into(), encoding ?: Encoding.default(), qosBuilder.build(), reliability, attachment) session.run { resolvePut(keyExpr, put) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt deleted file mode 100644 index 4c2ede28..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/IntoSelector.kt +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.query - -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.KeyExpr - -@Throws(ZError::class) -fun String.intoSelector(): Selector { - if (this.isEmpty()) { - throw(ZError("Attempting to create a KeyExpr from an empty string.")) - } - val result = this.split('?', limit = 2) - val keyExpr = KeyExpr.autocanonize(result[0]) - val params = if (result.size == 2) Parameters.from(result[1]) else null - return Selector(keyExpr, params) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt index 289a84f8..6a9fb106 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt @@ -14,6 +14,7 @@ package io.zenoh.query +import io.zenoh.exceptions.ZError import io.zenoh.keyexpr.KeyExpr /** @@ -50,6 +51,40 @@ import io.zenoh.keyexpr.KeyExpr */ data class Selector(val keyExpr: KeyExpr, val parameters: Parameters? = null) : AutoCloseable, IntoSelector { + companion object { + + /** + * Try from. + * + * The default way to construct a Selector. + * + * When in string form, selectors look a lot like a URI, with similar semantics: + * - the `key_expr` before the first `?` must be a valid key expression. + * - the `parameters` after the first `?` should be encoded like the query section of a URL: + * - parameters are separated by `;`, + * - the parameter name and value are separated by the first `=`, + * - in the absence of `=`, the parameter value is considered to be the empty string, + * - both name and value should use percent-encoding to escape characters, + * - defining a value for the same parameter name twice is considered undefined behavior, + * with the encouraged behaviour being to reject operations when a duplicate parameter is detected. + * + * @param selector The selector expression as a String. + * @return a Result with the constructed Selector. + */ + @Throws(ZError::class) + @JvmStatic + fun tryFrom(selector: String): Selector { + if (selector.isEmpty()) { + throw ZError("Attempting to create a selector from an empty string.") + } + val result = selector.split('?', limit = 2) + val keyExpr = KeyExpr.autocanonize(result[0]) + val params = if (result.size == 2) Parameters.from(result[1]) else null + + return Selector(keyExpr, params) + } + } + override fun into(): Selector = this override fun toString(): String { @@ -65,3 +100,6 @@ data class Selector(val keyExpr: KeyExpr, val parameters: Parameters? = null) : interface IntoSelector { fun into(): Selector } + +@Throws(ZError::class) +fun String.intoSelector(): Selector = Selector.tryFrom(this) diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt deleted file mode 100644 index 23da1f33..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/DeleteBuilderTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.sample.SampleKind -import io.zenoh.sample.Sample -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -class DeleteBuilderTest { - - @Test - fun delete_isProperlyReceivedBySubscriber() { - val session = Session.open() - var receivedSample: Sample? = null - val keyExpr = "example/testing/keyexpr".intoKeyExpr() - val subscriber = session.declareSubscriber(keyExpr).with { sample -> receivedSample = sample }.res() - session.delete(keyExpr).res() - subscriber.close() - keyExpr.close() - session.close() - assertNotNull(receivedSample) - assertEquals(receivedSample!!.kind, SampleKind.DELETE) - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/EncodingTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/EncodingTest.kt deleted file mode 100644 index 5f344e06..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/EncodingTest.kt +++ /dev/null @@ -1,168 +0,0 @@ -package io.zenoh - -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.Encoding -import io.zenoh.query.Reply -import io.zenoh.sample.Sample -import io.zenoh.value.Value -import kotlin.test.* - -class EncodingTest { - - @Test - fun encoding_subscriberTest() { - val session = Session.open() - val keyExpr = "example/testing/keyexpr".intoKeyExpr() - - // Testing non null schema - var receivedSample: Sample? = null - val subscriber = session.declareSubscriber(keyExpr).with { sample -> - receivedSample = sample - }.res() - var value = Value("test", Encoding(Encoding.ID.TEXT_CSV, "test_schema")) - session.put(keyExpr, value).res() - Thread.sleep(200) - - assertNotNull(receivedSample) - assertEquals(Encoding.ID.TEXT_CSV, receivedSample!!.value.encoding.id) - assertEquals("test_schema", receivedSample!!.value.encoding.schema) - - // Testing null schema - receivedSample = null - value = Value("test2", Encoding(Encoding.ID.ZENOH_STRING, null)) - session.put(keyExpr, value).res() - Thread.sleep(200) - - assertNotNull(receivedSample) - assertEquals(Encoding.ID.ZENOH_STRING, receivedSample!!.value.encoding.id) - assertNull(receivedSample!!.value.encoding.schema) - - subscriber.close() - session.close() - } - - @Test - fun encoding_replySuccessTest() { - val session = Session.open() - val keyExpr = "example/testing/**".intoKeyExpr() - val test1 = "example/testing/reply_success".intoKeyExpr() - val test2 = "example/testing/reply_success_with_schema".intoKeyExpr() - - val testValueA = Value("test", Encoding(Encoding.ID.TEXT_CSV, null)) - val testValueB = Value("test", Encoding(Encoding.ID.TEXT_CSV, "test_schema")) - - val queryable = session.declareQueryable(keyExpr).with { query -> - when (query.keyExpr) { - test1 -> query.reply(query.keyExpr).success(testValueA).res() - test2 -> query.reply(query.keyExpr).success(testValueB).res() - } - }.res() - - // Testing with null schema on a reply success scenario. - var receivedSample: Sample? = null - session.get(test1).with { reply -> - assertTrue(reply is Reply.Success) - receivedSample = reply.sample - }.res() - Thread.sleep(200) - - assertNotNull(receivedSample) - assertEquals(Encoding.ID.TEXT_CSV, receivedSample!!.value.encoding.id) - assertNull(receivedSample!!.value.encoding.schema) - - // Testing with non-null schema on a reply success scenario. - receivedSample = null - session.get(test2).with { reply -> - assertTrue(reply is Reply.Success) - receivedSample = reply.sample - }.res() - Thread.sleep(200) - - assertNotNull(receivedSample) - assertEquals(Encoding.ID.TEXT_CSV, receivedSample!!.value.encoding.id) - assertEquals("test_schema", receivedSample!!.value.encoding.schema) - - queryable.close() - session.close() - } - - @Test - fun encoding_replyErrorTest() { - val session = Session.open() - val keyExpr = "example/testing/**".intoKeyExpr() - - val test1 = "example/testing/reply_error".intoKeyExpr() - val test2 = "example/testing/reply_error_with_schema".intoKeyExpr() - - val testValueA = Value("test", Encoding(Encoding.ID.TEXT_CSV, null)) - val testValueB = Value("test", Encoding(Encoding.ID.TEXT_CSV, "test_schema")) - - val queryable = session.declareQueryable(keyExpr).with { query -> - when (query.keyExpr) { - test1 -> query.reply(query.keyExpr).error(testValueA).res() - test2 -> query.reply(query.keyExpr).error(testValueB).res() - } - }.res() - - // Testing with null schema on a reply error scenario. - var errorValue: Value? = null - session.get(test1).with { reply -> - assertTrue(reply is Reply.Error) - errorValue = reply.error - }.res() - Thread.sleep(200) - - assertNotNull(errorValue) - assertEquals(Encoding.ID.TEXT_CSV, errorValue!!.encoding.id) - assertNull(errorValue!!.encoding.schema) - - // Testing with non-null schema on a reply error scenario. - errorValue = null - session.get(test2).with { reply -> - assertTrue(reply is Reply.Error) - errorValue = reply.error - }.res() - Thread.sleep(200) - - assertNotNull(errorValue) - assertEquals(Encoding.ID.TEXT_CSV, errorValue!!.encoding.id) - assertEquals("test_schema", errorValue!!.encoding.schema) - - queryable.close() - session.close() - } - - @Test - fun encoding_queryTest() { - val session = Session.open() - val keyExpr = "example/testing/keyexpr".intoKeyExpr() - val testValueA = Value("test", Encoding(Encoding.ID.TEXT_CSV, null)) - val testValueB = Value("test", Encoding(Encoding.ID.TEXT_CSV, "test_schema")) - - var receivedValue: Value? = null - val queryable = session.declareQueryable(keyExpr).with { query -> - receivedValue = query.value - query.close() - }.res() - - // Testing with null schema - session.get(keyExpr).withValue(testValueA).res() - Thread.sleep(200) - - assertNotNull(receivedValue) - assertEquals(Encoding.ID.TEXT_CSV, receivedValue!!.encoding.id) - assertNull(receivedValue!!.encoding.schema) - - // Testing non-null schema - receivedValue = null - session.get(keyExpr).withValue(testValueB).res() - Thread.sleep(200) - - assertNotNull(receivedValue) - assertEquals(Encoding.ID.TEXT_CSV, receivedValue!!.encoding.id) - assertEquals("test_schema", receivedValue!!.encoding.schema) - - queryable.close() - session.close() - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt deleted file mode 100644 index f2ebdbf5..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/GetTest.kt +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.handlers.Handler -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.sample.SampleKind -import io.zenoh.query.Reply -import io.zenoh.query.Queryable -import io.zenoh.query.Selector -import io.zenoh.value.Value -import org.apache.commons.net.ntp.TimeStamp -import java.time.Duration -import java.util.* -import kotlin.test.* - -class GetTest { - - companion object { - val value = Value("Test") - val timestamp = TimeStamp.getCurrentTime() - val kind = SampleKind.PUT - } - - private lateinit var session: Session - private lateinit var keyExpr: KeyExpr - private lateinit var queryable: Queryable - - @BeforeTest - fun setUp() { - session = Session.open() - keyExpr = "example/testing/keyexpr".intoKeyExpr() - queryable = session.declareQueryable(keyExpr).with { query -> - query.reply(query.keyExpr) - .success(value) - .timestamp(timestamp) - .res() - }.res() - } - - @AfterTest - fun tearDown() { - keyExpr.close() - queryable.close() - session.close() - } - - @Test - fun get_runsWithCallback() { - var reply: Reply? = null - session.get(keyExpr).with { reply = it }.timeout(Duration.ofMillis(1000)).res() - - assertTrue(reply is Reply.Success) - val sample = (reply as Reply.Success).sample - assertEquals(value, sample.value) - assertEquals(kind, sample.kind) - assertEquals(keyExpr, sample.keyExpr) - assertEquals(timestamp, sample.timestamp) - } - - @Test - fun get_runsWithHandler() { - val receiver: ArrayList = session.get(keyExpr).with(TestHandler()) - .timeout(Duration.ofMillis(1000)).res()!! - - for (reply in receiver) { - reply as Reply.Success - val receivedSample = reply.sample - assertEquals(value, receivedSample.value) - assertEquals(SampleKind.PUT, receivedSample.kind) - assertEquals(timestamp, receivedSample.timestamp) - } - } - - @Test - fun getWithSelectorParamsTest() { - var receivedParams = String() - val queryable = session.declareQueryable(keyExpr).with { - it.use { query -> - receivedParams = query.parameters - } - }.res() - - val params = "arg1=val1,arg2=val2" - val selector = Selector(keyExpr, params) - session.get(selector).with {}.timeout(Duration.ofMillis(1000)).res() - Thread.sleep(1000) - - queryable.close() - assertEquals(params, receivedParams) - } -} - -/** A dummy handler for get operations. */ -private class TestHandler : Handler> { - - val performedReplies: ArrayList = ArrayList() - - override fun handle(t: Reply) { - performedReplies.add(t) - } - - override fun receiver(): ArrayList { - return performedReplies - } - - override fun onClose() {} -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt deleted file mode 100644 index 4af63cde..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/KeyExprTest.kt +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.keyexpr.intoKeyExpr -import org.junit.Assert.assertThrows -import kotlin.test.* - -class KeyExprTest { - - init { - Zenoh.load() - } - - @Test - fun creation_TryFromTest() { - // A couple of examples of valid and invalid key expressions. - - KeyExpr.tryFrom("example/test") // Should not throw exception - - assertThrows(Exception::class.java) { KeyExpr.tryFrom("example/test?param='test'") } - - KeyExpr.tryFrom("example/*/test") // Should not throw exception - - assertThrows(Exception::class.java) { KeyExpr.tryFrom("example/!*/test") } - } - - @Test - fun equalizationTest() { - val keyExpr1 = KeyExpr.tryFrom("example/test") - val keyExpr2 = KeyExpr.tryFrom("example/test") - - assertEquals(keyExpr1, keyExpr2) - - val keyExpr3 = KeyExpr.tryFrom("different/key/expr") - assertNotEquals(keyExpr1, keyExpr3) - - // Despite being undeclared, the equals operation should still work. - keyExpr2.close() - assertEquals(keyExpr1, keyExpr2) - - keyExpr1.close() - assertEquals(keyExpr1, keyExpr2) - } - - @Test - fun creation_autocanonizeTest() { - val keyExpr1 = KeyExpr.autocanonize("example/**/test") - val keyExpr2 = KeyExpr.autocanonize("example/**/**/test") - assertEquals(keyExpr1, keyExpr2) - } - - @Test - fun intersectionTest() { - val keyExprA = KeyExpr.tryFrom("example/*/test") - - val keyExprB = KeyExpr.tryFrom("example/B/test") - assertTrue(keyExprA.intersects(keyExprB)) - - val keyExprC = KeyExpr.tryFrom("example/B/C/test") - assertFalse(keyExprA.intersects(keyExprC)) - - val keyExprA2 = KeyExpr.tryFrom("example/**") - assertTrue(keyExprA2.intersects(keyExprC)) - } - - @Test - fun includesTest() { - val keyExpr = KeyExpr.tryFrom("example/**") - val includedKeyExpr = KeyExpr.tryFrom("example/A/B/C/D") - assertTrue(keyExpr.includes(includedKeyExpr)) - - val notIncludedKeyExpr = KeyExpr.tryFrom("C/D") - assertFalse(keyExpr.includes(notIncludedKeyExpr)) - } - - @Test - fun sessionDeclarationTest() { - val session = Session.open() - val keyExpr = session.declareKeyExpr("a/b/c").res() - assertEquals("a/b/c", keyExpr.toString()) - session.close() - keyExpr.close() - } - - @Test - fun sessionUnDeclarationTest() { - val session = Session.open() - val keyExpr = session.declareKeyExpr("a/b/c").res() - assertEquals("a/b/c", keyExpr.toString()) - - session.undeclare(keyExpr).res() // Should not throw exception - - // Undeclaring a key expr that was not declared through a session. - val keyExpr2 = "x/y/z".intoKeyExpr() - assertThrows(ZError::class.java) {session.undeclare(keyExpr2).res()} - - session.close() - keyExpr.close() - keyExpr2.close() - } - - @Test - fun keyExprIsValidAfterClosingSession() { - val session = Session.open() - val keyExpr = session.declareKeyExpr("a/b/c").res() - session.close() - - assertTrue(keyExpr.isValid()) - assertFalse(keyExpr.toString().isEmpty()) // An operation such as toString that goes through JNI is still valid. - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt deleted file mode 100644 index f3ff99da..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/PublisherTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.Encoding -import io.zenoh.sample.SampleKind -import io.zenoh.pubsub.Publisher -import io.zenoh.sample.Sample -import io.zenoh.pubsub.Subscriber -import io.zenoh.value.Value -import kotlin.test.* - -class PublisherTest { - - lateinit var session: Session - lateinit var receivedSamples: ArrayList - lateinit var publisher: Publisher - lateinit var subscriber: Subscriber - lateinit var keyExpr: KeyExpr - - @BeforeTest - fun setUp() { - session = Session.open() - keyExpr = "example/testing/keyexpr".intoKeyExpr() - publisher = session.declarePublisher(keyExpr).res() - subscriber = session.declareSubscriber(keyExpr).with { sample -> - receivedSamples.add(sample) - }.res() - receivedSamples = ArrayList() - } - - @AfterTest - fun tearDown() { - publisher.close() - subscriber.close() - session.close() - keyExpr.close() - } - - @Test - fun putTest() { - - val testValues = arrayListOf( - Value("Test 1".encodeToByteArray(), Encoding(Encoding.ID.TEXT_PLAIN)), - Value("Test 2".encodeToByteArray(), Encoding(Encoding.ID.TEXT_JSON)), - Value("Test 3".encodeToByteArray(), Encoding(Encoding.ID.TEXT_CSV)) - ) - - testValues.forEach() { value -> publisher.put(value).res() } - - assertEquals(receivedSamples.size, testValues.size) - for ((index, sample) in receivedSamples.withIndex()) { - assertEquals(sample.value, testValues[index]) - } - } - - @Test - fun deleteTest() { - publisher.delete().res() - assertEquals(1, receivedSamples.size) - assertEquals(SampleKind.DELETE, receivedSamples[0].kind) - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt deleted file mode 100644 index f1e4f335..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/PutBuilderTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.prelude.Encoding -import io.zenoh.sample.Sample -import io.zenoh.value.Value -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -class PutBuilderTest { - - companion object { - const val TEST_KEY_EXP = "example/testing/keyexpr" - const val TEST_PAYLOAD = "Hello" - } - - @Test - fun putTest() { - val session = Session.open() - var receivedSample: Sample? = null - val keyExpr = TEST_KEY_EXP.intoKeyExpr() - val subscriber = session.declareSubscriber(keyExpr).with { sample -> receivedSample = sample }.res() - val value = Value(TEST_PAYLOAD.toByteArray(), Encoding(Encoding.ID.TEXT_PLAIN)) - session.put(keyExpr, value).res() - subscriber.close() - session.close() - keyExpr.close() - assertNotNull(receivedSample) - assertEquals(value, receivedSample!!.value) - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt deleted file mode 100644 index fb561003..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/QueryableTest.kt +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.handlers.Handler -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority -import io.zenoh.qos.QoS -import io.zenoh.sample.SampleKind -import io.zenoh.query.Reply -import io.zenoh.query.Query -import io.zenoh.sample.Sample -import io.zenoh.value.Value -import org.apache.commons.net.ntp.TimeStamp -import java.time.Duration -import java.time.Instant -import java.util.* -import java.util.concurrent.BlockingQueue -import kotlin.test.* - -class QueryableTest { - - companion object { - val TEST_KEY_EXP = "example/testing/keyexpr".intoKeyExpr() - const val testPayload = "Hello queryable" - } - - private lateinit var session: Session - private lateinit var testKeyExpr: KeyExpr - - @BeforeTest - fun setUp() { - session = Session.open() - testKeyExpr = "example/testing/keyexpr".intoKeyExpr() - } - - @AfterTest - fun tearDown() { - session.close() - testKeyExpr.close() - } - - /** Test validating both Queryable and get operations. */ - @Test - fun queryable_runsWithCallback() { - val sample = Sample( - testKeyExpr, Value(testPayload), SampleKind.PUT, TimeStamp(Date.from(Instant.now())), QoS.default() - ) - val queryable = session.declareQueryable(testKeyExpr).with { query -> - query.reply(testKeyExpr).success(sample.value).timestamp(sample.timestamp!!).res() - }.res() - - var reply: Reply? = null - val delay = Duration.ofMillis(1000) - session.get(testKeyExpr).with { reply = it }.timeout(delay).res() - - Thread.sleep(1000) - - assertTrue(reply is Reply.Success) - assertEquals((reply as Reply.Success).sample, sample) - - queryable.close() - } - - @Test - fun queryable_runsWithHandler() { - val handler = QueryHandler() - val queryable = session.declareQueryable(testKeyExpr).with(handler).res() - - val receivedReplies = ArrayList() - session.get(testKeyExpr).with { reply: Reply -> - receivedReplies.add(reply) - }.res() - - Thread.sleep(500) - - queryable.close() - assertTrue(receivedReplies.all { it is Reply.Success }) - assertEquals(handler.performedReplies.size, receivedReplies.size) - } - - @Test - fun queryableBuilder_queueHandlerIsTheDefaultHandler() { - val queryable = session.declareQueryable(TEST_KEY_EXP).res() - assertTrue(queryable.receiver is BlockingQueue>) - queryable.close() - } - - @Test - fun queryTest() { - var receivedQuery: Query? = null - val queryable = session.declareQueryable(testKeyExpr).with { query -> receivedQuery = query }.res() - - session.get(testKeyExpr).res() - - Thread.sleep(1000) - queryable.close() - assertNotNull(receivedQuery) - assertNull(receivedQuery!!.value) - } - - @Test - fun queryWithValueTest() { - var receivedQuery: Query? = null - val queryable = session.declareQueryable(testKeyExpr).with { query -> receivedQuery = query }.res() - - session.get(testKeyExpr).withValue("Test value").res() - - Thread.sleep(1000) - queryable.close() - assertNotNull(receivedQuery) - assertEquals(Value("Test value"), receivedQuery!!.value) - } - - @Test - fun queryReplySuccessTest() { - val message = "Test message" - val timestamp = TimeStamp.getCurrentTime() - val priority = Priority.DATA_HIGH - val express = true - val congestionControl = CongestionControl.DROP - val queryable = session.declareQueryable(testKeyExpr).with { - it.use { query -> - query.reply(testKeyExpr).success(message).timestamp(timestamp).priority(priority).express(express) - .congestionControl(congestionControl).res() - } - }.res() - - var receivedReply: Reply? = null - session.get(testKeyExpr).with { receivedReply = it }.timeout(Duration.ofMillis(10)).res() - - queryable.close() - - assertTrue(receivedReply is Reply.Success) - val reply = receivedReply as Reply.Success - assertEquals(message, reply.sample.value.payload.decodeToString()) - assertEquals(timestamp, reply.sample.timestamp) - assertEquals(priority, reply.sample.qos.priority) - assertEquals(express, reply.sample.qos.express) - assertEquals(congestionControl, reply.sample.qos.congestionControl) - } - - @Test - fun queryReplyErrorTest() { - val message = "Error message" - val queryable = session.declareQueryable(testKeyExpr).with { - it.use { query -> - query.reply(testKeyExpr).error(Value(message)).res() - } - }.res() - - var receivedReply: Reply? = null - session.get(testKeyExpr).with { receivedReply = it }.timeout(Duration.ofMillis(10)).res() - - Thread.sleep(1000) - queryable.close() - - assertNotNull(receivedReply) - assertTrue(receivedReply is Reply.Error) - val reply = receivedReply as Reply.Error - assertEquals(message, reply.error.payload.decodeToString()) - } - - @Test - fun queryReplyDeleteTest() { - val timestamp = TimeStamp.getCurrentTime() - val priority = Priority.DATA_HIGH - val express = true - val congestionControl = CongestionControl.DROP - val queryable = session.declareQueryable(testKeyExpr).with { - it.use { query -> - query.reply(testKeyExpr).delete().timestamp(timestamp).priority(priority).express(express) - .congestionControl(congestionControl).res() - } - }.res() - - var receivedReply: Reply? = null - session.get(testKeyExpr).with { receivedReply = it }.timeout(Duration.ofMillis(10)).res() - - queryable.close() - - assertNotNull(receivedReply) - assertTrue(receivedReply is Reply.Delete) - val reply = receivedReply as Reply.Delete - assertEquals(timestamp, reply.timestamp) - assertEquals(priority, reply.qos.priority) - assertEquals(express, reply.qos.express) - assertEquals(congestionControl, reply.qos.congestionControl) - } - - @Test - fun onCloseTest() { - var onCloseWasCalled = false - val queryable = session.declareQueryable(testKeyExpr).onClose { onCloseWasCalled = true }.res() - queryable.undeclare() - - assertTrue(onCloseWasCalled) - } -} - -/** A dummy handler that replies "Hello queryable" followed by the count of replies performed. */ -private class QueryHandler : Handler { - - private var counter = 0 - - val performedReplies: ArrayList = ArrayList() - - override fun handle(t: Query) { - reply(t) - } - - override fun receiver(): QueryHandler { - return this - } - - override fun onClose() {} - - fun reply(query: Query) { - val payload = "Hello queryable $counter!" - counter++ - val sample = Sample( - query.keyExpr, Value(payload), SampleKind.PUT, TimeStamp(Date.from(Instant.now())), QoS.default() - ) - performedReplies.add(sample) - query.reply(query.keyExpr).success(sample.value).timestamp(sample.timestamp!!).res() - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt deleted file mode 100644 index b0102e70..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SelectorTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.zenoh - -import io.zenoh.exceptions.ZError -import io.zenoh.query.Selector -import io.zenoh.query.intoSelector -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - -class SelectorTest { - - init { - Zenoh.load() - } - - @Test - fun selectorFromStringTest() { - "a/b/c?arg1=val1".intoSelector().use { selector: Selector -> - assertEquals("a/b/c", selector.keyExpr.toString()) - assertEquals("arg1=val1", selector.parameters) - } - - "a/b/c".intoSelector().use { selector: Selector -> - assertEquals("a/b/c", selector.keyExpr.toString()) - assertEquals("", selector.parameters) - } - - assertFailsWith { "".intoSelector() } - } -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt deleted file mode 100644 index 10bef2f9..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SessionTest.kt +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.sample.Sample -import kotlin.test.* - -class SessionTest { - - companion object { - val TEST_KEY_EXP = "example/testing/keyexpr".intoKeyExpr() - } - - @Test - fun sessionStartCloseTest() { - val session = Session.open() - assertTrue(session.isOpen()) - session.close() - assertFalse(session.isOpen()) - } - - @Test - fun sessionStop_stopUnopenedSessionIsNoOp() { - val session = Session.open() - session.close() - } - - @Test - fun sessionClose_doesNotThrowExceptionWhenStoppingSessionWithActiveDeclarations() { - val session = Session.open() - session.declarePublisher(TEST_KEY_EXP) - session.close() - } - - @Test - fun sessionDeclare_sessionIsOpenFromInitialization() { - val session = Session.open() - assertTrue(session.isOpen()) - session.close() - } - - @Test - fun sessionClose_newDeclarationsReturnNullAfterClosingSession() { - val session = Session.open() - session.close() - assertFailsWith { session.declarePublisher(TEST_KEY_EXP).res() } - assertFailsWith { session.declareSubscriber(TEST_KEY_EXP).with {}.res() } - assertFailsWith { session.declareQueryable(TEST_KEY_EXP).with {}.res() } - } - -} diff --git a/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt b/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt deleted file mode 100644 index 69bc6ca9..00000000 --- a/zenoh-java/src/commonTest/kotlin/io/zenoh/SubscriberTest.kt +++ /dev/null @@ -1,150 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -import io.zenoh.handlers.Handler -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.keyexpr.intoKeyExpr -import io.zenoh.qos.CongestionControl -import io.zenoh.prelude.Encoding -import io.zenoh.qos.Priority -import io.zenoh.sample.Sample -import io.zenoh.value.Value -import java.util.* -import java.util.concurrent.BlockingQueue -import kotlin.collections.ArrayDeque -import kotlin.collections.ArrayList -import kotlin.test.* - -class SubscriberTest { - - companion object { - val TEST_PRIORITY = Priority.DATA_HIGH; - val TEST_CONGESTION_CONTROL = CongestionControl.BLOCK; - - val testValues = arrayListOf( - Value("Test 1".encodeToByteArray(), Encoding(Encoding.ID.TEXT_PLAIN)), - Value("Test 2".encodeToByteArray(), Encoding(Encoding.ID.TEXT_JSON)), - Value("Test 3".encodeToByteArray(), Encoding(Encoding.ID.TEXT_CSV)) - ) - } - - private lateinit var session: Session - private lateinit var testKeyExpr: KeyExpr - - @BeforeTest - fun setUp() { - session = Session.open() - testKeyExpr = "example/testing/keyexpr".intoKeyExpr() - } - - @AfterTest - fun tearDown() { - session.close() - testKeyExpr.close() - } - - @Test - fun subscriber_runsWithCallback() { - val receivedSamples = ArrayList() - val subscriber = - session.declareSubscriber(testKeyExpr).with { sample -> receivedSamples.add(sample) }.res() - - testValues.forEach { value -> - session.put(testKeyExpr, value) - .priority(TEST_PRIORITY) - .congestionControl(TEST_CONGESTION_CONTROL) - .res() - } - assertEquals(receivedSamples.size, testValues.size) - - receivedSamples.zip(testValues).forEach { (sample, value) -> - assertEquals(sample.value, value) - assertEquals(sample.qos.priority(), TEST_PRIORITY) - assertEquals(sample.qos.congestionControl(), TEST_CONGESTION_CONTROL) - } - - subscriber.close() - } - - @Test - fun subscriber_runsWithHandler() { - val handler = QueueHandler() - val subscriber = session.declareSubscriber(testKeyExpr).with(handler).res() - - testValues.forEach { value -> - session.put(testKeyExpr, value) - .priority(TEST_PRIORITY) - .congestionControl(TEST_CONGESTION_CONTROL) - .res() - } - assertEquals(handler.queue.size, testValues.size) - - handler.queue.zip(testValues).forEach { (sample, value) -> - assertEquals(sample.value, value) - assertEquals(sample.qos.priority(), TEST_PRIORITY) - assertEquals(sample.qos.congestionControl(), TEST_CONGESTION_CONTROL) - } - - subscriber.close() - } - - @Test - fun subscriberBuilder_queueHandlerIsTheDefaultHandler() { - val subscriber = session.declareSubscriber(testKeyExpr).res() - subscriber.close() - assertTrue(subscriber.receiver is BlockingQueue>) - } - - @Test - fun subscriber_isDeclaredWithNonDeclaredKeyExpression() { - // Declaring a subscriber with an undeclared key expression and verifying it properly receives samples. - val keyExpr = KeyExpr("example/**") - val session = Session.open() - - val receivedSamples = ArrayList() - val subscriber = session.declareSubscriber(keyExpr).with { sample -> receivedSamples.add(sample) }.res() - testValues.forEach { value -> session.put(testKeyExpr, value).res() } - subscriber.close() - - assertEquals(receivedSamples.size, testValues.size) - - for ((index, sample) in receivedSamples.withIndex()) { - assertEquals(sample.value, testValues[index]) - } - } - - @Test - fun onCloseTest() { - var onCloseWasCalled = false - val subscriber = session.declareSubscriber(testKeyExpr).onClose { onCloseWasCalled = true }.res() - subscriber.undeclare() - assertTrue(onCloseWasCalled) - } -} - -private class QueueHandler : Handler> { - - val queue: ArrayDeque = ArrayDeque() - override fun handle(t: T) { - queue.add(t) - } - - override fun receiver(): ArrayDeque { - return queue - } - - override fun onClose() {} -} diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java new file mode 100644 index 00000000..357398de --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -0,0 +1,355 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +package io.zenoh; + +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.sample.Sample; +import kotlin.Unit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class ConfigTest { + + private static final String json5ClientConfigString = + "{\n" + + " mode: \"peer\",\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " },\n" + + " scouting: {\n" + + " multicast: {\n" + + " enabled: false\n" + + " }\n" + + " }\n" + + "}"; + + private static final String json5ServerConfigString = + "{\n" + + " mode: \"peer\",\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7450\"],\n" + + " },\n" + + " scouting: {\n" + + " multicast: {\n" + + " enabled: false,\n" + + " }\n" + + " }\n" + + "}"; + + private static final String jsonClientConfigString = + "{\n" + + " \"mode\": \"peer\",\n" + + " \"connect\": {\n" + + " \"endpoints\": [\"tcp/localhost:7450\"]\n" + + " },\n" + + " \"scouting\": {\n" + + " \"multicast\": {\n" + + " \"enabled\": false\n" + + " }\n" + + " }\n" + + "}"; + + private static final String jsonServerConfigString = + "{\n" + + " \"mode\": \"peer\",\n" + + " \"listen\": {\n" + + " \"endpoints\": [\"tcp/localhost:7450\"]\n" + + " },\n" + + " \"scouting\": {\n" + + " \"multicast\": {\n" + + " \"enabled\": false\n" + + " }\n" + + " }\n" + + "}"; + + private static final String yamlClientConfigString = + "mode: peer\n" + + "connect:\n" + + " endpoints:\n" + + " - tcp/localhost:7450\n" + + "scouting:\n" + + " multicast:\n" + + " enabled: false\n"; + + private static final String yamlServerConfigString = + "mode: peer\n" + + "listen:\n" + + " endpoints:\n" + + " - tcp/localhost:7450\n" + + "scouting:\n" + + " multicast:\n" + + " enabled: false\n"; + + private static final KeyExpr TEST_KEY_EXP; + private static final Config json5ClientConfig; + private static final Config json5ServerConfig; + private static final Config jsonClientConfig; + private static final Config jsonServerConfig; + private static final Config yamlClientConfig; + private static final Config yamlServerConfig; + + static { + try { + TEST_KEY_EXP = KeyExpr.tryFrom("example/testing/keyexpr"); + json5ClientConfig = Config.fromJson5(json5ClientConfigString); + json5ServerConfig = Config.fromJson5(json5ServerConfigString); + + jsonClientConfig = Config.fromJson(jsonClientConfigString); + jsonServerConfig = Config.fromJson(jsonServerConfigString); + + yamlClientConfig = Config.fromYaml(yamlClientConfigString); + yamlServerConfig = Config.fromYaml(yamlServerConfigString); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + + private void runSessionTest(Config clientConfig, Config serverConfig) throws ZError, InterruptedException { + Session sessionClient = Zenoh.open(clientConfig); + Session sessionServer = Zenoh.open(serverConfig); + + final Sample[] receivedSample = new Sample[1]; + + Subscriber subscriber = sessionClient.declareSubscriber(TEST_KEY_EXP).callback( + sample -> receivedSample[0] = sample + ).res(); + + ZBytes payload = ZBytes.from("example message"); + sessionClient.put(TEST_KEY_EXP, payload).res(); + + Thread.sleep(1000); + + subscriber.close(); + sessionClient.close(); + sessionServer.close(); + + assertNotNull(receivedSample[0]); + assertEquals(receivedSample[0].getPayload(), payload); + } + + @Test + public void testConfigWithJSON5() throws ZError, InterruptedException { + runSessionTest(json5ClientConfig, json5ServerConfig); + } + + @Test + public void testConfigLoadsFromJSONString() throws ZError, InterruptedException { + runSessionTest(jsonClientConfig, jsonServerConfig); + } + + + @Test + public void testConfigLoadsFromYAMLString() throws ZError, InterruptedException { + runSessionTest(yamlClientConfig, yamlServerConfig); + } + + @Test + public void testDefaultConfig() throws ZError { + Config config = Config.loadDefault(); + Session session = Zenoh.open(config); + session.close(); + } + + @Test + public void configFailsWithIllFormatedJsonTest() throws ZError { + String illFormattedConfig = + "{\n" + + " mode: \"peer\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"],\n" + + // missing '}' character here + "}"; + + assertThrows(ZError.class, () -> Config.fromJson(illFormattedConfig)); + } + + @Test + public void configFailsWithIllFormatedYAMLTest() { + String illFormattedConfig = + "mode: peer\n" + + "connect:\n" + + " endpoints:\n" + + " - tcp/localhost:7450\n" + + "scouting\n"; + + assertThrows(ZError.class, () -> Config.fromJson(illFormattedConfig)); + } + + @Test + public void configLoadsFromJSONFileTest() throws IOException, ZError, InterruptedException { + File clientConfigFile = File.createTempFile("clientConfig", ".json"); + File serverConfigFile = File.createTempFile("serverConfig", ".json"); + + try { + // Writing text to the files + Files.write(clientConfigFile.toPath(), jsonClientConfigString.getBytes()); + Files.write(serverConfigFile.toPath(), jsonServerConfigString.getBytes()); + + Config loadedClientConfig = Config.fromFile(clientConfigFile); + Config loadedServerConfig = Config.fromFile(serverConfigFile); + + runSessionTest(loadedClientConfig, loadedServerConfig); + } finally { + clientConfigFile.delete(); + serverConfigFile.delete(); + } + } + + @Test + public void configLoadsFromYAMLFileTest() throws IOException, ZError, InterruptedException { + File clientConfigFile = File.createTempFile("clientConfig", ".yaml"); + File serverConfigFile = File.createTempFile("serverConfig", ".yaml"); + + try { + // Writing text to the files + Files.write(clientConfigFile.toPath(), yamlClientConfigString.getBytes()); + Files.write(serverConfigFile.toPath(), yamlServerConfigString.getBytes()); + + Config loadedClientConfig = Config.fromFile(clientConfigFile); + Config loadedServerConfig = Config.fromFile(serverConfigFile); + + runSessionTest(loadedClientConfig, loadedServerConfig); + } finally { + clientConfigFile.delete(); + serverConfigFile.delete(); + } + } + + @Test + public void configLoadsFromJSON5FileTest() throws IOException, ZError, InterruptedException { + File clientConfigFile = File.createTempFile("clientConfig", ".json5"); + File serverConfigFile = File.createTempFile("serverConfig", ".json5"); + + try { + // Writing text to the files + Files.write(clientConfigFile.toPath(), json5ClientConfigString.getBytes()); + Files.write(serverConfigFile.toPath(), json5ServerConfigString.getBytes()); + + Config loadedClientConfig = Config.fromFile(clientConfigFile); + Config loadedServerConfig = Config.fromFile(serverConfigFile); + + runSessionTest(loadedClientConfig, loadedServerConfig); + } finally { + clientConfigFile.delete(); + serverConfigFile.delete(); + } + } + + @Test + public void configLoadsFromJSON5FileProvidingPathTest() throws IOException, ZError, InterruptedException { + File clientConfigFile = File.createTempFile("clientConfig", ".json5"); + File serverConfigFile = File.createTempFile("serverConfig", ".json5"); + + try { + // Writing text to the files + Files.write(clientConfigFile.toPath(), json5ClientConfigString.getBytes()); + Files.write(serverConfigFile.toPath(), json5ServerConfigString.getBytes()); + + Config loadedClientConfig = Config.fromFile(clientConfigFile.toPath()); + Config loadedServerConfig = Config.fromFile(serverConfigFile.toPath()); + + runSessionTest(loadedClientConfig, loadedServerConfig); + } finally { + clientConfigFile.delete(); + serverConfigFile.delete(); + } + } + + @Test + public void getJsonFunctionTest() throws ZError { + String jsonConfig = + "{\n" + + " mode: \"peer\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"],\n" + + " },\n" + + " scouting: {\n" + + " multicast: {\n" + + " enabled: false,\n" + + " }\n" + + " }\n" + + "}"; + + Config config = Config.fromJson(jsonConfig); + + String value = config.getJson("connect"); + assertTrue(value.contains("\"endpoints\":[\"tcp/localhost:7450\"]")); + + String value2 = config.getJson("mode"); + assertEquals("\"peer\"", value2); + } + + @Test + public void configShouldRemainValidDespiteFailingToGetJsonValue() throws ZError { + String jsonConfig = + "{\n" + + " mode: \"peer\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"],\n" + + " },\n" + + " scouting: {\n" + + " multicast: {\n" + + " enabled: false,\n" + + " }\n" + + " }\n" + + "}"; + + Config config = Config.fromJson(jsonConfig); + + assertThrows(ZError.class, () -> { + config.getJson("non_existent_key"); + }); + + String mode = config.getJson("mode"); + assertEquals("\"peer\"", mode); + } + + @Test + public void insertJson5FunctionTest() throws ZError { + Config config = Config.loadDefault(); + String endpoints = "[\"tcp/8.8.8.8:8\", \"tcp/8.8.8.8:9\"]"; + + config.insertJson5("listen/endpoints", endpoints); + + String jsonValue = config.getJson("listen/endpoints"); + assertTrue(jsonValue.contains("8.8.8.8")); + } + + @Test + public void insertIllFormattedJson5ShouldFailTest() throws ZError { + Config config = Config.loadDefault(); + + String illFormattedEndpoints = "[\"tcp/8.8.8.8:8\""; + assertThrows(ZError.class, () -> { + config.insertJson5("listen/endpoints", illFormattedEndpoints); + }); + + String correctEndpoints = "[\"tcp/8.8.8.8:8\", \"tcp/8.8.8.8:9\"]"; + config.insertJson5("listen/endpoints", correctEndpoints); + String retrievedEndpoints = config.getJson("listen/endpoints"); + + assertTrue(retrievedEndpoints.contains("8.8.8.8")); + } +} From 4869b074270fbbb2664b881c995909225c465772 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 12 Nov 2024 14:18:03 -0300 Subject: [PATCH 30/83] Alignment: wip - converting tests to java tests. Added delete test. --- .../kotlin/io/zenoh/pubsub/Delete.kt | 1 + .../src/jvmTest/java/io/zenoh/DeleteTest.java | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt index 2741a7d7..b43dc3c1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt @@ -112,6 +112,7 @@ class Delete private constructor( */ @Throws(ZError::class) override fun res() { + // TODO: replace res() with delete() val delete = Delete(this.keyExpr, qosBuilder.build(), reliability, attachment) session.resolveDelete(keyExpr, delete) } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java new file mode 100644 index 00000000..5bb9cc2d --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java @@ -0,0 +1,47 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.sample.SampleKind; +import io.zenoh.sample.Sample; +import kotlin.Unit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(JUnit4.class) +public class DeleteTest { + + @Test + public void deleteIsProperlyReceivedBySubscriberTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + final Sample[] receivedSample = new Sample[1]; + KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + Subscriber subscriber = session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample).res(); + session.delete(keyExpr).res(); + + Thread.sleep(1000); + subscriber.close(); + session.close(); + assertNotNull(receivedSample[0]); + assertEquals(receivedSample[0].getKind(), SampleKind.DELETE); + } +} From f2d666dbb58f46562a23cf815c1d9af0d9ab2594 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 12 Nov 2024 23:52:54 -0300 Subject: [PATCH 31/83] Alignment: wip - converting tests to java tests. Added encoding tests. --- .../kotlin/io/zenoh/bytes/Encoding.kt | 57 ++++- .../kotlin/io/zenoh/jni/JNIPublisher.kt | 2 +- .../kotlin/io/zenoh/jni/JNISession.kt | 2 +- .../kotlin/io/zenoh/pubsub/Publisher.kt | 2 +- .../commonMain/kotlin/io/zenoh/pubsub/Put.kt | 2 +- .../commonMain/kotlin/io/zenoh/query/Get.kt | 7 +- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 4 +- .../jvmTest/java/io/zenoh/EncodingTest.java | 204 ++++++++++++++++++ 8 files changed, 272 insertions(+), 8 deletions(-) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt index e9c14984..a4f77815 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt @@ -33,6 +33,7 @@ class Encoding private constructor( internal constructor(id: Int, schema: String? = null) : this(id, schema, null) companion object { + /** * Just some bytes. * @@ -40,6 +41,7 @@ class Encoding private constructor( * * Usually used for types: `ByteArray`, `List`. */ + @JvmField val ZENOH_BYTES = Encoding(0, description = "zenoh/bytes") /** @@ -49,6 +51,7 @@ class Encoding private constructor( * * Usually used for type: `String`. */ + @JvmField val ZENOH_STRING = Encoding(1, description = "zenoh/string") /** @@ -56,6 +59,7 @@ class Encoding private constructor( * * Constant alias for string: `"zenoh/serialized"`. */ + @JvmField val ZENOH_SERIALIZED = Encoding(2, description = "zenoh/serialized") /** @@ -63,6 +67,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/octet-stream"`. */ + @JvmField val APPLICATION_OCTET_STREAM = Encoding(3, description = "application/octet-stream") /** @@ -70,6 +75,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/plain"`. */ + @JvmField val TEXT_PLAIN = Encoding(4, description = "text/plain") /** @@ -77,6 +83,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/json"`. */ + @JvmField val APPLICATION_JSON = Encoding(5, description = "application/json") /** @@ -84,6 +91,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/json"`. */ + @JvmField val TEXT_JSON = Encoding(6, description = "text/json") /** @@ -91,6 +99,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/cdr"`. */ + @JvmField val APPLICATION_CDR = Encoding(7, description = "application/cdr") /** @@ -98,6 +107,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/cbor"`. */ + @JvmField val APPLICATION_CBOR = Encoding(8, description = "application/cbor") /** @@ -105,6 +115,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/yaml"`. */ + @JvmField val APPLICATION_YAML = Encoding(9, description = "application/yaml") /** @@ -112,6 +123,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/yaml"`. */ + @JvmField val TEXT_YAML = Encoding(10, description = "text/yaml") /** @@ -119,6 +131,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/json5"`. */ + @JvmField val TEXT_JSON5 = Encoding(11, description = "text/json5") /** @@ -126,6 +139,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/python-serialized-object"`. */ + @JvmField val APPLICATION_PYTHON_SERIALIZED_OBJECT = Encoding(12, description = "application/python-serialized-object") @@ -134,6 +148,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/protobuf"`. */ + @JvmField val APPLICATION_PROTOBUF = Encoding(13, description = "application/protobuf") /** @@ -141,6 +156,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/java-serialized-object"`. */ + @JvmField val APPLICATION_JAVA_SERIALIZED_OBJECT = Encoding(14, description = "application/java-serialized-object") @@ -149,6 +165,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/openmetrics-text"`. */ + @JvmField val APPLICATION_OPENMETRICS_TEXT = Encoding(15, description = "application/openmetrics-text") @@ -157,6 +174,7 @@ class Encoding private constructor( * * Constant alias for string: `"image/png"`. */ + @JvmField val IMAGE_PNG = Encoding(16, description = "image/png") /** @@ -164,6 +182,7 @@ class Encoding private constructor( * * Constant alias for string: `"image/jpeg"`. */ + @JvmField val IMAGE_JPEG = Encoding(17, description = "image/jpeg") /** @@ -171,6 +190,7 @@ class Encoding private constructor( * * Constant alias for string: `"image/gif"`. */ + @JvmField val IMAGE_GIF = Encoding(18, description = "image/gif") /** @@ -178,6 +198,7 @@ class Encoding private constructor( * * Constant alias for string: `"image/bmp"`. */ + @JvmField val IMAGE_BMP = Encoding(19, description = "image/bmp") /** @@ -185,6 +206,7 @@ class Encoding private constructor( * * Constant alias for string: `"image/webp"`. */ + @JvmField val IMAGE_WEBP = Encoding(20, description = "image/webp") /** @@ -192,6 +214,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/xml"`. */ + @JvmField val APPLICATION_XML = Encoding(21, description = "application/xml") /** @@ -199,6 +222,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/x-www-form-urlencoded"`. */ + @JvmField val APPLICATION_X_WWW_FORM_URLENCODED = Encoding(22, description = "application/x-www-form-urlencoded") @@ -207,6 +231,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/html"`. */ + @JvmField val TEXT_HTML = Encoding(23, description = "text/html") /** @@ -214,6 +239,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/xml"`. */ + @JvmField val TEXT_XML = Encoding(24, description = "text/xml") /** @@ -221,6 +247,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/css"`. */ + @JvmField val TEXT_CSS = Encoding(25, description = "text/css") /** @@ -228,6 +255,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/javascript"`. */ + @JvmField val TEXT_JAVASCRIPT = Encoding(26, description = "text/javascript") /** @@ -235,6 +263,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/markdown"`. */ + @JvmField val TEXT_MARKDOWN = Encoding(27, description = "text/markdown") /** @@ -242,6 +271,7 @@ class Encoding private constructor( * * Constant alias for string: `"text/csv"`. */ + @JvmField val TEXT_CSV = Encoding(28, description = "text/csv") /** @@ -249,6 +279,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/sql"`. */ + @JvmField val APPLICATION_SQL = Encoding(29, description = "application/sql") /** @@ -256,6 +287,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/coap-payload"`. */ + @JvmField val APPLICATION_COAP_PAYLOAD = Encoding(30, description = "application/coap-payload") /** @@ -263,6 +295,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/json-patch+json"`. */ + @JvmField val APPLICATION_JSON_PATCH_JSON = Encoding(31, description = "application/json-patch+json") /** @@ -270,6 +303,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/json-seq"`. */ + @JvmField val APPLICATION_JSON_SEQ = Encoding(32, description = "application/json-seq") /** @@ -277,6 +311,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/jsonpath"`. */ + @JvmField val APPLICATION_JSONPATH = Encoding(33, description = "application/jsonpath") /** @@ -284,6 +319,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/jwt"`. */ + @JvmField val APPLICATION_JWT = Encoding(34, description = "application/jwt") /** @@ -291,6 +327,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/mp4"`. */ + @JvmField val APPLICATION_MP4 = Encoding(35, description = "application/mp4") /** @@ -298,6 +335,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/soap+xml"`. */ + @JvmField val APPLICATION_SOAP_XML = Encoding(36, description = "application/soap+xml") /** @@ -305,6 +343,7 @@ class Encoding private constructor( * * Constant alias for string: `"application/yang"`. */ + @JvmField val APPLICATION_YANG = Encoding(37, description = "application/yang") /** @@ -312,6 +351,7 @@ class Encoding private constructor( * * Constant alias for string: `"audio/aac"`. */ + @JvmField val AUDIO_AAC = Encoding(38, description = "audio/aac") /** @@ -319,6 +359,7 @@ class Encoding private constructor( * * Constant alias for string: `"audio/flac"`. */ + @JvmField val AUDIO_FLAC = Encoding(39, description = "audio/flac") /** @@ -326,6 +367,7 @@ class Encoding private constructor( * * Constant alias for string: `"audio/mp4"`. */ + @JvmField val AUDIO_MP4 = Encoding(40, description = "audio/mp4") /** @@ -333,6 +375,7 @@ class Encoding private constructor( * * Constant alias for string: `"audio/ogg"`. */ + @JvmField val AUDIO_OGG = Encoding(41, description = "audio/ogg") /** @@ -340,6 +383,7 @@ class Encoding private constructor( * * Constant alias for string: `"audio/vorbis"`. */ + @JvmField val AUDIO_VORBIS = Encoding(42, description = "audio/vorbis") /** @@ -347,6 +391,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/h261"`. */ + @JvmField val VIDEO_H261 = Encoding(43, description = "video/h261") /** @@ -354,6 +399,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/h263"`. */ + @JvmField val VIDEO_H263 = Encoding(44, description = "video/h263") /** @@ -361,6 +407,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/h264"`. */ + @JvmField val VIDEO_H264 = Encoding(45, description = "video/h264") /** @@ -368,6 +415,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/h265"`. */ + @JvmField val VIDEO_H265 = Encoding(46, description = "video/h265") /** @@ -375,6 +423,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/h266"`. */ + @JvmField val VIDEO_H266 = Encoding(47, description = "video/h266") /** @@ -382,6 +431,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/mp4"`. */ + @JvmField val VIDEO_MP4 = Encoding(48, description = "video/mp4") /** @@ -389,6 +439,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/ogg"`. */ + @JvmField val VIDEO_OGG = Encoding(49, description = "video/ogg") /** @@ -396,6 +447,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/raw"`. */ + @JvmField val VIDEO_RAW = Encoding(50, description = "video/raw") /** @@ -403,6 +455,7 @@ class Encoding private constructor( * * Constant alias for string: `"video/vp8"`. */ + @JvmField val VIDEO_VP8 = Encoding(51, description = "video/vp8") /** @@ -410,12 +463,14 @@ class Encoding private constructor( * * Constant alias for string: `"video/vp9"`. */ + @JvmField val VIDEO_VP9 = Encoding(52, description = "video/vp9") /** * The default [Encoding] is [ZENOH_BYTES]. */ - fun default() = ZENOH_BYTES + @JvmStatic + fun defaultEncoding() = ZENOH_BYTES } /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt index 9db2522a..2ee414bc 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt @@ -34,7 +34,7 @@ internal class JNIPublisher(private val ptr: Long) { */ @Throws(ZError::class) fun put(payload: IntoZBytes, encoding: Encoding?, attachment: IntoZBytes?) { - val resolvedEncoding = encoding ?: Encoding.default() + val resolvedEncoding = encoding ?: Encoding.defaultEncoding() putViaJNI(payload.into().bytes, resolvedEncoding.id, resolvedEncoding.schema, attachment?.into()?.bytes, ptr) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index a05de0e1..62d105db 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -200,7 +200,7 @@ internal class JNISession { consolidation.ordinal, attachment?.into()?.bytes, payload?.into()?.bytes, - encoding?.id ?: Encoding.default().id, + encoding?.id ?: Encoding.defaultEncoding().id, encoding?.schema ) return receiver diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 91135a7f..31f0bc4f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -144,7 +144,7 @@ class Publisher internal constructor( ) { private var reliability: Reliability = Reliability.RELIABLE private var qos = QoS.default() - private var encoding: Encoding = Encoding.default() + private var encoding: Encoding = Encoding.defaultEncoding() fun encoding(encoding: Encoding) { this.encoding = encoding diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt index 8368974f..13c0d863 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt @@ -131,7 +131,7 @@ class Put private constructor( @Throws(ZError::class) override fun res() { // TODO: rename res() to put() - val put = Put(keyExpr, payload.into(), encoding ?: Encoding.default(), qosBuilder.build(), reliability, attachment) + val put = Put(keyExpr, payload.into(), encoding ?: Encoding.defaultEncoding(), qosBuilder.build(), reliability, attachment) session.run { resolvePut(keyExpr, put) } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index e85d154a..3ec8ab4f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -131,6 +131,11 @@ class Get private constructor() { return this } + fun encoding(encoding: Encoding): Builder { + this.encoding = encoding + return this + } + /** Specify an attachment. */ fun withAttachment(attachment: IntoZBytes): Builder { this.attachment = attachment.into() @@ -148,7 +153,7 @@ class Get private constructor() { } /** Specify a [Callback]. Overrides any previously specified callback or handler. */ - fun with(callback: Callback): Builder = Builder(this, callback) + fun callback(callback: Callback): Builder = Builder(this, callback) /** Specify a [Handler]. Overrides any previously specified callback or handler. */ fun with(handler: Handler): Builder = Builder(this, handler) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index a34349c8..4a25991f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -98,7 +98,7 @@ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { class ReplyBuilder internal constructor(val query: Query, val keyExpr: KeyExpr, val payload: ZBytes, val kind: SampleKind): Resolvable { - private var encoding: Encoding = Encoding.default() + private var encoding: Encoding = Encoding.defaultEncoding() private var timeStamp: TimeStamp? = null private var attachment: ZBytes? = null private var qosBuilder = QoS.Builder() @@ -146,7 +146,7 @@ class ReplyBuilder internal constructor(val query: Query, val keyExpr: KeyExpr, class ReplyErrBuilder internal constructor(val query: Query, val payload: ZBytes): Resolvable { - private var encoding: Encoding = Encoding.default() + private var encoding: Encoding = Encoding.defaultEncoding() fun encoding(encoding: Encoding) = apply { this.encoding = encoding } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java new file mode 100644 index 00000000..7c31cbc6 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -0,0 +1,204 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.bytes.Encoding; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.query.Queryable; +import io.zenoh.query.Reply; +import io.zenoh.query.Selector; +import io.zenoh.sample.Sample; +import kotlin.Unit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class EncodingTest { + + private static final Encoding without_schema = Encoding.TEXT_CSV; + private static final Encoding with_schema = Encoding.APPLICATION_JSON.withSchema("test_schema"); + private ZBytes payload = ZBytes.from("test"); + + @Test + public void encoding_subscriberTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + + // Testing non null schema + Sample[] receivedSample = new Sample[1]; + Subscriber subscriber = session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample).res(); + + session.put(keyExpr, payload).encoding(with_schema).res(); + Thread.sleep(200); + + assertNotNull(receivedSample[0]); + assertEquals(receivedSample[0].getEncoding(), with_schema); + + // Testing null schema + receivedSample[0] = null; + session.put(keyExpr, payload).encoding(without_schema).res(); + Thread.sleep(200); + + assertEquals(receivedSample[0].getEncoding(), without_schema); + + subscriber.close(); + session.close(); + } + + @Test + public void encoding_replySuccessTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/**"); + Selector test1 = Selector.tryFrom("example/testing/reply_success"); + Selector test2 = Selector.tryFrom("example/testing/reply_success_with_schema"); + + Queryable queryable = session.declareQueryable(keyExpr).callback(query -> + { + try { + KeyExpr queryKeyExpr = query.getKeyExpr(); + if (queryKeyExpr.equals(test1.getKeyExpr())) { + query.reply(queryKeyExpr, payload).encoding(without_schema).res(); + } else if (queryKeyExpr.equals(test2.getKeyExpr())) { + query.reply(queryKeyExpr, payload).encoding(with_schema).res(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + ).res(); + + // Testing with null schema on a reply success scenario. + Sample[] receivedSample = new Sample[1]; + session.get(test1).callback(reply -> { + assertTrue(reply instanceof Reply.Success); + receivedSample[0] = ((Reply.Success) reply).getSample(); + }).res(); + Thread.sleep(200); + + assertNotNull(receivedSample[0]); + assertEquals(receivedSample[0].getEncoding(), without_schema); + + // Testing with non-null schema on a reply success scenario. + receivedSample[0] = null; + session.get(test2).callback(reply -> { + assertTrue(reply instanceof Reply.Success); + receivedSample[0] = ((Reply.Success) reply).getSample(); + }).res(); + Thread.sleep(200); + + assertNotNull(receivedSample[0]); + assertEquals(receivedSample[0].getEncoding(), with_schema); + + queryable.close(); + session.close(); + } + + @Test + public void encoding_replyErrorTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/**"); + Selector test1 = Selector.tryFrom("example/testing/reply_error"); + Selector test2 = Selector.tryFrom("example/testing/reply_error_with_schema"); + + ZBytes replyPayload = ZBytes.from("test"); + Queryable queryable = session.declareQueryable(keyExpr).callback(query -> + { + KeyExpr keyExpr1 = query.getKeyExpr(); + try { + if (keyExpr1.equals(test1.getKeyExpr())) { + query.replyErr(replyPayload).encoding(without_schema).res(); + } else if (keyExpr1.equals(test2.getKeyExpr())) { + query.replyErr(replyPayload).encoding(with_schema).res(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }).res(); + + // Testing with null schema on a reply error scenario. + ZBytes[] errorMessage = new ZBytes[1]; + Encoding[] errorEncoding = new Encoding[1]; + session.get(test1).callback(reply -> + { + assertTrue(reply instanceof Reply.Error); + Reply.Error reply1 = (Reply.Error) reply; + errorMessage[0] = reply1.getError(); + errorEncoding[0] = reply1.getEncoding(); + } + ).res(); + Thread.sleep(200); + + assertNotNull(errorMessage[0]); + assertEquals(errorEncoding[0], without_schema); + + Thread.sleep(200); + + // Testing with non-null schema on a reply error scenario. + errorMessage[0] = null; + errorEncoding[0] = null; + session.get(test2).callback(reply -> + { + assertTrue(reply instanceof Reply.Error); + Reply.Error error = (Reply.Error) reply; + errorMessage[0] = error.getError(); + errorEncoding[0] = error.getEncoding(); + }).res(); + Thread.sleep(200); + + assertNotNull(errorMessage[0]); + assertEquals(errorEncoding[0], with_schema); + + queryable.close(); + session.close(); + } + + @Test + public void encoding_queryTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + Selector selector = Selector.tryFrom("example/testing/keyexpr"); + + Encoding[] receivedEncoding = new Encoding[1]; + Queryable queryable = session.declareQueryable(keyExpr).callback(query -> + { + receivedEncoding[0] = query.getEncoding(); + query.close(); + }).res(); + + // Testing with null schema + session.get(selector).callback(reply -> {}).payload(payload).encoding(without_schema).res(); + Thread.sleep(200); + + assertEquals(receivedEncoding[0], without_schema); + + Thread.sleep(200); + + // Testing non-null schema + receivedEncoding[0] = null; + session.get(selector).callback(reply -> {}).payload(payload).encoding(with_schema).res(); + Thread.sleep(200); + + assertEquals(receivedEncoding[0], with_schema); + + queryable.close(); + session.close(); + } +} From 8badd0c92d00c0b6bd01d2c40b111e72b7fa4f48 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 13 Nov 2024 13:00:37 -0300 Subject: [PATCH 32/83] Alignment: wip - converting tests to java tests. Added get tests. --- .../kotlin/io/zenoh/query/Parameters.kt | 3 + .../src/jvmTest/java/io/zenoh/GetTest.java | 120 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt index 85d61e68..33573314 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt @@ -40,11 +40,13 @@ data class Parameters internal constructor(private val params: MutableMap): Parameters = Parameters(params.toMutableMap()) /** @@ -58,6 +60,7 @@ data class Parameters internal constructor(private val params: MutableMap queryable; + + @Before + public void setUp() throws ZError { + session = Zenoh.open(Config.loadDefault()); + selector = Selector.tryFrom("example/testing/keyexpr"); + queryable = session.declareQueryable(selector.getKeyExpr()).callback( query -> + { + try { + query.reply(query.getKeyExpr(), payload).timestamp(timestamp).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ).res(); + } + + @After + public void tearDown() throws ZError { + session.close(); + selector.close(); + queryable.close(); + } + + @Test + public void get_runsWithCallbackTest() throws ZError { + Reply[] reply = new Reply[1]; + + session.get(selector).callback( reply1 -> { + reply[0] = reply1; + }).timeout(Duration.ofMillis(1000)).res(); + + assertNotNull(reply[0]); + Sample sample = ((Reply.Success) reply[0]).getSample(); + assertEquals(payload, sample.getPayload()); + assertEquals(kind, sample.getKind()); + assertEquals(selector.getKeyExpr(), sample.getKeyExpr()); + assertEquals(timestamp, sample.getTimestamp()); + } + + @Test + public void get_runsWithHandlerTest() throws ZError { + ArrayList receiver = session.get(selector).with(new TestHandler()).timeout(Duration.ofMillis(1000)).res(); + for (Reply reply : receiver) { + Sample sample = ((Reply.Success) reply).getSample(); + assertEquals(payload, sample.getPayload()); + assertEquals(SampleKind.PUT, sample.getKind()); + } + } + + @Test + public void getWithSelectorParamsTest() throws ZError { + Parameters[] receivedParams = new Parameters[1]; + + Queryable queryable = session.declareQueryable(selector.getKeyExpr()).callback( query -> + receivedParams[0] = query.getParameters() + ).res(); + + Parameters params = Parameters.from("arg1=val1&arg2=val2&arg3"); + Selector selectorWithParams = new Selector(selector.getKeyExpr(), params); + session.get(selectorWithParams).timeout(Duration.ofMillis(1000)).res(); + + queryable.close(); + + assertEquals(params, receivedParams[0]); + } +} + +/** A dummy handler for get operations. */ +class TestHandler implements Handler> { + + static final ArrayList performedReplies = new ArrayList<>(); + + @Override + public void handle(Reply t) { + performedReplies.add(t); + } + + @Override + public ArrayList receiver() { + return performedReplies; + } + + @Override + public void onClose() {} +} From 5f1c9209205a9a8a9c7555f0acba595aa67ff038 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 13 Nov 2024 16:52:04 -0300 Subject: [PATCH 33/83] Alignment: wip - converting tests to java tests. Added key expr tests. --- .../jvmTest/java/io/zenoh/KeyExprTest.java | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java new file mode 100644 index 00000000..a246b482 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java @@ -0,0 +1,166 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.keyexpr.SetIntersectionLevel; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class KeyExprTest { + + @Test + public void creation_TryFromTest() throws ZError { + // A couple of examples of valid and invalid key expressions. + KeyExpr keyExpr = KeyExpr.tryFrom("example/test"); + + assertThrows(ZError.class, () -> KeyExpr.tryFrom("example/test?param='test'")); + + KeyExpr keyExpr3 = KeyExpr.tryFrom("example/*/test"); + + assertThrows(ZError.class, () -> KeyExpr.tryFrom("example/!*/test")); + } + + @Test + public void equalizationTest() throws ZError { + KeyExpr keyExpr1 = KeyExpr.tryFrom("example/test"); + KeyExpr keyExpr2 = KeyExpr.tryFrom("example/test"); + assertEquals(keyExpr1, keyExpr2); + + KeyExpr keyExpr3 = KeyExpr.tryFrom("different/key/expr"); + assertNotEquals(keyExpr1, keyExpr3); + } + + @Test + public void creation_autocanonizeTest() throws ZError { + KeyExpr keyExpr1 = KeyExpr.autocanonize("example/**/test"); + KeyExpr keyExpr2 = KeyExpr.autocanonize("example/**/**/test"); + assertEquals(keyExpr1, keyExpr2); + } + + @Test + public void toStringTest() throws ZError { + String keyExprStr = "example/test/a/b/c"; + KeyExpr keyExpr = KeyExpr.tryFrom(keyExprStr); + assertEquals(keyExprStr, keyExpr.toString()); + assertEquals(keyExprStr, keyExpr.toString()); + } + + @Test + public void intersectionTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("example/*/test"); + + KeyExpr keyExprB = KeyExpr.tryFrom("example/B/test"); + assertTrue(keyExprA.intersects(keyExprB)); + + KeyExpr keyExprC = KeyExpr.tryFrom("example/B/C/test"); + assertFalse(keyExprA.intersects(keyExprC)); + + KeyExpr keyExprA2 = KeyExpr.tryFrom("example/**"); + assertTrue(keyExprA2.intersects(keyExprC)); + } + + @Test + public void includesTest() throws ZError { + KeyExpr keyExpr = KeyExpr.tryFrom("example/**"); + KeyExpr includedKeyExpr = KeyExpr.tryFrom("example/A/B/C/D"); + assertTrue(keyExpr.includes(includedKeyExpr)); + + KeyExpr notIncludedKeyExpr = KeyExpr.tryFrom("C/D"); + assertFalse(keyExpr.includes(notIncludedKeyExpr)); + } + + @Test + public void sessionDeclarationTest() throws ZError { + Session session = Zenoh.open(Config.loadDefault()); + KeyExpr keyExpr = session.declareKeyExpr("a/b/c").res(); + assertEquals("a/b/c", keyExpr.toString()); + session.close(); + keyExpr.close(); + } + + @Test + public void sessionUnDeclarationTest() throws ZError { + Session session = Zenoh.open(Config.loadDefault()); + KeyExpr keyExpr = session.declareKeyExpr("a/b/c").res(); + assertEquals("a/b/c", keyExpr.toString()); + + session.undeclare(keyExpr).res(); + + // Undeclaring twice a key expression shall fail. + assertThrows(ZError.class, () -> session.undeclare(keyExpr).res()); + + // Undeclaring a key expr that was not declared through a session. + KeyExpr keyExpr2 = KeyExpr.tryFrom("x/y/z"); + assertThrows(ZError.class, () -> session.undeclare(keyExpr2).res()); + + session.close(); + } + + @Test + public void relationTo_includesTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("A/**"); + KeyExpr keyExprB = KeyExpr.tryFrom("A/B/C"); + + assertEquals(SetIntersectionLevel.INCLUDES, keyExprA.relationTo(keyExprB)); + } + + @Test + public void relationTo_intersectsTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("A/*/C/D"); + KeyExpr keyExprB = KeyExpr.tryFrom("A/B/C/*"); + + assertEquals(SetIntersectionLevel.INTERSECTS, keyExprA.relationTo(keyExprB)); + } + + @Test + public void relationTo_equalsTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("A/B/C"); + KeyExpr keyExprB = KeyExpr.tryFrom("A/B/C"); + + assertEquals(SetIntersectionLevel.EQUALS, keyExprA.relationTo(keyExprB)); + } + + @Test + public void relationTo_disjointTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("A/B/C"); + KeyExpr keyExprB = KeyExpr.tryFrom("D/E/F"); + + assertEquals(SetIntersectionLevel.DISJOINT, keyExprA.relationTo(keyExprB)); + } + + @Test + public void joinTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("A/B"); + KeyExpr keyExprExpected = KeyExpr.tryFrom("A/B/C/D"); + + KeyExpr keyExprJoined = keyExprA.join("C/D"); + assertEquals(keyExprExpected, keyExprJoined); + } + + @Test + public void concatTest() throws ZError { + KeyExpr keyExprA = KeyExpr.tryFrom("A/B"); + KeyExpr keyExprExpected = KeyExpr.tryFrom("A/B/C/D"); + + KeyExpr keyExprConcat = keyExprA.concat("/C/D"); + assertEquals(keyExprExpected, keyExprConcat); + } +} From ce8147a37bdd610a0ad625afc48677bbf35053fd Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 13 Nov 2024 16:52:18 -0300 Subject: [PATCH 34/83] Alignment: wip - converting tests to java tests. Added parameters tests. --- .../jvmTest/java/io/zenoh/ParametersTest.java | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/ParametersTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ParametersTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ParametersTest.java new file mode 100644 index 00000000..0b6ab63b --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ParametersTest.java @@ -0,0 +1,125 @@ +package io.zenoh; + +import io.zenoh.query.Parameters; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class ParametersTest { + + @Test + public void shouldCreateEmptyParametersFromEmptyString() { + var result = Parameters.from(""); + + assertTrue(result.isEmpty()); + } + + @Test + public void shouldParseParametersFromFormattedString() { + var parameters = Parameters.from("a=1;b=2;c=3|4|5;d=6"); + + assertEquals("1", parameters.get("a")); + assertEquals("2", parameters.get("b")); + assertEquals("3|4|5", parameters.get("c")); + assertEquals("6", parameters.get("d")); + } + + @Test + public void shouldReturnListOfValuesSplitBySeparator() { + var parameters = Parameters.from("a=1;b=2;c=3|4|5;d=6"); + + assertEquals(List.of("3", "4", "5"), parameters.values("c")); + } + + @Test + public void containsKeyTest() { + var parameters = Parameters.from("a=1;b=2;c=3|4|5;d=6"); + + assertTrue(parameters.containsKey("a")); + assertFalse(parameters.containsKey("e")); + } + + @Test + public void getTest() { + var parameters = Parameters.from("a=1;b=2;c=3|4|5;d=6"); + + assertEquals("1", parameters.get("a")); + assertEquals("2", parameters.get("b")); + assertEquals("3|4|5", parameters.get("c")); + assertEquals("6", parameters.get("d")); + } + + @Test + public void getOrDefaultTest() { + var parameters = Parameters.from("a=1;b=2;c=3|4|5;d=6"); + + assertEquals("1", parameters.get("a")); + assertEquals("None", parameters.getOrDefault("e", "None")); + } + + @Test + public void toMapTest() { + var parameters = Parameters.from("a=1;b=2;c=3|4|5;d=6"); + + assertEquals(Map.of("a", "1", "b", "2", "c", "3|4|5", "d", "6"), parameters.toMap()); + } + + @Test + public void insertShouldReturnPreviouslyContainedValue() { + var parameters = Parameters.from("a=1"); + var oldValue = parameters.insert("a", "3"); + assertEquals("1", oldValue); + } + + @Test + public void insertShouldReturnNullIfNotAlreadyPresent() { + var parameters = Parameters.empty(); + var oldValue = parameters.insert("a", "1"); + assertNull(oldValue); + } + + @Test + public void removeShouldReturnOldValueIfPresent() { + var parameters = Parameters.from("a=1"); + var oldValue = parameters.remove("a"); + assertEquals("1", oldValue); + } + + @Test + public void removeShouldReturnNullIfNotAlreadyPresent() { + var parameters = Parameters.empty(); + var oldValue = parameters.remove("a"); + assertNull(oldValue); + } + + @Test + public void extendTest() { + var parameters = Parameters.from("a=1;b=2"); + parameters.extend(Parameters.from("c=3;d=4")); + + assertEquals(Parameters.from("a=1;b=2;c=3;d=4"), parameters); + + parameters.extend(Map.of("e", "5")); + assertEquals(Parameters.from("a=1;b=2;c=3;d=4;e=5"), parameters); + } + + @Test + public void extendOverwritesConflictingKeysTest() { + var parameters = Parameters.from("a=1;b=2"); + parameters.extend(Parameters.from("b=3;d=4")); + + assertEquals(Parameters.from("a=1;b=3;d=4"), parameters); + } + + @Test + public void emptyParametersToStringTest() { + var parameters = Parameters.empty(); + assertEquals("", parameters.toString()); + } +} From faccac950c6e6339909412e8de636c4405c68cfe Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 13 Nov 2024 16:52:28 -0300 Subject: [PATCH 35/83] Alignment: wip - converting tests to java tests. Added publisher tests. --- .../kotlin/io/zenoh/pubsub/Publisher.kt | 15 ++-- .../jvmTest/java/io/zenoh/PublisherTest.java | 90 +++++++++++++++++++ 2 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 31f0bc4f..3dea4110 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -80,7 +80,7 @@ class Publisher internal constructor( fun priority() = qos.priority /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ - fun put(payload: IntoZBytes) = PutBuilder(jniPublisher, payload) + fun put(payload: IntoZBytes) = PutBuilder(jniPublisher, payload, encoding) /** * Performs a DELETE operation on the specified [keyExpr] @@ -106,12 +106,14 @@ class Publisher internal constructor( class PutBuilder internal constructor( private var jniPublisher: JNIPublisher?, val payload: IntoZBytes, - val encoding: Encoding? = null, + var encoding: Encoding? = null, var attachment: IntoZBytes? = null ) { fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + @Throws(ZError::class) fun res() { jniPublisher?.put(payload, encoding, attachment) ?: throw(publisherNotValid) @@ -146,16 +148,19 @@ class Publisher internal constructor( private var qos = QoS.default() private var encoding: Encoding = Encoding.defaultEncoding() - fun encoding(encoding: Encoding) { + fun encoding(encoding: Encoding): Builder { this.encoding = encoding + return this } - fun reliability(reliability: Reliability) { + fun reliability(reliability: Reliability): Builder { this.reliability = reliability + return this } - fun qos(qos: QoS) { + fun qos(qos: QoS): Builder { this.qos = qos + return this } fun res(): Publisher { diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java new file mode 100644 index 00000000..7557f6c6 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -0,0 +1,90 @@ +package io.zenoh; + +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.bytes.Encoding; +import io.zenoh.sample.SampleKind; +import io.zenoh.pubsub.Publisher; +import io.zenoh.sample.Sample; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.Config; +import io.zenoh.Session; +import kotlin.Pair; +import kotlin.Unit; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(JUnit4.class) +public class PublisherTest { + + private Session session; + private ArrayList receivedSamples; + private Publisher publisher; + private Subscriber subscriber; + private KeyExpr keyExpr; + + @Before + public void setUp() throws ZError { + session = Zenoh.open(Config.loadDefault()); + keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + publisher = session.declarePublisher(keyExpr).encoding(Encoding.ZENOH_STRING).res(); + receivedSamples = new ArrayList<>(); + subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSamples.add(sample)).res(); + } + + @After + public void tearDown() throws ZError { + publisher.close(); + subscriber.close(); + session.close(); + keyExpr.close(); + } + + @Test + public void putTest() { + + List> testPayloads = List.of( + new Pair<>(ZBytes.from("Test 1"), Encoding.TEXT_PLAIN), + new Pair<>(ZBytes.from("Test 2"), Encoding.TEXT_JSON), + new Pair<>(ZBytes.from("Test 3"), Encoding.TEXT_CSV) + ); + + testPayloads.forEach(value -> { + try { + publisher.put(value.getFirst()).encoding(value.getSecond()).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + }); + + assertEquals(testPayloads.size(), receivedSamples.size()); + for (int index = 0; index < receivedSamples.size(); index++) { + var sample = receivedSamples.get(index); + assertEquals(testPayloads.get(index).getFirst(), sample.getPayload()); + assertEquals(testPayloads.get(index).getSecond(), sample.getEncoding()); + } + } + + @Test + public void deleteTest() throws ZError { + publisher.delete().res(); + assertEquals(1, receivedSamples.size()); + assertEquals(SampleKind.DELETE, receivedSamples.get(0).getKind()); + } + + @Test + public void shouldFallbackToPublisherEncodingWhenEncodingNotProvided() throws ZError { + publisher.put(ZBytes.from("Test")).res(); + assertEquals(1, receivedSamples.size()); + assertEquals(Encoding.ZENOH_STRING, receivedSamples.get(0).getEncoding()); + } +} From 6b9d6e114bbe95268eab0445b932c760f54eba98 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 13 Nov 2024 20:02:24 -0300 Subject: [PATCH 36/83] Alignment: wip - converting tests to java tests. Added Queryable tests. --- .../kotlin/io/zenoh/pubsub/Publisher.kt | 2 +- .../src/commonMain/kotlin/io/zenoh/qos/QoS.kt | 3 +- .../commonMain/kotlin/io/zenoh/query/Get.kt | 2 +- .../kotlin/io/zenoh/query/Queryable.kt | 4 +- .../jvmTest/java/io/zenoh/QueryableTest.java | 278 ++++++++++++++++++ 5 files changed, 284 insertions(+), 5 deletions(-) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 3dea4110..f7c35ac8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -145,7 +145,7 @@ class Publisher internal constructor( internal val keyExpr: KeyExpr, ) { private var reliability: Reliability = Reliability.RELIABLE - private var qos = QoS.default() + private var qos = QoS.defaultQoS() private var encoding: Encoding = Encoding.defaultEncoding() fun encoding(encoding: Encoding): Builder { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt index f669c542..50b4dd10 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt @@ -30,7 +30,8 @@ data class QoS ( companion object { private val defaultQoS = QoS() - fun default() = defaultQoS + @JvmStatic + fun defaultQoS() = defaultQoS } internal class Builder( diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index 3ec8ab4f..a1c359ac 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -137,7 +137,7 @@ class Get private constructor() { } /** Specify an attachment. */ - fun withAttachment(attachment: IntoZBytes): Builder { + fun attachment(attachment: IntoZBytes): Builder { this.attachment = attachment.into() return this } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index b0794ba9..9b6100e4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -143,8 +143,8 @@ class Queryable internal constructor( fun complete(complete: Boolean) = apply { this.complete = complete } /** Specify an action to be invoked when the [Queryable] is undeclared. */ - fun onClose(action: () -> Unit): Builder { - this.onClose = action + fun onClose(action: Runnable): Builder { + this.onClose = { action.run() } return this } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java new file mode 100644 index 00000000..51b36eb5 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -0,0 +1,278 @@ +package io.zenoh; + +import io.zenoh.bytes.Encoding; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.handlers.Handler; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.query.Query; +import io.zenoh.qos.CongestionControl; +import io.zenoh.qos.Priority; +import io.zenoh.qos.QoS; +import io.zenoh.query.Reply; +import io.zenoh.sample.Sample; +import io.zenoh.sample.SampleKind; +import org.apache.commons.net.ntp.TimeStamp; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Date; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.*; + + +@RunWith(JUnit4.class) +public class QueryableTest { + + private static final ZBytes testPayload = ZBytes.from("Hello queryable"); + private Session session; + private KeyExpr testKeyExpr; + + @Before + public void setUp() throws ZError { + session = Zenoh.open(Config.loadDefault()); + testKeyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + } + + @After + public void tearDown() throws ZError { + session.close(); + testKeyExpr.close(); + } + + @Test + public void queryableRunsWithCallback() throws ZError { + var timestamp = new TimeStamp(Date.from(Instant.now())); + + var sample = new Sample( + testKeyExpr, + testPayload, + Encoding.defaultEncoding(), + SampleKind.PUT, + timestamp, + QoS.defaultQoS(), + null + ); + + var queryable = session.declareQueryable(testKeyExpr).callback(query -> + { + try { + query.reply(testKeyExpr, testPayload) + .timestamp(timestamp) + .congestionControl(QoS.defaultQoS().getCongestionControl()) + .priority(QoS.defaultQoS().getPriority()) + .express(QoS.defaultQoS().getExpress()) + .res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ).res(); + + Reply[] reply = new Reply[1]; + session.get(testKeyExpr.into()).callback(reply1 -> reply[0] = reply1).timeout(Duration.ofMillis(1000)).res(); + + assertNotNull(reply[0]); + Sample receivedSample = ((Reply.Success) reply[0]).getSample(); + assertEquals(sample, receivedSample); + queryable.close(); + } + + @Test + public void queryableRunsWithHandler() throws ZError, InterruptedException { + var handler = new QueryHandler(); + var queryable = session.declareQueryable(testKeyExpr).with(handler).res(); + + Thread.sleep(500); + + Reply[] reply = new Reply[1]; + session.get(testKeyExpr.into()).callback(reply1 -> reply[0] = reply1).res(); + + Thread.sleep(500); + + queryable.close(); + assertTrue(reply[0] instanceof Reply.Success); + } + + @Test + public void queryTest() throws ZError, InterruptedException { + Query[] receivedQuery = new Query[1]; + var queryable = session.declareQueryable(testKeyExpr).callback(query -> receivedQuery[0] = query).res(); + + session.get(testKeyExpr).res(); + + Thread.sleep(100); + + Query query = receivedQuery[0]; + assertNotNull(query); + assertNull(query.getPayload()); + assertNull(query.getEncoding()); + assertNull(query.getAttachment()); + + receivedQuery[0] = null; + var payload = ZBytes.from("Test value"); + var attachment = ZBytes.from("Attachment"); + session.get(testKeyExpr).callback(reply -> { + }).payload(payload).encoding(Encoding.ZENOH_STRING).attachment(attachment).res(); + + Thread.sleep(100); + + query = receivedQuery[0]; + assertNotNull(query); + assertEquals(payload, query.getPayload()); + assertEquals(Encoding.ZENOH_STRING, query.getEncoding()); + assertEquals(attachment, query.getAttachment()); + + queryable.close(); + } + + @Test + public void queryReplySuccessTest() throws ZError { + var message = ZBytes.from("Test message"); + var timestamp = TimeStamp.getCurrentTime(); + var queryable = session.declareQueryable(testKeyExpr).callback(query -> + { + try { + query.reply(testKeyExpr, message) + .timestamp(timestamp) + .priority(Priority.DATA_HIGH) + .express(true) + .congestionControl(CongestionControl.DROP) + .res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + }).res(); + + Reply[] receivedReply = new Reply[1]; + session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); + + queryable.close(); + + assertNotNull(receivedReply[0]); + assertTrue(receivedReply[0] instanceof Reply.Success); + + var sample = ((Reply.Success) receivedReply[0]).getSample(); + assertEquals(message, sample.getPayload()); + assertEquals(timestamp, sample.getTimestamp()); + assertEquals(Priority.DATA_HIGH, sample.getQos().getPriority()); + assertTrue(sample.getQos().getExpress()); + assertEquals(CongestionControl.DROP, sample.getQos().getCongestionControl()); + } + + @Test + public void queryReplyErrorTest() throws ZError, InterruptedException { + var errorMessage = ZBytes.from("Error message"); + var queryable = session.declareQueryable(testKeyExpr).callback(query -> + { + try { + query.replyErr(errorMessage).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ).res(); + + Reply[] receivedReply = new Reply[1]; + session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); + + Thread.sleep(1000); + queryable.close(); + + assertNotNull(receivedReply[0]); + assertTrue(receivedReply[0] instanceof Reply.Error); + + var errorReply = (Reply.Error) receivedReply[0]; + assertEquals(errorMessage, errorReply.getError()); + } + + @Test + public void queryReplyDeleteTest() throws ZError, InterruptedException { + var timestamp = TimeStamp.getCurrentTime(); + + var queryable = session.declareQueryable(testKeyExpr).callback(query -> + { + try { + query.replyDel(testKeyExpr).timestamp(timestamp).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ).res(); + + Reply[] receivedReply = new Reply[1]; + session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); + + Thread.sleep(1000); + queryable.close(); + + assertNotNull(receivedReply[0]); + assertTrue(receivedReply[0] instanceof Reply.Success); + + var sample = ((Reply.Success) receivedReply[0]).getSample(); + assertEquals(SampleKind.DELETE, sample.getKind()); + assertEquals(timestamp, sample.getTimestamp()); + } + + @Test + public void onCloseTest() throws InterruptedException, ZError { + AtomicReference onCloseWasCalled = new AtomicReference<>(false); + var queryable = session.declareQueryable(testKeyExpr).onClose(() -> onCloseWasCalled.set(true)).res(); + queryable.undeclare(); + + Thread.sleep(1000); + assertTrue(onCloseWasCalled.get()); + } +} + +class QueryHandler implements Handler { + + private int counter = 0; + private final ArrayList performedReplies = new ArrayList<>(); + + public ArrayList getPerformedReplies() { + return performedReplies; + } + + @Override + public void handle(Query query) { + try { + reply(query); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + + @Override + public QueryHandler receiver() { + return this; + } + + @Override + public void onClose() { + // No action needed on close + } + + public void reply(Query query) throws ZError { + ZBytes payload = ZBytes.from("Hello queryable " + counter + "!"); + counter++; + Sample sample = new Sample( + query.getKeyExpr(), + payload, + Encoding.defaultEncoding(), + SampleKind.PUT, + new TimeStamp(Date.from(Instant.now())), + new QoS(), + null + ); + performedReplies.add(sample); + query.reply(query.getKeyExpr(), payload).timestamp(sample.getTimestamp()).res(); + } +} From 163b953ff4e712f1dc54158035040256b43e5d5d Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 13 Nov 2024 21:06:17 -0300 Subject: [PATCH 37/83] Alignment: wip - converting tests to java tests. Added Put tests. --- .../src/jvmTest/java/io/zenoh/PutTest.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java new file mode 100644 index 00000000..8e1c0ec0 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -0,0 +1,47 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.bytes.ZBytes; +import io.zenoh.bytes.Encoding; +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.sample.Sample; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(JUnit4.class) +public class PutTest { + + public static final String TEST_KEY_EXP = "example/testing/keyexpr"; + public static final ZBytes TEST_PAYLOAD = ZBytes.from("Hello"); + + @Test + public void putTest() throws ZError { + Session session = Zenoh.open(Config.loadDefault()); + Sample[] receivedSample = new Sample[1]; + var keyExpr = KeyExpr.tryFrom(TEST_KEY_EXP); + var subscriber = session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample ).res(); + session.put(keyExpr, TEST_PAYLOAD).encoding(Encoding.TEXT_PLAIN).res(); + subscriber.close(); + session.close(); + assertNotNull(receivedSample[0]); + assertEquals(TEST_PAYLOAD, receivedSample[0].getPayload()); + } +} From 790a131c77f80b9337ce9494f2724ccc3b524350 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 14 Nov 2024 12:00:37 -0300 Subject: [PATCH 38/83] Alignment: wip - Added Scouting tests + adding scouting builder. --- .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 70 ++++++++++++------- .../kotlin/io/zenoh/jni/JNIScout.kt | 6 ++ .../kotlin/io/zenoh/pubsub/Subscriber.kt | 2 +- .../kotlin/io/zenoh/scouting/ScoutBuilder.kt | 67 ++++++++++++++++++ 4 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index fe708b4a..cadf20f9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -23,6 +23,11 @@ import io.zenoh.scouting.Scout import io.zenoh.config.WhatAmI import io.zenoh.config.WhatAmI.* import io.zenoh.exceptions.ZError +import io.zenoh.handlers.BlockingQueueHandler +import io.zenoh.scouting.ScoutBuilder +import java.util.* +import java.util.concurrent.BlockingQueue +import java.util.concurrent.LinkedBlockingDeque object Zenoh { @@ -38,6 +43,17 @@ object Zenoh { return Session.open(config) } + /** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + */ + @JvmStatic + fun scoutBuilder(): ScoutBuilder>> { + return ScoutBuilder(handler = BlockingQueueHandler(queue = LinkedBlockingDeque())) + } + /** * Scout for routers and/or peers. * @@ -87,31 +103,35 @@ object Zenoh { ) } -// /** TODO -// * Scout for routers and/or peers. -// * -// * Scout spawns a task that periodically sends scout messages and waits for Hello replies. -// * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. -// * -// * @param channel [Channel] upon which the incoming [Hello] messages will be piped. -// * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. -// * @param config Optional [Config] for the scout. -// * @return A result with the [Scout] object. -// */ -// fun scout( -// channel: Channel, -// whatAmI: Set = setOf(Peer, Router), -// config: Config? = null -// ): Result>> { -// ZenohLoad -// val handler = ChannelHandler(channel) -// return JNIScout.scout( -// whatAmI = whatAmI, -// callback = { hello -> handler.handle(hello) }, -// receiver = handler.receiver(), -// config = config -// ) -// } + /** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + * + * @param blockingQueue [BlockingQueue] upon which the incoming [Hello] messages will be piped. The optional wrapper + * for the [Hello] messages is used to notify the closing of the blocking queue, that is, if the hello message + * is "empty", that means that the queue was closed. + * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. + * @param config Optional [Config] for the scout. + * @return A result with the [Scout] object. + */ + @JvmStatic + @Throws(ZError::class) + fun scout( + blockingQueue: BlockingQueue>, + whatAmI: Set = setOf(Peer, Router), + config: Config? = null + ): Scout>> { + ZenohLoad + val handler = BlockingQueueHandler(blockingQueue) + return JNIScout.scout( + whatAmI = whatAmI, + callback = { hello -> handler.handle(hello) }, + receiver = handler.receiver(), + config = config + ) + } /** * Initializes the zenoh runtime logger, using rust environment settings. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt index d6083a4f..6b9f658f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt @@ -15,6 +15,7 @@ package io.zenoh.jni import io.zenoh.Config +import io.zenoh.ZenohLoad import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.callbacks.JNIScoutCallback @@ -31,6 +32,11 @@ import io.zenoh.config.WhatAmI internal class JNIScout(private val ptr: Long) { companion object { + + init { + ZenohLoad + } + @Throws(ZError::class) fun scout( whatAmI: Set, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index 13732324..e8bf1ca7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -84,7 +84,7 @@ class Subscriber internal constructor( jniSubscriber?.close() } - companion object { + internal companion object { /** * Creates a new [Builder] associated to the specified [session] and [keyExpr]. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt new file mode 100644 index 00000000..9a5e1dc6 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt @@ -0,0 +1,67 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.scouting + +import io.zenoh.Config +import io.zenoh.Resolvable +import io.zenoh.config.WhatAmI +import io.zenoh.handlers.BlockingQueueHandler +import io.zenoh.handlers.Callback +import io.zenoh.handlers.Handler +import io.zenoh.jni.JNIScout +import java.util.* +import java.util.concurrent.BlockingQueue + +class ScoutBuilder internal constructor( + private var callback: Callback? = null, + private var handler: Handler? = null, + private var config: Config? = null, + private var whatAmI: Set = setOf(WhatAmI.Peer, WhatAmI.Router) +): Resolvable> { + + /** + * Specify a [Callback] to be run when receiving a [Hello] message. Overrides any previously specified callback or handler. + */ + fun callback(callback: Callback): ScoutBuilder = + ScoutBuilder(callback = callback, handler = null, config = config, whatAmI = whatAmI) + + fun whatAmI(whatAmI: Set): ScoutBuilder { + return ScoutBuilder(callback, handler, config, whatAmI) + } + + /** + * Specify a [Handler]. Overrides any previously specified callback or handler. + */ + fun with(handler: Handler): ScoutBuilder = + ScoutBuilder(callback = null, handler = handler, config = config, whatAmI = whatAmI) + + /** Specify a [BlockingQueue]. Overrides any previously specified callback or handler. */ + fun with(blockingQueue: BlockingQueue>): ScoutBuilder>> = + ScoutBuilder(callback = null, handler = BlockingQueueHandler(blockingQueue), config = config, whatAmI = whatAmI) + + /** + * Resolve the builder, creating a [Scout] with the provided parameters. + * + * @return The newly created [Scout]. + */ + override fun res(): Scout { + require(callback != null || handler != null) { "Either a callback or a handler must be provided." } + val resolvedCallback = callback ?: Callback { t: Hello -> handler?.handle(t) } + // TODO: add onClose() + + @Suppress("UNCHECKED_CAST") + return JNIScout.scout(whatAmI = whatAmI, callback = resolvedCallback, receiver = handler?.receiver() ?: Unit as R, config = config) + } +} From f94ee4b729ec2ed8fce7d0a0a1340da1e17a5f4a Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 18 Nov 2024 11:10:42 -0300 Subject: [PATCH 39/83] Alignment: wrapping up scouting, closing queue upon scout close. --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 1 - .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 84 ------------------ .../kotlin/io/zenoh/jni/JNIScout.kt | 5 +- .../kotlin/io/zenoh/jni/JNISession.kt | 1 - .../kotlin/io/zenoh/scouting/ScoutBuilder.kt | 6 +- .../src/jvmTest/java/io/zenoh/ScoutTest.java | 87 +++++++++++++++++++ zenoh-jni/src/scouting.rs | 8 +- 7 files changed, 100 insertions(+), 92 deletions(-) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 1ea0e8ba..0bf56080 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -84,7 +84,6 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * However, any session declaration that was still alive and bound to the session previous to closing it, will still be alive. */ - @Throws(ZError::class) override fun close() { declarations.removeIf { it.undeclare() diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index cadf20f9..59df9555 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -15,13 +15,8 @@ package io.zenoh import io.zenoh.Logger.Companion.LOG_ENV -import io.zenoh.handlers.Callback -import io.zenoh.handlers.Handler -import io.zenoh.jni.JNIScout import io.zenoh.scouting.Hello import io.zenoh.scouting.Scout -import io.zenoh.config.WhatAmI -import io.zenoh.config.WhatAmI.* import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.scouting.ScoutBuilder @@ -54,85 +49,6 @@ object Zenoh { return ScoutBuilder(handler = BlockingQueueHandler(queue = LinkedBlockingDeque())) } - /** - * Scout for routers and/or peers. - * - * Scout spawns a task that periodically sends scout messages and waits for Hello replies. - * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. - * - * @param callback [Callback] to be run when receiving a [Hello] message. - * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. - * @param config Optional [Config] for the scout. - * @return A result with the [Scout] object. - */ - @JvmStatic - @Throws(ZError::class) - fun scout( - callback: Callback, - whatAmI: Set = setOf(Peer, Router), - config: Config? = null - ): Scout { - ZenohLoad - return JNIScout.scout(whatAmI = whatAmI, callback = callback, receiver = Unit, config = config) - } - - /** - * Scout for routers and/or peers. - * - * Scout spawns a task that periodically sends scout messages and waits for Hello replies. - * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. - * - * @param handler [Handler] to handle incoming [Hello] messages. - * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. - * @param config Optional [Config] for the scout. - * @return A result with the [Scout] object. - */ - @JvmStatic - @Throws(ZError::class) - fun scout( - handler: Handler, - whatAmI: Set = setOf(Peer, Router), - config: Config? = null - ): Scout { - ZenohLoad - return JNIScout.scout( - whatAmI = whatAmI, - callback = { hello -> handler.handle(hello) }, - receiver = handler.receiver(), - config = config - ) - } - - /** - * Scout for routers and/or peers. - * - * Scout spawns a task that periodically sends scout messages and waits for Hello replies. - * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. - * - * @param blockingQueue [BlockingQueue] upon which the incoming [Hello] messages will be piped. The optional wrapper - * for the [Hello] messages is used to notify the closing of the blocking queue, that is, if the hello message - * is "empty", that means that the queue was closed. - * @param whatAmI [WhatAmI] configuration: it indicates the role of the zenoh node sending the HELLO message. - * @param config Optional [Config] for the scout. - * @return A result with the [Scout] object. - */ - @JvmStatic - @Throws(ZError::class) - fun scout( - blockingQueue: BlockingQueue>, - whatAmI: Set = setOf(Peer, Router), - config: Config? = null - ): Scout>> { - ZenohLoad - val handler = BlockingQueueHandler(blockingQueue) - return JNIScout.scout( - whatAmI = whatAmI, - callback = { hello -> handler.handle(hello) }, - receiver = handler.receiver(), - config = config - ) - } - /** * Initializes the zenoh runtime logger, using rust environment settings. * E.g.: `RUST_LOG=info` will enable logging at info level. Similarly, you can set the variable to `error` or `debug`. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt index 6b9f658f..1db97215 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt @@ -23,6 +23,7 @@ import io.zenoh.config.ZenohId import io.zenoh.scouting.Hello import io.zenoh.scouting.Scout import io.zenoh.config.WhatAmI +import io.zenoh.jni.callbacks.JNIOnCloseCallback /** * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.scouting.Scout] @@ -41,6 +42,7 @@ internal class JNIScout(private val ptr: Long) { fun scout( whatAmI: Set, callback: Callback, + onClose: () -> Unit, config: Config?, receiver: R ): Scout { @@ -48,7 +50,7 @@ internal class JNIScout(private val ptr: Long) { callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) } val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } - val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, config?.jniConfig?.ptr ?: 0) + val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, onClose,config?.jniConfig?.ptr ?: 0) return Scout(receiver, JNIScout(ptr)) } @@ -56,6 +58,7 @@ internal class JNIScout(private val ptr: Long) { private external fun scoutViaJNI( whatAmI: Int, callback: JNIScoutCallback, + onClose: JNIOnCloseCallback, configPtr: Long, ): Long diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 62d105db..4bb6049a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -60,7 +60,6 @@ internal class JNISession { sessionPtr.set(session) } - @Throws(ZError::class) fun close() { closeSessionViaJNI(sessionPtr.get()) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt index 9a5e1dc6..786161f5 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt @@ -59,9 +59,9 @@ class ScoutBuilder internal constructor( override fun res(): Scout { require(callback != null || handler != null) { "Either a callback or a handler must be provided." } val resolvedCallback = callback ?: Callback { t: Hello -> handler?.handle(t) } - // TODO: add onClose() - @Suppress("UNCHECKED_CAST") - return JNIScout.scout(whatAmI = whatAmI, callback = resolvedCallback, receiver = handler?.receiver() ?: Unit as R, config = config) + return JNIScout.scout(whatAmI = whatAmI, callback = resolvedCallback, onClose = fun() { + handler?.onClose() + }, receiver = handler?.receiver() ?: Unit as R, config = config) } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java new file mode 100644 index 00000000..d9c3b232 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java @@ -0,0 +1,87 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.config.WhatAmI; +import io.zenoh.exceptions.ZError; +import io.zenoh.scouting.Hello; +import io.zenoh.scouting.Scout; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.BlockingQueue; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +@RunWith(JUnit4.class) +public class ScoutTest { + + @Test + public void scouting_queueTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + + Thread.sleep(1000); + + Scout>> scout = Zenoh.scoutBuilder().res(); + Hello[] hello = new Hello[1]; + + while (true) { + var hello1 = scout.getReceiver().take(); + if (hello1.isEmpty()) { + break; + } else { + hello[0] = hello1.get(); + } + } + scout.close(); + session.close(); + + assertNotNull(hello[0]); + } + + @Test + public void scouting_callbackTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + + Hello[] hello = new Hello[1]; + Zenoh.scoutBuilder().callback(hello1 -> hello[0] = hello1).res(); + + Thread.sleep(1000); + + assertNotNull(hello[0]); + session.close(); + } + + @Test + public void scouting_whatAmITest() { + var scout = Zenoh.scoutBuilder().whatAmI(Set.of(WhatAmI.Client, WhatAmI.Peer)).res(); + scout.close(); + } + + @Test + public void scouting_onCloseTest() { + Scout>> scout = Zenoh.scoutBuilder().res(); + var receiver = scout.getReceiver(); + + scout.close(); + var element = receiver.poll(); + assertNotNull(element); + assertTrue(element.isEmpty()); + } +} diff --git a/zenoh-jni/src/scouting.rs b/zenoh-jni/src/scouting.rs index e334e954..b0a665c1 100644 --- a/zenoh-jni/src/scouting.rs +++ b/zenoh-jni/src/scouting.rs @@ -15,14 +15,14 @@ use std::{ptr::null, sync::Arc}; use jni::{ - objects::{JClass, JList, JObject, JValue}, + objects::{GlobalRef, JClass, JList, JObject, JValue}, sys::jint, JNIEnv, }; use zenoh::{config::WhatAmIMatcher, Wait}; use zenoh::{scouting::Scout, Config}; -use crate::utils::{get_callback_global_ref, get_java_vm}; +use crate::utils::{get_callback_global_ref, get_java_vm, load_on_close}; use crate::{errors::ZResult, throw_exception, zerror}; /// Start a scout. @@ -42,11 +42,14 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIScout_00024Companion_scoutViaJNI( _class: JClass, whatAmI: jint, callback: JObject, + on_close: JObject, config_ptr: /*nullable=*/ *const Config, ) -> *const Scout<()> { || -> ZResult<*const Scout<()>> { let callback_global_ref = get_callback_global_ref(&mut env, callback)?; let java_vm = Arc::new(get_java_vm(&mut env)?); + let on_close_global_ref: GlobalRef = get_callback_global_ref(&mut env, on_close)?; + let on_close = load_on_close(&java_vm, on_close_global_ref); let whatAmIMatcher: WhatAmIMatcher = (whatAmI as u8).try_into().unwrap(); // The validity of the operation is guaranteed on the kotlin layer. let config = if config_ptr.is_null() { Config::default() @@ -58,6 +61,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNIScout_00024Companion_scoutViaJNI( }; zenoh::scout(whatAmIMatcher, config) .callback(move |hello| { + on_close.noop(); // Moves `on_close` inside the closure so it gets destroyed with the closure tracing::debug!("Received hello: {hello}"); let _ = || -> jni::errors::Result<()> { let mut env = java_vm.attach_current_thread_as_daemon()?; From 54269425648b80e93201d385c0abb1f8a10cf91b Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 18 Nov 2024 11:49:58 -0300 Subject: [PATCH 40/83] Alignment: adding selector tests --- .../jvmTest/java/io/zenoh/SelectorTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java new file mode 100644 index 00000000..8a7cc7d9 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java @@ -0,0 +1,41 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.query.Selector; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class SelectorTest { + + @Test + public void selector_fromStringTest() throws ZError { + var selector = Selector.tryFrom("a/b/c?arg1=val1"); + assertEquals("a/b/c", selector.getKeyExpr().toString()); + assertNotNull(selector.getParameters()); + assertEquals("arg1=val1", selector.getParameters().toString()); + + var selector2 = Selector.tryFrom("a/b/c"); + assertEquals("a/b/c", selector2.getKeyExpr().toString()); + assertNull(selector2.getParameters()); + + assertThrows(ZError.class, () -> Selector.tryFrom("")); + } +} From 98db96e3d213a45965a7644af111d0e7ffc3610d Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 18 Nov 2024 13:20:00 -0300 Subject: [PATCH 41/83] Alignment: fix SessionInfo + adding tests --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 27 +++++++++++++------ .../kotlin/io/zenoh/jni/JNISession.kt | 15 ++++++----- .../kotlin/io/zenoh/session/SessionInfo.kt | 10 ++++--- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 0bf56080..d02eac5b 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -33,6 +33,7 @@ import io.zenoh.query.Selector import io.zenoh.qos.Reliability import io.zenoh.pubsub.Subscriber import io.zenoh.session.SessionDeclaration +import io.zenoh.session.SessionInfo import java.time.Duration import java.util.* import java.util.concurrent.BlockingQueue @@ -298,8 +299,15 @@ class Session private constructor(private val config: Config) : AutoCloseable { fun delete(keyExpr: KeyExpr): Delete.Builder = Delete.newBuilder(this, keyExpr) /** Returns if session is open or has been closed. */ - fun isOpen(): Boolean { - return jniSession != null + fun isClosed(): Boolean { + return jniSession == null + } + + /** + * Returns the [SessionInfo] of this session. + */ + fun info(): SessionInfo { + return SessionInfo(this) } @Throws(ZError::class) @@ -356,16 +364,19 @@ class Session private constructor(private val config: Config) : AutoCloseable { jniSession?.run { performDelete(keyExpr, delete) } } - internal fun zid(): Result { - return jniSession?.zid() ?: Result.failure(sessionClosedException) + @Throws(ZError::class) + internal fun zid(): ZenohId { + return jniSession?.zid() ?: throw sessionClosedException } - internal fun getPeersId(): Result> { - return jniSession?.peersZid() ?: Result.failure(sessionClosedException) + @Throws(ZError::class) + internal fun getPeersId(): List { + return jniSession?.peersZid() ?: throw sessionClosedException } - internal fun getRoutersId(): Result> { - return jniSession?.routersZid() ?: Result.failure(sessionClosedException) + @Throws(ZError::class) + internal fun getRoutersId(): List { + return jniSession?.routersZid() ?: throw sessionClosedException } /** Launches the session through the jni session, returning the [Session] on success. */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 4bb6049a..78c8718f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -256,16 +256,19 @@ internal class JNISession { ) } - fun zid(): Result = runCatching { - ZenohId(getZidViaJNI(sessionPtr.get())) + @Throws(ZError::class) + fun zid(): ZenohId { + return ZenohId(getZidViaJNI(sessionPtr.get())) } - fun peersZid(): Result> = runCatching { - getPeersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } + @Throws(ZError::class) + fun peersZid(): List { + return getPeersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } } - fun routersZid(): Result> = runCatching { - getRoutersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } + @Throws(ZError::class) + fun routersZid(): List { + return getRoutersZidViaJNI(sessionPtr.get()).map { ZenohId(it) } } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt index 66b57d2f..9215daa4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionInfo.kt @@ -16,6 +16,7 @@ package io.zenoh.session import io.zenoh.Session import io.zenoh.config.ZenohId +import io.zenoh.exceptions.ZError /** * Class allowing to obtain the information of a [Session]. @@ -25,21 +26,24 @@ class SessionInfo(private val session: Session) { /** * Return the [ZenohId] of the current Zenoh [Session] */ - fun zid(): Result { + @Throws(ZError::class) + fun zid(): ZenohId { return session.zid() } /** * Return the [ZenohId] of the zenoh peers the session is currently connected to. */ - fun peersZid(): Result> { + @Throws(ZError::class) + fun peersZid(): List { return session.getPeersId() } /** * Return the [ZenohId] of the zenoh routers the session is currently connected to. */ - fun routersZid(): Result> { + @Throws(ZError::class) + fun routersZid(): List { return session.getRoutersId() } } From 1fa7d9dcd85d058b38f57a859c43674e2adf1517 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 18 Nov 2024 13:20:13 -0300 Subject: [PATCH 42/83] Alignment: fix Scouting queue test --- .../src/jvmTest/java/io/zenoh/ScoutTest.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java index d9c3b232..f01a4c48 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java @@ -22,6 +22,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.ArrayList; import java.util.Optional; import java.util.Set; import java.util.concurrent.BlockingQueue; @@ -39,20 +40,18 @@ public void scouting_queueTest() throws ZError, InterruptedException { Thread.sleep(1000); Scout>> scout = Zenoh.scoutBuilder().res(); - Hello[] hello = new Hello[1]; - while (true) { - var hello1 = scout.getReceiver().take(); - if (hello1.isEmpty()) { - break; - } else { - hello[0] = hello1.get(); - } - } + Thread.sleep(1000); scout.close(); - session.close(); - assertNotNull(hello[0]); + ArrayList> helloList = new ArrayList<>(); + scout.getReceiver().drainTo(helloList); + + assertTrue(helloList.size() > 1); + for (int i = 0; i < helloList.size() - 1; i++) { + assertTrue(helloList.get(i).isPresent()); + } + assertTrue(helloList.get(helloList.size() - 1).isEmpty()); } @Test From 9a859e11aa2b9ba6020c4e68aa6c80c892b470e9 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 18 Nov 2024 14:52:57 -0300 Subject: [PATCH 43/83] amend! Alignment: fix SessionInfo + adding tests Alignment: fix SessionInfo + adding tests --- .../java/io/zenoh/SessionInfoTest.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/SessionInfoTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SessionInfoTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SessionInfoTest.java new file mode 100644 index 00000000..7a3c9a89 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SessionInfoTest.java @@ -0,0 +1,111 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.config.ZenohId; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(JUnit4.class) +public class SessionInfoTest { + + @Test + public void peersZidTest() throws Exception { + String jsonConfig = "{\n" + + " mode: \"peer\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " }\n" + + "}"; + + Config listenConfig = Config.fromJson("{\n" + + " mode: \"peer\",\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " }\n" + + "}"); + + Session sessionC = Zenoh.open(listenConfig); + Session sessionA = Zenoh.open(Config.fromJson(jsonConfig)); + Session sessionB = Zenoh.open(Config.fromJson(jsonConfig)); + + ZenohId idA = sessionA.info().zid(); + ZenohId idB = sessionB.info().zid(); + var peers = sessionC.info().peersZid(); + assertTrue(peers.contains(idA)); + assertTrue(peers.contains(idB)); + + sessionA.close(); + sessionB.close(); + sessionC.close(); + } + + @Test + public void routersZidTest() throws Exception { + Session session = Zenoh.open(Config.fromJson("{\n" + + " mode: \"router\",\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " }\n" + + "}")); + + Session connectedRouterA = Zenoh.open(Config.fromJson("{\n" + + " mode: \"router\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " },\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7451\"]\n" + + " }\n" + + "}")); + + Session connectedRouterB = Zenoh.open(Config.fromJson("{\n" + + " mode: \"router\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " },\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7452\"]\n" + + " }\n" + + "}")); + + ZenohId idA = connectedRouterA.info().zid(); + ZenohId idB = connectedRouterB.info().zid(); + + var routers = session.info().routersZid(); + + assertTrue(routers.contains(idA)); + assertTrue(routers.contains(idB)); + + connectedRouterA.close(); + connectedRouterB.close(); + session.close(); + } + + @Test + public void zidTest() throws Exception { + String jsonConfig = "{\n" + + " id: \"123456\"\n" + + "}"; + + Session session = Zenoh.open(Config.fromJson(jsonConfig)); + assertEquals("123456", session.info().zid().toString()); + session.close(); + } +} From 384ba335d47860d31c3dbab10c316babd29946c7 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 18 Nov 2024 17:42:40 -0300 Subject: [PATCH 44/83] Alignment: session tests --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 16 +++- .../kotlin/io/zenoh/pubsub/Publisher.kt | 7 ++ .../jvmTest/java/io/zenoh/SessionTest.java | 74 +++++++++++++++++++ 3 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index d02eac5b..5f0af506 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -217,7 +217,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ fun declareKeyExpr(keyExpr: String): Resolvable = Resolvable { return@Resolvable jniSession?.run { - declareKeyExpr(keyExpr) + val keyexpr = declareKeyExpr(keyExpr) + declarations.add(keyexpr) + keyexpr } ?: throw sessionClosedException } @@ -313,7 +315,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolvePublisher(keyExpr: KeyExpr, encoding: Encoding, qos: QoS, reliability: Reliability): Publisher { return jniSession?.run { - declarePublisher(keyExpr, qos, encoding, reliability) + val publisher = declarePublisher(keyExpr, qos, encoding, reliability) + declarations.add(publisher) + publisher } ?: throw(sessionClosedException) } @@ -322,7 +326,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R ): Subscriber { return jniSession?.run { - declareSubscriber(keyExpr, callback, onClose, receiver) + val subscriber = declareSubscriber(keyExpr, callback, onClose, receiver) + declarations.add(subscriber) + subscriber } ?: throw (sessionClosedException) } @@ -331,7 +337,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R, complete: Boolean ): Queryable { return jniSession?.run { - declareQueryable(keyExpr, callback, onClose, receiver, complete) + val queryable = declareQueryable(keyExpr, callback, onClose, receiver, complete) + declarations.add(queryable) + queryable } ?: throw (sessionClosedException) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index f7c35ac8..fa86f196 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -89,6 +89,13 @@ class Publisher internal constructor( */ fun delete() = DeleteBuilder(jniPublisher) + /** + * Returns `true` if the publisher is still running. + */ + fun isValid(): Boolean { + return jniPublisher != null + } + override fun close() { undeclare() } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java new file mode 100644 index 00000000..fb768667 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java @@ -0,0 +1,74 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Publisher; +import io.zenoh.pubsub.Subscriber; +import kotlin.Unit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class SessionTest { + + private static final KeyExpr testKeyExpr; + + static { + try { + testKeyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + + @Test + public void sessionStartCloseTest() throws ZError { + Session session = Zenoh.open(Config.loadDefault()); + assertFalse(session.isClosed()); + session.close(); + assertTrue(session.isClosed()); + } + + @Test + public void sessionClose_declarationsAreUndeclaredAfterClosingSessionTest() throws ZError, InterruptedException { + Session session = Zenoh.open(Config.loadDefault()); + + Publisher publisher = session.declarePublisher(testKeyExpr).res(); + Subscriber subscriber = session.declareSubscriber(testKeyExpr).callback(sample -> {}).res(); + session.close(); + + Thread.sleep(1000); + + assertFalse(subscriber.isValid()); + assertFalse(publisher.isValid()); + + assertThrows(ZError.class, () -> publisher.put(ZBytes.from("Test")).res()); + } + + @Test + public void sessionClose_newDeclarationsReturnNullAfterClosingSession() throws ZError { + Session session = Zenoh.open(Config.loadDefault()); + session.close(); + assertThrows(ZError.class, () -> session.declarePublisher(testKeyExpr).res()); + assertThrows(ZError.class, () -> session.declareQueryable(testKeyExpr).res()); + assertThrows(ZError.class, () -> session.declareSubscriber(testKeyExpr).res()); + } +} From 2424498e67818df41a1a2b5a1695bb98755157cd Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 19 Nov 2024 23:21:45 -0300 Subject: [PATCH 45/83] Alignment: user attachment tests --- .../java/io/zenoh/UserAttachmentTest.java | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java new file mode 100644 index 00000000..1f3320f2 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -0,0 +1,199 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.bytes.ZBytes; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.query.Reply; +import io.zenoh.sample.Sample; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.time.Duration; + +import static org.junit.Assert.*; + +@RunWith(JUnit4.class) +public class UserAttachmentTest { + + static final KeyExpr keyExpr; + static final ZBytes payload = ZBytes.from("test payload"); + static final ZBytes attachment = ZBytes.from("mock_attachment"); + static { + try { + keyExpr = KeyExpr.tryFrom("example/testing/attachment"); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + + Session session; + + @Before + public void setup() throws ZError { + session = Zenoh.open(Config.loadDefault()); + } + + @After + public void tearDown() { + session.close(); + } + + @Test + public void putWithAttachmentTest() throws ZError { + Sample[] receivedSample = new Sample[1]; + Subscriber subscriber = + session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample).res(); + session.put(keyExpr, payload).attachment(attachment).res(); + + subscriber.close(); + + assertNotNull(receivedSample[0]); + ZBytes receivedAttachment = receivedSample[0].getAttachment(); + assertEquals(attachment, receivedAttachment); + } + + @Test + public void publisherPutWithAttachmentTest() throws ZError { + Sample[] receivedSample = new Sample[1]; + var publisher = session.declarePublisher(keyExpr).res(); + var subscriber = session.declareSubscriber(keyExpr).callback( sample -> + receivedSample[0] = sample).res(); + + publisher.put(payload).attachment(attachment).res(); + + publisher.close(); + subscriber.close(); + + assertNotNull(receivedSample[0]); + ZBytes receivedAttachment = receivedSample[0].getAttachment(); + assertEquals(attachment, receivedAttachment); + } + + @Test + public void publisherPutWithoutAttachmentTest() throws ZError { + Sample[] receivedSample = new Sample[1]; + var publisher = session.declarePublisher(keyExpr).res(); + var subscriber = session.declareSubscriber(keyExpr).callback( sample -> + receivedSample[0] = sample).res(); + + publisher.put(payload).res(); + + publisher.close(); + subscriber.close(); + + assertNotNull(receivedSample[0]); + assertNull(receivedSample[0].getAttachment()); + } + + @Test + public void publisherDeleteWithAttachmentTest() throws ZError { + Sample[] receivedSample = new Sample[1]; + var publisher = session.declarePublisher(keyExpr).res(); + var subscriber = session.declareSubscriber(keyExpr).callback( sample -> + receivedSample[0] = sample).res(); + + publisher.delete().attachment(attachment).res(); + + publisher.close(); + subscriber.close(); + + assertNotNull(receivedSample[0]); + ZBytes receivedAttachment = receivedSample[0].getAttachment(); + assertEquals(attachment, receivedAttachment); + } + + @Test + public void publisherDeleteWithoutAttachmentTest() throws ZError { + Sample[] receivedSample = new Sample[1]; + var publisher = session.declarePublisher(keyExpr).res(); + var subscriber = session.declareSubscriber(keyExpr).callback( sample -> + receivedSample[0] = sample).res(); + + publisher.delete().res(); + + publisher.close(); + subscriber.close(); + + assertNotNull(receivedSample[0]); + assertNull(receivedSample[0].getAttachment()); + } + + @Test + public void queryWithAttachmentTest() throws ZError { + ZBytes[] receivedAttachment = new ZBytes[1]; + var queryable = session.declareQueryable(keyExpr).callback(query -> { + receivedAttachment[0] = query.getAttachment(); + try { + query.reply(keyExpr, payload).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + }).res(); + + session.get(keyExpr).callback(reply -> {}).attachment(attachment).timeout(Duration.ofMillis(1000)).res(); + + queryable.close(); + + assertNotNull(receivedAttachment[0]); + assertEquals(attachment, receivedAttachment[0]); + } + + @Test + public void queryReplyWithAttachmentTest() throws ZError { + Reply[] reply = new Reply[1]; + var queryable = session.declareQueryable(keyExpr).callback(query -> { + try { + query.reply(keyExpr, payload).attachment(attachment).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + }).res(); + + session.get(keyExpr).callback(reply1 -> reply[0] = reply1).attachment(attachment).timeout(Duration.ofMillis(1000)).res(); + + queryable.close(); + + Reply receivedReply = reply[0]; + assertNotNull(receivedReply); + ZBytes receivedAttachment = ((Reply.Success) receivedReply).getSample().getAttachment(); + assertEquals(attachment, receivedAttachment); + } + + @Test + public void queryReplyWithoutAttachmentTest() throws ZError { + Reply[] reply = new Reply[1]; + var queryable = session.declareQueryable(keyExpr).callback(query -> { + try { + query.reply(keyExpr, payload).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + }).res(); + session.get(keyExpr).callback(reply1 -> reply[0] = reply1).timeout(Duration.ofMillis(1000)).res(); + + queryable.close(); + + Reply receivedReply = reply[0]; + assertNotNull(receivedReply); + ZBytes receivedAttachment = ((Reply.Success) receivedReply).getSample().getAttachment(); + assertNull(receivedAttachment); + } +} From 025bcf46c12471a530ebb58b1207b9f2430c99fb Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 19 Nov 2024 23:22:07 -0300 Subject: [PATCH 46/83] Alignment: subscriber tests --- .../jvmTest/java/io/zenoh/SubscriberTest.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java new file mode 100644 index 00000000..aa35d9c3 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java @@ -0,0 +1,152 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.bytes.Encoding; +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.handlers.Handler; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.qos.CongestionControl; +import io.zenoh.qos.Priority; +import io.zenoh.sample.Sample; +import kotlin.Pair; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.ArrayDeque; +import java.util.ArrayList; + +import static org.junit.Assert.assertEquals; + +@RunWith(JUnit4.class) +public class SubscriberTest { + + private static final Priority TEST_PRIORITY = Priority.DATA_HIGH; + private static final CongestionControl TEST_CONGESTION_CONTROL = CongestionControl.BLOCK; + private static final ArrayList> TEST_VALUES = new ArrayList<>(); + private static final KeyExpr testKeyExpr; + + static { + TEST_VALUES.add(new Pair<>(ZBytes.from("Test 1"), Encoding.TEXT_PLAIN)); + TEST_VALUES.add(new Pair<>(ZBytes.from("Test 2"), Encoding.TEXT_JSON)); + TEST_VALUES.add(new Pair<>(ZBytes.from("Test 3"), Encoding.TEXT_CSV)); + try { + testKeyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + + private Session session = null; + + @Before + public void setUp() throws ZError { + session = Zenoh.open(Config.loadDefault()); + } + + @After + public void tearDown() { + session.close(); + } + + @Test + public void subscriber_runsWithCallback() throws ZError { + var receivedSamples = new ArrayList(); + var subscriber = + session.declareSubscriber(testKeyExpr).callback(receivedSamples::add).res(); + + TEST_VALUES.forEach(value -> { + try { + session.put(testKeyExpr, value.getFirst()) + .encoding(value.getSecond()) + .priority(TEST_PRIORITY) + .congestionControl(TEST_CONGESTION_CONTROL) + .res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ); + assertEquals(receivedSamples.size(), TEST_VALUES.size()); + + for (int i = 0; i < TEST_VALUES.size(); i++) { + var valueSent = TEST_VALUES.get(i); + var valueRecv = receivedSamples.get(i); + + assertEquals(valueRecv.getPayload(), valueSent.getFirst()); + assertEquals(valueRecv.getEncoding(), valueSent.getSecond()); + assertEquals(valueRecv.getPriority(), TEST_PRIORITY); + assertEquals(valueRecv.getCongestionControl(), TEST_CONGESTION_CONTROL); + } + + subscriber.close(); + } + + @Test + public void subscriber_runsWithHandler() throws ZError { + var handler = new QueueHandler(); + var subscriber = + session.declareSubscriber(testKeyExpr).with(handler).res(); + + TEST_VALUES.forEach(value -> { + try { + session.put(testKeyExpr, value.getFirst()) + .encoding(value.getSecond()) + .priority(TEST_PRIORITY) + .congestionControl(TEST_CONGESTION_CONTROL) + .res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ); + assertEquals(handler.queue.size(), TEST_VALUES.size()); + + for (int i = 0; i < TEST_VALUES.size(); i++) { + var valueSent = TEST_VALUES.get(i); + var valueRecv = handler.queue.poll(); + + assert valueRecv != null; + assertEquals(valueRecv.getPayload(), valueSent.getFirst()); + assertEquals(valueRecv.getEncoding(), valueSent.getSecond()); + assertEquals(valueRecv.getPriority(), TEST_PRIORITY); + assertEquals(valueRecv.getCongestionControl(), TEST_CONGESTION_CONTROL); + } + + subscriber.close(); + } +} + +class QueueHandler implements Handler> { + + final ArrayDeque queue = new ArrayDeque<>(); + + @Override + public void handle(T t) { + queue.add(t); + } + + @Override + public ArrayDeque receiver() { + return queue; + } + + @Override + public void onClose() {} +} From f5565f215c56ae41d09c63887d3380e3c900c35c Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 21 Nov 2024 14:17:06 -0300 Subject: [PATCH 47/83] Alignment: removing the zenoh-ext package (to be added later in another PR) --- .../kotlin/io/zenoh/ext/ZDeserialize.kt | 76 --- .../kotlin/io/zenoh/ext/ZSerialize.kt | 76 --- .../kotlin/io/zenoh/jni/JNISession.kt | 14 +- zenoh-jni/src/lib.rs | 2 - zenoh-jni/src/zbytes.rs | 571 ------------------ 5 files changed, 7 insertions(+), 732 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt delete mode 100644 zenoh-jni/src/zbytes.rs diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt deleted file mode 100644 index 93d86a4c..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserialize.kt +++ /dev/null @@ -1,76 +0,0 @@ -package io.zenoh.ext - -import io.zenoh.bytes.ZBytes -import io.zenoh.jni.JNIZBytes.deserializeViaJNI -import kotlin.reflect.typeOf - -/** - * Deserialize the [ZBytes] instance into an element of type [T]. - * - * This function supports the following types: - * - [Boolean] - * - [Byte] - * - [Short] - * - [Int] - * - [Long] - * - [Float] - * - [Double] - * - [UByte] - * - [UShort] - * - [UInt] - * - [ULong] - * - [List] - * - [String] - * - [ByteArray] - * - [Map] - * - [Pair] - * - [Triple] - * - * **NOTE** - * - * This deserialization utility can be used across the Zenoh ecosystem with Zenoh - * versions based on other supported languages such as Rust, Python, C and C++. - * This works when the types are equivalent (a `Byte` corresponds to an `i8` in Rust, a `Short` to an `i16`, etc). - * - * ### Examples - * - * For a Boolean: - * ``` - * val input: Boolean = true - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For a List: - * ``` - * val input: List = listOf(1, 2, 3, 4, 5) - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize>(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For a nested list: - * ``` - * val input: List> = listOf(listOf(1, 2, 3)) - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize>>(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For a combined list of maps: - * ``` - * val input: List> = listOf(mapOf("a" to 1, "b" to 2)) - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize>>(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For additional examples, checkout the [ZBytes examples](https://github.com/eclipse-zenoh/zenoh-kotlin/blob/main/examples/src/main/kotlin/io.zenoh/ZBytes.kt). - * - * @see ZBytes - * @return a [Result] with the deserialization. - */ -inline fun zDeserialize(zbytes: ZBytes): Result = runCatching { - deserializeViaJNI(zbytes, typeOf()) as T -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt deleted file mode 100644 index e4d9b224..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerialize.kt +++ /dev/null @@ -1,76 +0,0 @@ -package io.zenoh.ext - -import io.zenoh.bytes.ZBytes -import io.zenoh.jni.JNIZBytes.serializeViaJNI -import kotlin.reflect.typeOf - -/** - * Serializes an element of type [T] into a [ZBytes]. - * - * This function supports the following types: - * - [Boolean] - * - [Byte] - * - [Short] - * - [Int] - * - [Long] - * - [Float] - * - [Double] - * - [UByte] - * - [UShort] - * - [UInt] - * - [ULong] - * - [List] - * - [String] - * - [ByteArray] - * - [Map] - * - [Pair] - * - [Triple] - * - * **NOTE** - * - * This serialization utility can be used across the Zenoh ecosystem with Zenoh - * versions based on other supported languages such as Rust, Python, C and C++. - * This works when the types are equivalent (a `Byte` corresponds to an `i8` in Rust, a `Short` to an `i16`, etc). - * - * ### Examples - * - * For a Boolean: - * ``` - * val input: Boolean = true - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For a List: - * ``` - * val input: List = listOf(1, 2, 3, 4, 5) - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize>(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For a nested list: - * ``` - * val input: List> = listOf(listOf(1, 2, 3)) - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize>>(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For a combined list of maps: - * ``` - * val input: List> = listOf(mapOf("a" to 1, "b" to 2)) - * val zbytes = zSerialize(input).getOrThrow() - * val output = zDeserialize>>(zbytes).getOrThrow() - * check(input == output) - * ``` - * - * For additional examples, checkout the [ZBytes examples](https://github.com/eclipse-zenoh/zenoh-kotlin/blob/main/examples/src/main/kotlin/io.zenoh/ZBytes.kt). - * - * @see ZBytes - * @return a [Result] with the serialized [ZBytes]. - */ -inline fun zSerialize(t: T): Result = runCatching { - serializeViaJNI(t, typeOf()) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 78c8718f..91314ddd 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -88,10 +88,10 @@ internal class JNISession { keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R ): Subscriber { val subCallback = - JNISubscriberCallback { keyExpr, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> + JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null val sample = Sample( - KeyExpr(keyExpr, null), + KeyExpr(keyExpr1, null), payload.into(), Encoding(encodingId, schema = encodingSchema), SampleKind.fromInt(kind), @@ -112,9 +112,9 @@ internal class JNISession { keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R, complete: Boolean ): Queryable { val queryCallback = - JNIQueryableCallback { keyExpr: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> + JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> val jniQuery = JNIQuery(queryPtr) - val keyExpr2 = KeyExpr(keyExpr, null) + val keyExpr2 = KeyExpr(keyExpr1, null) val selector = if (selectorParams.isEmpty()) { Selector(keyExpr2) } else { @@ -153,7 +153,7 @@ internal class JNISession { replierId: ByteArray?, success: Boolean, keyExpr: String?, - payload: ByteArray, + payload1: ByteArray, encodingId: Int, encodingSchema: String?, kind: Int, @@ -169,7 +169,7 @@ internal class JNISession { val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null val sample = Sample( KeyExpr(keyExpr!!, null), - payload.into(), + payload1.into(), Encoding(encodingId, schema = encodingSchema), SampleKind.fromInt(kind), timestamp, @@ -180,7 +180,7 @@ internal class JNISession { } else { reply = Reply.Error( replierId?.let { ZenohId(it) }, - payload.into(), + payload1.into(), Encoding(encodingId, schema = encodingSchema) ) } diff --git a/zenoh-jni/src/lib.rs b/zenoh-jni/src/lib.rs index 6661ee55..51b710b9 100644 --- a/zenoh-jni/src/lib.rs +++ b/zenoh-jni/src/lib.rs @@ -23,8 +23,6 @@ mod scouting; mod session; mod subscriber; mod utils; -#[cfg(feature = "zenoh-ext")] -mod zbytes; mod zenoh_id; // Test should be runned with `cargo test --no-default-features` diff --git a/zenoh-jni/src/zbytes.rs b/zenoh-jni/src/zbytes.rs deleted file mode 100644 index 0a1b0443..00000000 --- a/zenoh-jni/src/zbytes.rs +++ /dev/null @@ -1,571 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use jni::{ - objects::{AutoLocal, JByteArray, JClass, JList, JMap, JObject, JString, JValue}, - sys::jobject, - JNIEnv, -}; -use zenoh::bytes::ZBytes; -use zenoh_ext::{VarInt, ZDeserializeError, ZDeserializer, ZSerializer}; - -use crate::{ - errors::ZResult, - throw_exception, - utils::{bytes_to_java_array, decode_byte_array}, - zerror, -}; - -enum KotlinType { - Boolean, - String, - ByteArray, - Byte, - Short, - Int, - Long, - Float, - Double, - UByte, - UShort, - UInt, - ULong, - List(Box), - Map(Box, Box), - Pair(Box, Box), - Triple(Box, Box, Box), -} - -fn decode_ktype(env: &mut JNIEnv, ktype: JObject) -> ZResult { - let classifier_obj = env - .call_method( - &ktype, - "getClassifier", - "()Lkotlin/reflect/KClassifier;", - &[], - ) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - let classifier_obj = AutoLocal::new(classifier_obj, env); - - let kclass_class = env - .find_class("kotlin/reflect/KClass") - .map_err(|err| zerror!(err))?; - let is_kclass = env - .is_instance_of(&classifier_obj, kclass_class) - .map_err(|err| zerror!(err))?; - if is_kclass { - let qualified_name_jobject = env - .call_method( - &classifier_obj, - "getQualifiedName", - "()Ljava/lang/String;", - &[], - ) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - - let qualified_name: String = env - .get_string(&JString::from(qualified_name_jobject)) - .map_err(|err| zerror!(err))? - .into(); - - match qualified_name.as_str() { - "kotlin.Boolean" => Ok(KotlinType::Boolean), - "kotlin.String" => Ok(KotlinType::String), - "kotlin.ByteArray" => Ok(KotlinType::ByteArray), - "kotlin.Byte" => Ok(KotlinType::Byte), - "kotlin.Short" => Ok(KotlinType::Short), - "kotlin.Int" => Ok(KotlinType::Int), - "kotlin.Long" => Ok(KotlinType::Long), - "kotlin.Float" => Ok(KotlinType::Float), - "kotlin.Double" => Ok(KotlinType::Double), - "kotlin.UByte" => Ok(KotlinType::UByte), - "kotlin.UShort" => Ok(KotlinType::UShort), - "kotlin.UInt" => Ok(KotlinType::UInt), - "kotlin.ULong" => Ok(KotlinType::ULong), - "kotlin.collections.List" => Ok(KotlinType::List(Box::new(decode_ktype_arg( - env, &ktype, 0, - )?))), - "kotlin.collections.Map" => Ok(KotlinType::Map( - Box::new(decode_ktype_arg(env, &ktype, 0)?), - Box::new(decode_ktype_arg(env, &ktype, 1)?), - )), - "kotlin.Pair" => Ok(KotlinType::Pair( - Box::new(decode_ktype_arg(env, &ktype, 0)?), - Box::new(decode_ktype_arg(env, &ktype, 1)?), - )), - "kotlin.Triple" => Ok(KotlinType::Triple( - Box::new(decode_ktype_arg(env, &ktype, 0)?), - Box::new(decode_ktype_arg(env, &ktype, 1)?), - Box::new(decode_ktype_arg(env, &ktype, 2)?), - )), - _ => Err(zerror!("Unsupported type: {}", qualified_name)), - } - } else { - Err(zerror!("Classifier is not a KClass")) - } -} - -fn decode_ktype_arg(env: &mut JNIEnv, ktype: &JObject, idx: i32) -> ZResult { - let arguments = env - .call_method(ktype, "getArguments", "()Ljava/util/List;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - let arg = env - .call_method( - &arguments, - "get", - "(I)Ljava/lang/Object;", - &[JValue::Int(idx)], - ) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - let ktype = env - .call_method(arg, "getType", "()Lkotlin/reflect/KType;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - decode_ktype(env, ktype) -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIZBytes_serializeViaJNI( - mut env: JNIEnv, - _class: JClass, - any: JObject, - ktype: JObject, -) -> jobject { - || -> ZResult { - let mut serializer = ZSerializer::new(); - let ktype = decode_ktype(&mut env, ktype)?; - serialize(&mut env, &mut serializer, any, &ktype)?; - let zbytes = serializer.finish(); - - let byte_array = bytes_to_java_array(&env, &zbytes).map_err(|err| zerror!(err))?; - let zbytes_obj = env - .new_object( - "io/zenoh/bytes/ZBytes", - "([B)V", - &[JValue::Object(&JObject::from(byte_array))], - ) - .map_err(|err| zerror!(err))?; - - Ok(zbytes_obj.as_raw()) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - JObject::default().as_raw() - }) -} - -fn serialize( - env: &mut JNIEnv, - serializer: &mut ZSerializer, - any: JObject, - ktype: &KotlinType, -) -> ZResult<()> { - match ktype { - KotlinType::Byte => { - let byte_value = env - .call_method(any, "byteValue", "()B", &[]) - .map_err(|err| zerror!(err))? - .b() - .map_err(|err| zerror!(err))?; - serializer.serialize(byte_value); - } - KotlinType::Short => { - let short_value = env - .call_method(any, "shortValue", "()S", &[]) - .map_err(|err| zerror!(err))? - .s() - .map_err(|err| zerror!(err))?; - serializer.serialize(short_value); - } - KotlinType::Int => { - let int_value = env - .call_method(any, "intValue", "()I", &[]) - .map_err(|err| zerror!(err))? - .i() - .map_err(|err| zerror!(err))?; - serializer.serialize(int_value); - } - KotlinType::Long => { - let long_value = env - .call_method(any, "longValue", "()J", &[]) - .map_err(|err| zerror!(err))? - .j() - .map_err(|err| zerror!(err))?; - serializer.serialize(long_value); - } - KotlinType::Float => { - let float_value = env - .call_method(any, "floatValue", "()F", &[]) - .map_err(|err| zerror!(err))? - .f() - .map_err(|err| zerror!(err))?; - serializer.serialize(float_value); - } - KotlinType::Double => { - let double_value = env - .call_method(any, "doubleValue", "()D", &[]) - .map_err(|err| zerror!(err))? - .d() - .map_err(|err| zerror!(err))?; - serializer.serialize(double_value); - } - KotlinType::Boolean => { - let boolean_value = env - .call_method(any, "booleanValue", "()Z", &[]) - .map_err(|err| zerror!(err))? - .z() - .map_err(|err| zerror!(err))?; - serializer.serialize(boolean_value); - } - KotlinType::String => { - let jstring = JString::from(any); - let string_value: String = env.get_string(&jstring).map_err(|err| zerror!(err))?.into(); - serializer.serialize(string_value); - } - KotlinType::ByteArray => { - let jbyte_array = JByteArray::from(any); - let bytes = decode_byte_array(env, jbyte_array).map_err(|err| zerror!(err))?; - serializer.serialize(bytes); - } - KotlinType::UByte => { - let byte = env - .get_field(any, "data", "B") - .map_err(|err| zerror!(err))? - .b() - .map_err(|err| zerror!(err))?; - serializer.serialize(byte as u8); - } - KotlinType::UShort => { - let short = env - .get_field(any, "data", "S") - .map_err(|err| zerror!(err))? - .s() - .map_err(|err| zerror!(err))?; - serializer.serialize(short as u16); - } - KotlinType::UInt => { - let int = env - .get_field(any, "data", "I") - .map_err(|err| zerror!(err))? - .i() - .map_err(|err| zerror!(err))?; - serializer.serialize(int as u32); - } - KotlinType::ULong => { - let long = env - .get_field(any, "data", "J") - .map_err(|err| zerror!(err))? - .j() - .map_err(|err| zerror!(err))?; - serializer.serialize(long as u64); - } - KotlinType::List(kotlin_type) => { - let jlist: JList<'_, '_, '_> = - JList::from_env(env, &any).map_err(|err| zerror!(err))?; - let mut iterator = jlist.iter(env).map_err(|err| zerror!(err))?; - let list_size = jlist.size(env).unwrap(); - serializer.serialize(zenoh_ext::VarInt(list_size as usize)); - while let Some(value) = iterator.next(env).map_err(|err| zerror!(err))? { - serialize(env, serializer, value, kotlin_type)?; - } - } - KotlinType::Map(key_type, value_type) => { - let jmap = JMap::from_env(env, &any).map_err(|err| zerror!(err))?; - - let map_size = env - .call_method(&jmap, "size", "()I", &[]) - .map_err(|err| zerror!(err))? - .i() - .map_err(|err| zerror!(err))?; - - serializer.serialize(zenoh_ext::VarInt(map_size as usize)); - - let mut iterator = jmap.iter(env).map_err(|err| zerror!(err))?; - while let Some((key, value)) = iterator.next(env).map_err(|err| zerror!(err))? { - serialize(env, serializer, key, key_type)?; - serialize(env, serializer, value, value_type)?; - } - } - KotlinType::Pair(first_type, second_type) => { - let first = env - .call_method(&any, "getFirst", "()Ljava/lang/Object;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - let second = env - .call_method(&any, "getSecond", "()Ljava/lang/Object;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - serialize(env, serializer, first, first_type)?; - serialize(env, serializer, second, second_type)?; - } - KotlinType::Triple(first_type, second_type, third_type) => { - let first = env - .call_method(&any, "getFirst", "()Ljava/lang/Object;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - let second = env - .call_method(&any, "getSecond", "()Ljava/lang/Object;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - let third = env - .call_method(&any, "getThird", "()Ljava/lang/Object;", &[]) - .map_err(|err| zerror!(err))? - .l() - .map_err(|err| zerror!(err))?; - serialize(env, serializer, first, first_type)?; - serialize(env, serializer, second, second_type)?; - serialize(env, serializer, third, third_type)?; - } - } - Ok(()) -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIZBytes_deserializeViaJNI( - mut env: JNIEnv, - _class: JClass, - zbytes: JObject, - ktype: JObject, -) -> jobject { - || -> ZResult { - let payload = env - .get_field(zbytes, "bytes", "[B") - .map_err(|err| zerror!(err))?; - let decoded_bytes: Vec = - decode_byte_array(&env, JByteArray::from(payload.l().unwrap()))?; - let zbytes = ZBytes::from(decoded_bytes); - let mut deserializer = ZDeserializer::new(&zbytes); - let ktype = decode_ktype(&mut env, ktype)?; - let obj = deserialize(&mut env, &mut deserializer, &ktype)?; - if !deserializer.done() { - return Err(zerror!(ZDeserializeError)); - } - Ok(obj) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - JObject::default().as_raw() - }) -} - -fn deserialize( - env: &mut JNIEnv, - deserializer: &mut ZDeserializer, - ktype: &KotlinType, -) -> ZResult { - match ktype { - KotlinType::Byte => { - let byte = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let byte_obj = env - .new_object("java/lang/Byte", "(B)V", &[JValue::Byte(byte)]) - .map_err(|err| zerror!(err))?; - Ok(byte_obj.as_raw()) - } - KotlinType::Short => { - let short = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let short_obj = env - .new_object("java/lang/Short", "(S)V", &[JValue::Short(short)]) - .map_err(|err| zerror!(err))?; - Ok(short_obj.as_raw()) - } - KotlinType::Int => { - let integer = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let integer_obj = env - .new_object("java/lang/Integer", "(I)V", &[JValue::Int(integer)]) - .map_err(|err| zerror!(err))?; - Ok(integer_obj.as_raw()) - } - KotlinType::Long => { - let long = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let long_obj = env - .new_object("java/lang/Long", "(J)V", &[JValue::Long(long)]) - .map_err(|err| zerror!(err))?; - Ok(long_obj.as_raw()) - } - KotlinType::Float => { - let float = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let float_obj = env - .new_object("java/lang/Float", "(F)V", &[JValue::Float(float)]) - .map_err(|err| zerror!(err))?; - Ok(float_obj.as_raw()) - } - KotlinType::Double => { - let double = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let double_obj = env - .new_object("java/lang/Double", "(D)V", &[JValue::Double(double)]) - .map_err(|err| zerror!(err))?; - Ok(double_obj.as_raw()) - } - KotlinType::Boolean => { - let boolean_value = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let jboolean = if boolean_value { 1u8 } else { 0u8 }; - let boolean_obj = env - .new_object("java/lang/Boolean", "(Z)V", &[JValue::Bool(jboolean)]) - .map_err(|err| zerror!(err))?; - Ok(boolean_obj.as_raw()) - } - KotlinType::String => { - let deserialized_string = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let jstring = env - .new_string(&deserialized_string) - .map_err(|err| zerror!(err))?; - Ok(jstring.into_raw()) - } - KotlinType::ByteArray => { - let deserialized_bytes = deserializer - .deserialize::>() - .map_err(|err| zerror!(err))?; - let jbytes = env - .byte_array_from_slice(deserialized_bytes.as_slice()) - .map_err(|err| zerror!(err))?; - Ok(jbytes.into_raw()) - } - KotlinType::UByte => { - let ubyte = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let ubyte_obj = env - .new_object("kotlin/UByte", "(B)V", &[JValue::Byte(ubyte as i8)]) - .map_err(|err| zerror!(err))?; - Ok(ubyte_obj.as_raw()) - } - KotlinType::UShort => { - let ushort = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let ushort_obj = env - .new_object("kotlin/UShort", "(S)V", &[JValue::Short(ushort as i16)]) - .map_err(|err| zerror!(err))?; - Ok(ushort_obj.as_raw()) - } - KotlinType::UInt => { - let uint = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let uint_obj = env - .new_object("kotlin/UInt", "(I)V", &[JValue::Int(uint as i32)]) - .map_err(|err| zerror!(err))?; - Ok(uint_obj.as_raw()) - } - KotlinType::ULong => { - let ulong = deserializer - .deserialize::() - .map_err(|err| zerror!(err))?; - let ulong_obj = env - .new_object("kotlin/ULong", "(J)V", &[JValue::Long(ulong as i64)]) - .map_err(|err| zerror!(err))?; - Ok(ulong_obj.as_raw()) - } - KotlinType::List(kotlin_type) => { - let list_size = deserializer - .deserialize::>() - .map_err(|err| zerror!(err))? - .0; - let array_list = env - .new_object("java/util/ArrayList", "()V", &[]) - .map_err(|err| zerror!(err))?; - let jlist = JList::from_env(env, &array_list).map_err(|err| zerror!(err))?; - - for _ in 0..list_size { - let item = deserialize(env, deserializer, kotlin_type)?; - let item_obj = unsafe { JObject::from_raw(item) }; - jlist.add(env, &item_obj).map_err(|err| zerror!(err))?; - } - Ok(array_list.as_raw()) - } - KotlinType::Map(key_type, value_type) => { - let map_size = deserializer - .deserialize::>() - .map_err(|err| zerror!(err))? - .0; - let map = env - .new_object("java/util/HashMap", "()V", &[]) - .map_err(|err| zerror!(err))?; - let jmap = JMap::from_env(env, &map).map_err(|err| zerror!(err))?; - - for _ in 0..map_size { - let key = deserialize(env, deserializer, key_type)?; - let key_obj = unsafe { JObject::from_raw(key) }; - let value = deserialize(env, deserializer, value_type)?; - let value_obj = unsafe { JObject::from_raw(value) }; - jmap.put(env, &key_obj, &value_obj) - .map_err(|err| zerror!(err))?; - } - Ok(map.as_raw()) - } - KotlinType::Pair(first_type, second_type) => { - let first = deserialize(env, deserializer, first_type)?; - let second = deserialize(env, deserializer, second_type)?; - let pair = env - .new_object( - "kotlin/Pair", - "(Ljava/lang/Object;Ljava/lang/Object;)V", - &[ - JValue::Object(&unsafe { JObject::from_raw(first) }), - JValue::Object(&unsafe { JObject::from_raw(second) }), - ], - ) - .map_err(|err| zerror!(err))?; - Ok(pair.as_raw()) - } - KotlinType::Triple(first_type, second_type, third_type) => { - let first = deserialize(env, deserializer, first_type)?; - let second = deserialize(env, deserializer, second_type)?; - let third = deserialize(env, deserializer, third_type)?; - let triple = env - .new_object( - "kotlin/Triple", - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", - &[ - JValue::Object(&unsafe { JObject::from_raw(first) }), - JValue::Object(&unsafe { JObject::from_raw(second) }), - JValue::Object(&unsafe { JObject::from_raw(third) }), - ], - ) - .map_err(|err| zerror!(err))?; - Ok(triple.as_raw()) - } - } -} From 14a615e8cec50574d5062ba81c0cb1603917a181 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 22 Nov 2024 17:11:01 -0300 Subject: [PATCH 48/83] Alignment: Publisher config params --- examples/src/main/java/io/zenoh/ZPub.java | 2 +- examples/src/main/java/io/zenoh/ZPubThr.java | 2 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 43 ++++++------------- .../kotlin/io/zenoh/jni/JNISession.kt | 20 ++++----- .../kotlin/io/zenoh/pubsub/Publisher.kt | 39 ++--------------- .../jvmTest/java/io/zenoh/PublisherTest.java | 10 +++-- .../jvmTest/java/io/zenoh/SessionTest.java | 4 +- .../java/io/zenoh/UserAttachmentTest.java | 8 ++-- 8 files changed, 40 insertions(+), 88 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index adfe7757..8bf7fc63 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -25,7 +25,7 @@ public static void main(String[] args) throws ZError, InterruptedException { try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-pub")) { System.out.println("Declaring publisher on '" + keyExpr + "'..."); - try (Publisher publisher = session.declarePublisher(keyExpr).res()) { + try (Publisher publisher = session.declarePublisher(keyExpr)) { System.out.println("Press CTRL-C to quit..."); int idx = 0; while (true) { diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index ebe530c1..d04bd448 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -29,7 +29,7 @@ public static void main(String[] args) throws ZError { } try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Publisher publisher = session.declarePublisher(keyExpr).res()) { + try (Publisher publisher = session.declarePublisher(keyExpr)) { System.out.println("Publisher declared on test/thr."); System.out.println("Press CTRL-C to quit..."); while (true) { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 5f0af506..b3431a1f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -21,17 +21,12 @@ import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr -import io.zenoh.qos.QoS -import io.zenoh.pubsub.Delete -import io.zenoh.pubsub.Publisher -import io.zenoh.pubsub.Put +import io.zenoh.pubsub.* import io.zenoh.query.* import io.zenoh.query.Query import io.zenoh.query.Queryable import io.zenoh.sample.Sample import io.zenoh.query.Selector -import io.zenoh.qos.Reliability -import io.zenoh.pubsub.Subscriber import io.zenoh.session.SessionDeclaration import io.zenoh.session.SessionInfo import java.time.Duration @@ -103,30 +98,18 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Publisher] on the session. * - * Example: - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/greeting")) { - * try (Publisher publisher = session.declarePublisher(keyExpr) - * .priority(Priority.REALTIME) - * .congestionControl(CongestionControl.DROP) - * .res()) { - * int idx = 0; - * while (true) { - * String payload = "Hello for the " + idx + "th time!"; - * publisher.put(payload).res(); - * Thread.sleep(1000); - * idx++; - * } - * } - * } - * } - * ``` + * TODO + */ + fun declarePublisher(keyExpr: KeyExpr): Publisher = declarePublisher(keyExpr, PublisherConfig()) + + /** + * Declare a [Publisher] on the session. * - * @param keyExpr The [KeyExpr] the publisher will be associated to. - * @return A resolvable [Publisher.Builder] + * TODO */ - fun declarePublisher(keyExpr: KeyExpr): Publisher.Builder = Publisher.Builder(this, keyExpr) + fun declarePublisher(keyExpr: KeyExpr, publisherConfig: PublisherConfig): Publisher { + return resolvePublisher(keyExpr, publisherConfig) + } /** * Declare a [Subscriber] on the session. @@ -313,9 +296,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolvePublisher(keyExpr: KeyExpr, encoding: Encoding, qos: QoS, reliability: Reliability): Publisher { + internal fun resolvePublisher(keyExpr: KeyExpr, config: PublisherConfig): Publisher { return jniSession?.run { - val publisher = declarePublisher(keyExpr, qos, encoding, reliability) + val publisher = declarePublisher(keyExpr, config) declarations.add(publisher) publisher } ?: throw(sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 91314ddd..7053aff5 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -27,17 +27,13 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.config.ZenohId import io.zenoh.bytes.into import io.zenoh.Config -import io.zenoh.pubsub.Delete -import io.zenoh.pubsub.Publisher -import io.zenoh.pubsub.Put +import io.zenoh.pubsub.* import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.query.* import io.zenoh.sample.Sample -import io.zenoh.qos.Reliability import io.zenoh.sample.SampleKind -import io.zenoh.pubsub.Subscriber import org.apache.commons.net.ntp.TimeStamp import java.time.Duration import java.util.concurrent.atomic.AtomicLong @@ -65,20 +61,20 @@ internal class JNISession { } @Throws(ZError::class) - fun declarePublisher(keyExpr: KeyExpr, qos: QoS, encoding: Encoding, reliability: Reliability): Publisher { + fun declarePublisher(keyExpr: KeyExpr, publisherConfig: PublisherConfig): Publisher { val publisherRawPtr = declarePublisherViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - qos.congestionControl.value, - qos.priority.value, - qos.express, - reliability.ordinal + publisherConfig.qos.congestionControl.value, + publisherConfig.qos.priority.value, + publisherConfig.qos.express, + publisherConfig.reliability.ordinal ) return Publisher( keyExpr, - qos, - encoding, + publisherConfig.qos, + publisherConfig.encoding, JNIPublisher(publisherRawPtr), ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index fa86f196..22c1b5c7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -139,39 +139,8 @@ class Publisher internal constructor( jniPublisher?.delete(attachment) ?: throw(publisherNotValid) } } - - /** - * Publisher Builder. - * - * @property session The [Session] from which the publisher is declared. - * @property keyExpr The key expression the publisher will be associated to. - * @constructor Create empty Builder. - */ - class Builder internal constructor( - internal val session: Session, - internal val keyExpr: KeyExpr, - ) { - private var reliability: Reliability = Reliability.RELIABLE - private var qos = QoS.defaultQoS() - private var encoding: Encoding = Encoding.defaultEncoding() - - fun encoding(encoding: Encoding): Builder { - this.encoding = encoding - return this - } - - fun reliability(reliability: Reliability): Builder { - this.reliability = reliability - return this - } - - fun qos(qos: QoS): Builder { - this.qos = qos - return this - } - - fun res(): Publisher { - return session.run { resolvePublisher(keyExpr, encoding, qos, reliability) } - } - } } + +data class PublisherConfig(var reliability: Reliability = Reliability.RELIABLE, + var qos: QoS = QoS.defaultQoS(), + var encoding: Encoding = Encoding.defaultEncoding()) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 7557f6c6..72e9454c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -4,12 +4,13 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; +import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.qos.QoS; +import io.zenoh.qos.Reliability; import io.zenoh.sample.SampleKind; import io.zenoh.pubsub.Publisher; import io.zenoh.sample.Sample; import io.zenoh.pubsub.Subscriber; -import io.zenoh.Config; -import io.zenoh.Session; import kotlin.Pair; import kotlin.Unit; import org.junit.After; @@ -36,7 +37,10 @@ public class PublisherTest { public void setUp() throws ZError { session = Zenoh.open(Config.loadDefault()); keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); - publisher = session.declarePublisher(keyExpr).encoding(Encoding.ZENOH_STRING).res(); + + var config = new PublisherConfig(Reliability.RELIABLE, QoS.defaultQoS(), Encoding.ZENOH_STRING); + publisher = session.declarePublisher(keyExpr, config); + receivedSamples = new ArrayList<>(); subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSamples.add(sample)).res(); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java index fb768667..091e4023 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java @@ -51,7 +51,7 @@ public void sessionStartCloseTest() throws ZError { public void sessionClose_declarationsAreUndeclaredAfterClosingSessionTest() throws ZError, InterruptedException { Session session = Zenoh.open(Config.loadDefault()); - Publisher publisher = session.declarePublisher(testKeyExpr).res(); + Publisher publisher = session.declarePublisher(testKeyExpr); Subscriber subscriber = session.declareSubscriber(testKeyExpr).callback(sample -> {}).res(); session.close(); @@ -67,7 +67,7 @@ public void sessionClose_declarationsAreUndeclaredAfterClosingSessionTest() thro public void sessionClose_newDeclarationsReturnNullAfterClosingSession() throws ZError { Session session = Zenoh.open(Config.loadDefault()); session.close(); - assertThrows(ZError.class, () -> session.declarePublisher(testKeyExpr).res()); + assertThrows(ZError.class, () -> session.declarePublisher(testKeyExpr)); assertThrows(ZError.class, () -> session.declareQueryable(testKeyExpr).res()); assertThrows(ZError.class, () -> session.declareSubscriber(testKeyExpr).res()); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 1f3320f2..5b522a28 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -73,7 +73,7 @@ public void putWithAttachmentTest() throws ZError { @Test public void publisherPutWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - var publisher = session.declarePublisher(keyExpr).res(); + var publisher = session.declarePublisher(keyExpr); var subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSample[0] = sample).res(); @@ -90,7 +90,7 @@ public void publisherPutWithAttachmentTest() throws ZError { @Test public void publisherPutWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - var publisher = session.declarePublisher(keyExpr).res(); + var publisher = session.declarePublisher(keyExpr); var subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSample[0] = sample).res(); @@ -106,7 +106,7 @@ public void publisherPutWithoutAttachmentTest() throws ZError { @Test public void publisherDeleteWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - var publisher = session.declarePublisher(keyExpr).res(); + var publisher = session.declarePublisher(keyExpr); var subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSample[0] = sample).res(); @@ -123,7 +123,7 @@ public void publisherDeleteWithAttachmentTest() throws ZError { @Test public void publisherDeleteWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - var publisher = session.declarePublisher(keyExpr).res(); + var publisher = session.declarePublisher(keyExpr); var subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSample[0] = sample).res(); From 5d5326233edd2bc50d7cf9957761d2dcd5191354 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 22 Nov 2024 18:37:06 -0300 Subject: [PATCH 49/83] Alignment: Subscriber config params --- examples/src/main/java/io/zenoh/ZSub.java | 8 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 14 +- .../kotlin/io/zenoh/jni/JNISession.kt | 13 +- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 93 +---------- .../src/jvmTest/java/io/zenoh/ConfigTest.java | 158 +++++++++--------- .../src/jvmTest/java/io/zenoh/DeleteTest.java | 7 +- .../jvmTest/java/io/zenoh/EncodingTest.java | 7 +- .../jvmTest/java/io/zenoh/PublisherTest.java | 9 +- .../src/jvmTest/java/io/zenoh/PutTest.java | 9 +- .../jvmTest/java/io/zenoh/SessionTest.java | 6 +- .../jvmTest/java/io/zenoh/SubscriberTest.java | 13 +- .../java/io/zenoh/UserAttachmentTest.java | 32 ++-- 12 files changed, 166 insertions(+), 203 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index e5424c50..b4a68656 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -29,7 +29,7 @@ public static void main(String[] args) throws ZError, InterruptedException { try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/**")) { System.out.println("Declaring Subscriber on '" + keyExpr + "'..."); - try (Subscriber>> subscriber = session.declareSubscriber(keyExpr).res()) { + try (Subscriber>> subscriber = session.declareSubscriber(keyExpr)) { BlockingQueue> receiver = subscriber.getReceiver(); assert receiver != null; System.out.println("Press CTRL-C to quit..."); @@ -41,14 +41,8 @@ public static void main(String[] args) throws ZError, InterruptedException { Sample sample = wrapper.get(); System.out.println(">> [Subscriber] Received " + sample.getKind() + " ('" + sample.getKeyExpr() + "': '" + sample.getPayload() + "')"); } - } catch (ZError e) { - throw new RuntimeException(e); } } } } - - public static void handleSample(Sample sample) { - - } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index b3431a1f..a1fa8f7b 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -139,7 +139,15 @@ class Session private constructor(private val config: Config) : AutoCloseable { * @param keyExpr The [KeyExpr] the subscriber will be associated to. * @return A [Subscriber.Builder] with a [BlockingQueue] receiver. */ - fun declareSubscriber(keyExpr: KeyExpr): Subscriber.Builder>> = Subscriber.newBuilder(this, keyExpr) + @Throws(ZError::class) + fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { + return resolveSubscriber(keyExpr, SubscriberConfig()) + } + + @Throws(ZError::class) + fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberConfig): Subscriber { + return resolveSubscriber(keyExpr, config) + } /** * Declare a [Queryable] on the session. @@ -306,10 +314,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriber( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R + keyExpr: KeyExpr, config: SubscriberConfig ): Subscriber { return jniSession?.run { - val subscriber = declareSubscriber(keyExpr, callback, onClose, receiver) + val subscriber = declareSubscriber(keyExpr, config) declarations.add(subscriber) subscriber } ?: throw (sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 7053aff5..93151550 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -81,8 +81,13 @@ internal class JNISession { @Throws(ZError::class) fun declareSubscriber( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R + keyExpr: KeyExpr, config: SubscriberConfig ): Subscriber { + val resolvedCallback = config.callback ?: Callback { t: Sample -> config.handler?.handle(t) } + val resolvedOnClose = fun() { + config.handler?.onClose() + config.onClose?.invoke() + } val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null @@ -95,12 +100,12 @@ internal class JNISession { QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), attachmentBytes?.into() ) - callback.run(sample) + resolvedCallback.run(sample) } val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, onClose + keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, resolvedOnClose ) - return Subscriber(keyExpr, receiver, JNISubscriber(subscriberRawPtr)) + return Subscriber(keyExpr, config.handler?.receiver(), JNISubscriber(subscriberRawPtr)) } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index e8bf1ca7..6acdc309 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -15,18 +15,14 @@ package io.zenoh.pubsub import io.zenoh.* -import io.zenoh.exceptions.ZError import io.zenoh.handlers.Callback import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler -import io.zenoh.pubsub.Subscriber.Builder import io.zenoh.jni.JNISubscriber import io.zenoh.keyexpr.KeyExpr import io.zenoh.sample.Sample import io.zenoh.session.SessionDeclaration import java.util.* -import java.util.concurrent.BlockingQueue -import java.util.concurrent.LinkedBlockingDeque /** * A subscriber that allows listening to updates on a key expression and reacting to changes. @@ -83,87 +79,10 @@ class Subscriber internal constructor( protected fun finalize() { jniSubscriber?.close() } - - internal companion object { - - /** - * Creates a new [Builder] associated to the specified [session] and [keyExpr]. - * - * @param session The [Session] from which the subscriber will be declared. - * @param keyExpr The [KeyExpr] associated to the subscriber. - * @return An empty [Builder] with a default [BlockingQueueHandler] to handle the incoming samples. - */ - fun newBuilder(session: Session, keyExpr: KeyExpr): Builder>> { - return Builder(session, keyExpr, handler = BlockingQueueHandler(queue = LinkedBlockingDeque())) - } - } - - /** - * Builder to construct a [Subscriber]. - * - * Either a [Handler] or a [Callback] must be specified. Note neither of them are stackable and are mutually exclusive, - * meaning that it is not possible to specify multiple callbacks and/or handlers, the builder only considers the - * last one specified. - * - * @param R Receiver type of the [Handler] implementation. If no handler is provided to the builder, R will be [Unit]. - * @property session [Session] to which the [Subscriber] will be bound to. - * @property keyExpr The [KeyExpr] to which the subscriber is associated. - * @constructor Creates a Builder. This constructor is internal and should not be called directly. Instead, this - * builder should be obtained through the [Session] after calling [Session.declareSubscriber]. - */ - class Builder internal constructor( - private val session: Session, - private val keyExpr: KeyExpr, - private var callback: Callback? = null, - private var handler: Handler? = null - ): Resolvable> { - - private var onClose: (() -> Unit)? = null - - private constructor(other: Builder<*>, handler: Handler?): this(other.session, other.keyExpr) { - this.handler = handler - copyParams(other) - } - - private constructor(other: Builder<*>, callback: Callback?) : this(other.session, other.keyExpr) { - this.callback = callback - copyParams(other) - } - - private fun copyParams(other: Builder<*>) { - this.onClose = other.onClose - } - - /** Specify an action to be invoked when the [Subscriber] is undeclared. */ - fun onClose(action: () -> Unit): Builder { - this.onClose = action - return this - } - - /** Specify a [Callback]. Overrides any previously specified callback or handler. */ - fun callback(callback: Callback): Builder = Builder(this, callback) - - /** Specify a [Handler]. Overrides any previously specified callback or handler. */ - fun with(handler: Handler): Builder = Builder(this, handler) - - /** Specify a [BlockingQueue]. Overrides any previously specified callback or handler. */ - fun with(blockingQueue: BlockingQueue>): Builder>> = Builder(this, BlockingQueueHandler(blockingQueue)) - - /** - * Resolve the builder, creating a [Subscriber] with the provided parameters. - * - * @return The newly created [Subscriber]. - */ - @Suppress("UNCHECKED_CAST") - @Throws(ZError::class) - override fun res(): Subscriber { - require(callback != null || handler != null) { "Either a callback or a handler must be provided." } - val resolvedCallback = callback ?: Callback { t: Sample -> handler?.handle(t) } - val resolvedOnClose = fun() { - handler?.onClose() - onClose?.invoke() - } - return session.run { resolveSubscriber(keyExpr, resolvedCallback, resolvedOnClose, handler?.receiver() ?: Unit as R) } //TODO: double check this cast - } - } } + +data class SubscriberConfig( + var callback: Callback? = null, + var handler: Handler? = null, + var onClose: (() -> Unit)? = null +) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java index 357398de..a5ee9e0d 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -17,8 +17,8 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.sample.Sample; -import kotlin.Unit; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -34,73 +34,73 @@ public class ConfigTest { private static final String json5ClientConfigString = "{\n" + - " mode: \"peer\",\n" + - " listen: {\n" + - " endpoints: [\"tcp/localhost:7450\"]\n" + - " },\n" + - " scouting: {\n" + - " multicast: {\n" + - " enabled: false\n" + - " }\n" + - " }\n" + - "}"; + " mode: \"peer\",\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7450\"]\n" + + " },\n" + + " scouting: {\n" + + " multicast: {\n" + + " enabled: false\n" + + " }\n" + + " }\n" + + "}"; private static final String json5ServerConfigString = "{\n" + - " mode: \"peer\",\n" + - " listen: {\n" + - " endpoints: [\"tcp/localhost:7450\"],\n" + - " },\n" + - " scouting: {\n" + - " multicast: {\n" + - " enabled: false,\n" + - " }\n" + - " }\n" + - "}"; + " mode: \"peer\",\n" + + " listen: {\n" + + " endpoints: [\"tcp/localhost:7450\"],\n" + + " },\n" + + " scouting: {\n" + + " multicast: {\n" + + " enabled: false,\n" + + " }\n" + + " }\n" + + "}"; private static final String jsonClientConfigString = "{\n" + - " \"mode\": \"peer\",\n" + - " \"connect\": {\n" + - " \"endpoints\": [\"tcp/localhost:7450\"]\n" + - " },\n" + - " \"scouting\": {\n" + - " \"multicast\": {\n" + - " \"enabled\": false\n" + - " }\n" + - " }\n" + - "}"; + " \"mode\": \"peer\",\n" + + " \"connect\": {\n" + + " \"endpoints\": [\"tcp/localhost:7450\"]\n" + + " },\n" + + " \"scouting\": {\n" + + " \"multicast\": {\n" + + " \"enabled\": false\n" + + " }\n" + + " }\n" + + "}"; private static final String jsonServerConfigString = "{\n" + - " \"mode\": \"peer\",\n" + - " \"listen\": {\n" + - " \"endpoints\": [\"tcp/localhost:7450\"]\n" + - " },\n" + - " \"scouting\": {\n" + - " \"multicast\": {\n" + - " \"enabled\": false\n" + - " }\n" + - " }\n" + - "}"; + " \"mode\": \"peer\",\n" + + " \"listen\": {\n" + + " \"endpoints\": [\"tcp/localhost:7450\"]\n" + + " },\n" + + " \"scouting\": {\n" + + " \"multicast\": {\n" + + " \"enabled\": false\n" + + " }\n" + + " }\n" + + "}"; private static final String yamlClientConfigString = "mode: peer\n" + - "connect:\n" + - " endpoints:\n" + - " - tcp/localhost:7450\n" + - "scouting:\n" + - " multicast:\n" + - " enabled: false\n"; + "connect:\n" + + " endpoints:\n" + + " - tcp/localhost:7450\n" + + "scouting:\n" + + " multicast:\n" + + " enabled: false\n"; private static final String yamlServerConfigString = "mode: peer\n" + - "listen:\n" + - " endpoints:\n" + - " - tcp/localhost:7450\n" + - "scouting:\n" + - " multicast:\n" + - " enabled: false\n"; + "listen:\n" + + " endpoints:\n" + + " - tcp/localhost:7450\n" + + "scouting:\n" + + " multicast:\n" + + " enabled: false\n"; private static final KeyExpr TEST_KEY_EXP; private static final Config json5ClientConfig; @@ -127,26 +127,26 @@ public class ConfigTest { } private void runSessionTest(Config clientConfig, Config serverConfig) throws ZError, InterruptedException { - Session sessionClient = Zenoh.open(clientConfig); - Session sessionServer = Zenoh.open(serverConfig); + Session sessionClient = Zenoh.open(clientConfig); + Session sessionServer = Zenoh.open(serverConfig); final Sample[] receivedSample = new Sample[1]; - Subscriber subscriber = sessionClient.declareSubscriber(TEST_KEY_EXP).callback( - sample -> receivedSample[0] = sample - ).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + sessionClient.declareSubscriber(TEST_KEY_EXP, config); + ZBytes payload = ZBytes.from("example message"); + sessionClient.put(TEST_KEY_EXP, payload).res(); - ZBytes payload = ZBytes.from("example message"); - sessionClient.put(TEST_KEY_EXP, payload).res(); + Thread.sleep(1000); - Thread.sleep(1000); + subscriber.close(); + sessionClient.close(); + sessionServer.close(); - subscriber.close(); - sessionClient.close(); - sessionServer.close(); - - assertNotNull(receivedSample[0]); - assertEquals(receivedSample[0].getPayload(), payload); + assertNotNull(receivedSample[0]); + assertEquals(receivedSample[0].getPayload(), payload); } @Test @@ -174,13 +174,13 @@ public void testDefaultConfig() throws ZError { @Test public void configFailsWithIllFormatedJsonTest() throws ZError { - String illFormattedConfig = - "{\n" + - " mode: \"peer\",\n" + - " connect: {\n" + - " endpoints: [\"tcp/localhost:7450\"],\n" + - // missing '}' character here - "}"; + String illFormattedConfig = + "{\n" + + " mode: \"peer\",\n" + + " connect: {\n" + + " endpoints: [\"tcp/localhost:7450\"],\n" + + // missing '}' character here + "}"; assertThrows(ZError.class, () -> Config.fromJson(illFormattedConfig)); } @@ -188,11 +188,11 @@ public void configFailsWithIllFormatedJsonTest() throws ZError { @Test public void configFailsWithIllFormatedYAMLTest() { String illFormattedConfig = - "mode: peer\n" + - "connect:\n" + - " endpoints:\n" + - " - tcp/localhost:7450\n" + - "scouting\n"; + "mode: peer\n" + + "connect:\n" + + " endpoints:\n" + + " - tcp/localhost:7450\n" + + "scouting\n"; assertThrows(ZError.class, () -> Config.fromJson(illFormattedConfig)); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java index 5bb9cc2d..26e1d2d1 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java @@ -17,9 +17,9 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.sample.SampleKind; import io.zenoh.sample.Sample; -import kotlin.Unit; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -35,7 +35,10 @@ public void deleteIsProperlyReceivedBySubscriberTest() throws ZError, Interrupte Session session = Zenoh.open(Config.loadDefault()); final Sample[] receivedSample = new Sample[1]; KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); - Subscriber subscriber = session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); session.delete(keyExpr).res(); Thread.sleep(1000); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index 7c31cbc6..48e34876 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -19,6 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.query.Queryable; import io.zenoh.query.Reply; import io.zenoh.query.Selector; @@ -44,7 +45,11 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { // Testing non null schema Sample[] receivedSample = new Sample[1]; - Subscriber subscriber = session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample).res(); + + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); session.put(keyExpr, payload).encoding(with_schema).res(); Thread.sleep(200); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 72e9454c..78f92649 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -5,6 +5,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.qos.QoS; import io.zenoh.qos.Reliability; import io.zenoh.sample.SampleKind; @@ -12,7 +13,6 @@ import io.zenoh.sample.Sample; import io.zenoh.pubsub.Subscriber; import kotlin.Pair; -import kotlin.Unit; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -30,7 +30,7 @@ public class PublisherTest { private Session session; private ArrayList receivedSamples; private Publisher publisher; - private Subscriber subscriber; + private Subscriber subscriber; private KeyExpr keyExpr; @Before @@ -42,7 +42,10 @@ public void setUp() throws ZError { publisher = session.declarePublisher(keyExpr, config); receivedSamples = new ArrayList<>(); - subscriber = session.declareSubscriber(keyExpr).callback( sample -> receivedSamples.add(sample)).res(); + + SubscriberConfig subscriberConfig = new SubscriberConfig<>(); + subscriberConfig.setCallback(sample -> receivedSamples.add(sample)); + subscriber = session.declareSubscriber(keyExpr, subscriberConfig); } @After diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java index 8e1c0ec0..b758e66a 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -18,6 +18,8 @@ import io.zenoh.bytes.Encoding; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.sample.Sample; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,7 +39,12 @@ public void putTest() throws ZError { Session session = Zenoh.open(Config.loadDefault()); Sample[] receivedSample = new Sample[1]; var keyExpr = KeyExpr.tryFrom(TEST_KEY_EXP); - var subscriber = session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample ).res(); + + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); + session.put(keyExpr, TEST_PAYLOAD).encoding(Encoding.TEXT_PLAIN).res(); subscriber.close(); session.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java index 091e4023..0c508d01 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java @@ -18,8 +18,6 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; -import io.zenoh.pubsub.Subscriber; -import kotlin.Unit; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -52,7 +50,7 @@ public void sessionClose_declarationsAreUndeclaredAfterClosingSessionTest() thro Session session = Zenoh.open(Config.loadDefault()); Publisher publisher = session.declarePublisher(testKeyExpr); - Subscriber subscriber = session.declareSubscriber(testKeyExpr).callback(sample -> {}).res(); + var subscriber = session.declareSubscriber(testKeyExpr); session.close(); Thread.sleep(1000); @@ -69,6 +67,6 @@ public void sessionClose_newDeclarationsReturnNullAfterClosingSession() throws Z session.close(); assertThrows(ZError.class, () -> session.declarePublisher(testKeyExpr)); assertThrows(ZError.class, () -> session.declareQueryable(testKeyExpr).res()); - assertThrows(ZError.class, () -> session.declareSubscriber(testKeyExpr).res()); + assertThrows(ZError.class, () -> session.declareSubscriber(testKeyExpr)); } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java index aa35d9c3..8cdb6618 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java @@ -19,6 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; import io.zenoh.sample.Sample; @@ -68,8 +69,12 @@ public void tearDown() { @Test public void subscriber_runsWithCallback() throws ZError { var receivedSamples = new ArrayList(); + + var subscriberConfig = new SubscriberConfig<>(); + subscriberConfig.setCallback(receivedSamples::add); + var subscriber = - session.declareSubscriber(testKeyExpr).callback(receivedSamples::add).res(); + session.declareSubscriber(testKeyExpr, subscriberConfig); TEST_VALUES.forEach(value -> { try { @@ -101,8 +106,12 @@ public void subscriber_runsWithCallback() throws ZError { @Test public void subscriber_runsWithHandler() throws ZError { var handler = new QueueHandler(); + + var subscriberConfig = new SubscriberConfig>(); + subscriberConfig.setHandler(handler); + var subscriber = - session.declareSubscriber(testKeyExpr).with(handler).res(); + session.declareSubscriber(testKeyExpr, subscriberConfig); TEST_VALUES.forEach(value -> { try { diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 5b522a28..2d282b13 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -18,6 +18,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.ZBytes; import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.query.Reply; import io.zenoh.sample.Sample; import org.junit.After; @@ -59,8 +60,11 @@ public void tearDown() { @Test public void putWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - Subscriber subscriber = - session.declareSubscriber(keyExpr).callback(sample -> receivedSample[0] = sample).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); + session.put(keyExpr, payload).attachment(attachment).res(); subscriber.close(); @@ -74,8 +78,10 @@ public void putWithAttachmentTest() throws ZError { public void publisherPutWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - var subscriber = session.declareSubscriber(keyExpr).callback( sample -> - receivedSample[0] = sample).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); publisher.put(payload).attachment(attachment).res(); @@ -91,8 +97,10 @@ public void publisherPutWithAttachmentTest() throws ZError { public void publisherPutWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - var subscriber = session.declareSubscriber(keyExpr).callback( sample -> - receivedSample[0] = sample).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); publisher.put(payload).res(); @@ -107,8 +115,10 @@ public void publisherPutWithoutAttachmentTest() throws ZError { public void publisherDeleteWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - var subscriber = session.declareSubscriber(keyExpr).callback( sample -> - receivedSample[0] = sample).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); publisher.delete().attachment(attachment).res(); @@ -124,8 +134,10 @@ public void publisherDeleteWithAttachmentTest() throws ZError { public void publisherDeleteWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - var subscriber = session.declareSubscriber(keyExpr).callback( sample -> - receivedSample[0] = sample).res(); + SubscriberConfig config = new SubscriberConfig<>(); + config.setCallback(sample -> receivedSample[0] = sample); + Subscriber subscriber = + session.declareSubscriber(keyExpr, config); publisher.delete().res(); From a98180d0dee067db9580581b382e19baa382b851 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 25 Nov 2024 13:35:17 -0300 Subject: [PATCH 50/83] Alignment: Queryable config params --- .../src/main/java/io/zenoh/ZQueryable.java | 2 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 97 +++++++-------- .../io/zenoh/handlers/BlockingQueueHandler.kt | 2 +- .../kotlin/io/zenoh/jni/JNISession.kt | 53 ++++++++- .../kotlin/io/zenoh/query/Queryable.kt | 110 ++++-------------- .../jvmTest/java/io/zenoh/EncodingTest.java | 15 ++- .../src/jvmTest/java/io/zenoh/GetTest.java | 16 +-- .../jvmTest/java/io/zenoh/QueryableTest.java | 68 +++++------ .../jvmTest/java/io/zenoh/SessionTest.java | 2 +- .../java/io/zenoh/UserAttachmentTest.java | 13 ++- 10 files changed, 171 insertions(+), 207 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index fc42103d..b27ebcb9 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -31,7 +31,7 @@ public static void main(String[] args) throws ZError, InterruptedException { try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom(keyExprString)) { System.out.println("Declaring Queryable on " + keyExprString + "..."); - try (Queryable>> queryable = session.declareQueryable(keyExpr).res()) { + try (Queryable>> queryable = session.declareQueryable(keyExpr)) { BlockingQueue> receiver = queryable.getReceiver(); assert receiver != null; System.out.println("Press CTRL-C to quit..."); diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index a1fa8f7b..c9f5de58 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -18,6 +18,7 @@ import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.config.ZenohId import io.zenoh.exceptions.ZError +import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr @@ -32,6 +33,7 @@ import io.zenoh.session.SessionInfo import java.time.Duration import java.util.* import java.util.concurrent.BlockingQueue +import java.util.concurrent.LinkedBlockingDeque /** * A Zenoh Session, the core interaction point with a Zenoh network. @@ -114,36 +116,18 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Subscriber] on the session. * - * The default receiver is a [BlockingQueue], but can be changed with the [Subscriber.Builder.callback] functions. - * - * Example: - * - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/sub")) { - * try (Subscriber>> subscriber = session.declareSubscriber(keyExpr).res()) { - * BlockingQueue> receiver = subscriber.getReceiver(); - * assert receiver != null; - * while (true) { - * Optional sample = receiver.take(); - * if (sample.isEmpty()) { - * break; - * } - * System.out.println(sample.get()); - * } - * } - * } - * } - * ``` - * - * @param keyExpr The [KeyExpr] the subscriber will be associated to. - * @return A [Subscriber.Builder] with a [BlockingQueue] receiver. + * TODO */ @Throws(ZError::class) fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { return resolveSubscriber(keyExpr, SubscriberConfig()) } + /** + * Declare a [Subscriber] on the session. + * + * TODO + */ @Throws(ZError::class) fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberConfig): Subscriber { return resolveSubscriber(keyExpr, config) @@ -152,37 +136,29 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Queryable] on the session. * - * The default receiver is a [BlockingQueue], but can be changed with the [Queryable.Builder.callback] functions. + * TODO + */ + fun declareQueryable(keyExpr: KeyExpr): Queryable>> { + return resolveQueryableWithHandler(keyExpr, QueryableHandlerConfig(BlockingQueueHandler(LinkedBlockingDeque()))) + } + + /** + * Declare a [Queryable] on the session. * - * Example: - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/greeting")) { - * System.out.println("Declaring Queryable"); - * try (Queryable>> queryable = session.declareQueryable(keyExpr).res()) { - * BlockingQueue> receiver = queryable.getReceiver(); - * while (true) { - * Optional wrapper = receiver.take(); - * if (wrapper.isEmpty()) { - * break; - * } - * Query query = wrapper.get(); - * System.out.println("Received query at " + query.getSelector()); - * query.reply(keyExpr) - * .success("Hello!") - * .withKind(SampleKind.PUT) - * .withTimeStamp(TimeStamp.getCurrentTime()) - * .res(); - * } - * } - * } - * } - * ``` + * TODO + */ + fun declareQueryable(keyExpr: KeyExpr, config: QueryableHandlerConfig): Queryable { + return resolveQueryableWithHandler(keyExpr, config) + } + + /** + * Declare a [Queryable] on the session. * - * @param keyExpr The [KeyExpr] the queryable will be associated to. - * @return A [Queryable.Builder] with a [BlockingQueue] receiver. + * TODO */ - fun declareQueryable(keyExpr: KeyExpr): Queryable.Builder>> = Queryable.newBuilder(this, keyExpr) + fun declareQueryable(keyExpr: KeyExpr, config: QueryableCallbackConfig): Queryable { + return resolveQueryableWithCallback(keyExpr, config) + } /** * Declare a [KeyExpr]. @@ -324,11 +300,22 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolveQueryable( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R, complete: Boolean + internal fun resolveQueryableWithHandler( + keyExpr: KeyExpr, config: QueryableHandlerConfig ): Queryable { return jniSession?.run { - val queryable = declareQueryable(keyExpr, callback, onClose, receiver, complete) + val queryable = declareQueryableWithHandler(keyExpr, config) + declarations.add(queryable) + queryable + } ?: throw (sessionClosedException) + } + + @Throws(ZError::class) + internal fun resolveQueryableWithCallback( + keyExpr: KeyExpr, config: QueryableCallbackConfig + ): Queryable { + return jniSession?.run { + val queryable = declareQueryableWithCallback(keyExpr, config) declarations.add(queryable) queryable } ?: throw (sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt index 1bedd7fa..b6ffe3ac 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt @@ -31,7 +31,7 @@ import java.util.concurrent.BlockingQueue * @property queue * @constructor Create empty Queue handler */ -class BlockingQueueHandler(private val queue: BlockingQueue>) : Handler>> { +internal class BlockingQueueHandler(private val queue: BlockingQueue>) : Handler>> { override fun handle(t: T) { queue.put(Optional.of(t)) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 93151550..0a99197e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -109,9 +109,47 @@ internal class JNISession { } @Throws(ZError::class) - fun declareQueryable( - keyExpr: KeyExpr, callback: Callback, onClose: () -> Unit, receiver: R, complete: Boolean + fun declareQueryableWithCallback( + keyExpr: KeyExpr, config: QueryableCallbackConfig + ): Queryable { + val queryCallback = + JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> + val jniQuery = JNIQuery(queryPtr) + val keyExpr2 = KeyExpr(keyExpr1, null) + val selector = if (selectorParams.isEmpty()) { + Selector(keyExpr2) + } else { + Selector(keyExpr2, Parameters.from(selectorParams)) + } + val query = Query( + keyExpr2, + selector, + payload?.into(), + payload?.let { Encoding(encodingId, schema = encodingSchema) }, + attachmentBytes?.into(), + jniQuery + ) + config.callback.run(query) + } + val queryableRawPtr = declareQueryableViaJNI( + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + sessionPtr.get(), + queryCallback, + fun() { config.onClose?.run() }, + config.complete + ) + return Queryable(keyExpr, null, JNIQueryable(queryableRawPtr)) + } + + @Throws(ZError::class) + fun declareQueryableWithHandler( + keyExpr: KeyExpr, config: QueryableHandlerConfig ): Queryable { + val resolvedOnClose: (() -> Unit) = fun() { + config.handler.onClose() + config.onClose?.run() + } val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> val jniQuery = JNIQuery(queryPtr) @@ -129,12 +167,17 @@ internal class JNISession { attachmentBytes?.into(), jniQuery ) - callback.run(query) + config.handler.handle(query) } val queryableRawPtr = declareQueryableViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), queryCallback, onClose, complete + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + sessionPtr.get(), + queryCallback, + resolvedOnClose, + config.complete ) - return Queryable(keyExpr, receiver, JNIQueryable(queryableRawPtr)) + return Queryable(keyExpr, config.handler.receiver(), JNIQueryable(queryableRawPtr)) } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index 9b6100e4..72eccc42 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -88,92 +88,30 @@ class Queryable internal constructor( protected fun finalize() { jniQueryable?.close() } +} - companion object { - - /** - * Creates a new [Builder] associated to the specified [session] and [keyExpr]. - * - * @param session The [Session] from which the queryable will be declared. - * @param keyExpr The [KeyExpr] associated to the queryable. - * @return An empty [Builder] with a default [BlockingQueueHandler] to handle the incoming samples. - */ - fun newBuilder(session: Session, keyExpr: KeyExpr): Builder>> { - return Builder(session, keyExpr, handler = BlockingQueueHandler(queue = LinkedBlockingDeque())) - } - } - - /** - * Builder to construct a [Queryable]. - * - * Either a [Handler] or a [Callback] must be specified. Note neither of them are stackable and are mutually exclusive, - * meaning that it is not possible to specify multiple callbacks and/or handlers, the builder only considers the - * last one specified. - * - * @param R Receiver type of the [Handler] implementation. If no handler is provided to the builder, R will be [Unit]. - * @property session [Session] to which the [Queryable] will be bound to. - * @property keyExpr The [KeyExpr] to which the queryable is associated. - * @property callback Optional callback that will be triggered upon receiving a [Query]. - * @property handler Optional handler to receive the incoming queries. - * @constructor Creates a Builder. This constructor is internal and should not be called directly. Instead, this - * builder should be obtained through the [Session] after calling [Session.declareQueryable]. - */ - class Builder internal constructor( - private val session: Session, - private val keyExpr: KeyExpr, - private var callback: Callback? = null, - private var handler: Handler? = null - ): Resolvable> { - private var complete: Boolean = false - private var onClose: (() -> Unit)? = null - - private constructor(other: Builder<*>, handler: Handler?) : this(other.session, other.keyExpr) { - this.handler = handler - this.complete = other.complete - this.onClose = other.onClose - } - - private constructor(other: Builder<*>, callback: Callback?) : this(other.session, other.keyExpr) { - this.callback = callback - this.complete = other.complete - this.onClose = other.onClose - } - - /** Change queryable completeness. */ - fun complete(complete: Boolean) = apply { this.complete = complete } - - /** Specify an action to be invoked when the [Queryable] is undeclared. */ - fun onClose(action: Runnable): Builder { - this.onClose = { action.run() } - return this - } - - /** Specify a [Callback]. Overrides any previously specified callback or handler. */ - fun callback(callback: Callback): Builder = Builder(this, callback) - - /** Specify a [Handler]. Overrides any previously specified callback or handler. */ - fun with(handler: Handler): Builder = Builder(this, handler) - - /** Specify a [BlockingQueue]. Overrides any previously specified callback or handler. */ - fun with(blockingQueue: BlockingQueue>): Builder>> = Builder(this, BlockingQueueHandler(blockingQueue)) +/** + * TODO: add doc + */ +data class QueryableCallbackConfig( + var callback: Callback, +) { + var complete: Boolean = false + var onClose: Runnable? = null + + fun complete(complete: Boolean) = apply { this.complete = complete } + fun onClose(onClose: Runnable) = apply { this.onClose = onClose } +} - /** - * Resolve the builder, creating a [Queryable] with the provided parameters. - * - * @return The newly created [Queryable]. - */ - @Throws(ZError::class) - override fun res(): Queryable { - require(callback != null || handler != null) { "Either a callback or a handler must be provided." } - val resolvedCallback = callback ?: Callback { t: Query -> handler?.handle(t) } - val resolvedOnClose = fun() { - handler?.onClose() - onClose?.invoke() - } - return session.run { - @Suppress("UNCHECKED_CAST") - resolveQueryable(keyExpr, resolvedCallback, resolvedOnClose, handler?.receiver() ?: Unit as R, complete) // TODO: double check cast - } - } - } +/** + * TODO: add doc + */ +data class QueryableHandlerConfig( + var handler: Handler, +) { + var complete: Boolean = false + var onClose: Runnable? = null + + fun complete(complete: Boolean) = apply { this.complete = complete } + fun onClose(onClose: Runnable) = apply { this.onClose = onClose } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index 48e34876..2cf206ee 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -20,11 +20,10 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; import io.zenoh.pubsub.SubscriberConfig; -import io.zenoh.query.Queryable; +import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; import io.zenoh.query.Selector; import io.zenoh.sample.Sample; -import kotlin.Unit; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -75,7 +74,7 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { Selector test1 = Selector.tryFrom("example/testing/reply_success"); Selector test2 = Selector.tryFrom("example/testing/reply_success_with_schema"); - Queryable queryable = session.declareQueryable(keyExpr).callback(query -> + var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { try { KeyExpr queryKeyExpr = query.getKeyExpr(); @@ -88,7 +87,7 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { throw new RuntimeException(e); } } - ).res(); + )); // Testing with null schema on a reply success scenario. Sample[] receivedSample = new Sample[1]; @@ -124,7 +123,7 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { Selector test2 = Selector.tryFrom("example/testing/reply_error_with_schema"); ZBytes replyPayload = ZBytes.from("test"); - Queryable queryable = session.declareQueryable(keyExpr).callback(query -> + var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { KeyExpr keyExpr1 = query.getKeyExpr(); try { @@ -136,7 +135,7 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { } catch (Exception e) { throw new RuntimeException(e); } - }).res(); + })); // Testing with null schema on a reply error scenario. ZBytes[] errorMessage = new ZBytes[1]; @@ -182,11 +181,11 @@ public void encoding_queryTest() throws ZError, InterruptedException { Selector selector = Selector.tryFrom("example/testing/keyexpr"); Encoding[] receivedEncoding = new Encoding[1]; - Queryable queryable = session.declareQueryable(keyExpr).callback(query -> + var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { receivedEncoding[0] = query.getEncoding(); query.close(); - }).res(); + })); // Testing with null schema session.get(selector).callback(reply -> {}).payload(payload).encoding(without_schema).res(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index dbe3f932..e4498c27 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -3,13 +3,9 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; -import io.zenoh.query.Parameters; -import io.zenoh.query.Queryable; -import io.zenoh.query.Reply; -import io.zenoh.query.Selector; +import io.zenoh.query.*; import io.zenoh.sample.Sample; import io.zenoh.sample.SampleKind; -import kotlin.Unit; import org.apache.commons.net.ntp.TimeStamp; import org.junit.After; import org.junit.Before; @@ -32,13 +28,13 @@ public class GetTest { private Session session; private Selector selector; - private Queryable queryable; + private Queryable queryable; @Before public void setUp() throws ZError { session = Zenoh.open(Config.loadDefault()); selector = Selector.tryFrom("example/testing/keyexpr"); - queryable = session.declareQueryable(selector.getKeyExpr()).callback( query -> + queryable = session.declareQueryable(selector.getKeyExpr(), new QueryableCallbackConfig(query -> { try { query.reply(query.getKeyExpr(), payload).timestamp(timestamp).res(); @@ -46,7 +42,7 @@ public void setUp() throws ZError { throw new RuntimeException(e); } } - ).res(); + )); } @After @@ -86,9 +82,9 @@ public void get_runsWithHandlerTest() throws ZError { public void getWithSelectorParamsTest() throws ZError { Parameters[] receivedParams = new Parameters[1]; - Queryable queryable = session.declareQueryable(selector.getKeyExpr()).callback( query -> + Queryable queryable = session.declareQueryable(selector.getKeyExpr(), new QueryableCallbackConfig(query -> receivedParams[0] = query.getParameters() - ).res(); + )); Parameters params = Parameters.from("arg1=val1&arg2=val2&arg3"); Selector selectorWithParams = new Selector(selector.getKeyExpr(), params); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index 51b36eb5..f8ac9f7a 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -5,11 +5,10 @@ import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.query.Query; +import io.zenoh.query.*; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; import io.zenoh.qos.QoS; -import io.zenoh.query.Reply; import io.zenoh.sample.Sample; import io.zenoh.sample.SampleKind; import org.apache.commons.net.ntp.TimeStamp; @@ -27,7 +26,6 @@ import static org.junit.Assert.*; - @RunWith(JUnit4.class) public class QueryableTest { @@ -61,7 +59,7 @@ public void queryableRunsWithCallback() throws ZError { null ); - var queryable = session.declareQueryable(testKeyExpr).callback(query -> + var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { try { query.reply(testKeyExpr, testPayload) @@ -74,7 +72,7 @@ public void queryableRunsWithCallback() throws ZError { throw new RuntimeException(e); } } - ).res(); + )); Reply[] reply = new Reply[1]; session.get(testKeyExpr.into()).callback(reply1 -> reply[0] = reply1).timeout(Duration.ofMillis(1000)).res(); @@ -87,8 +85,8 @@ public void queryableRunsWithCallback() throws ZError { @Test public void queryableRunsWithHandler() throws ZError, InterruptedException { - var handler = new QueryHandler(); - var queryable = session.declareQueryable(testKeyExpr).with(handler).res(); + var config = new QueryableHandlerConfig<>(new QueryHandler()); + var queryable = session.declareQueryable(testKeyExpr, config); Thread.sleep(500); @@ -104,7 +102,8 @@ public void queryableRunsWithHandler() throws ZError, InterruptedException { @Test public void queryTest() throws ZError, InterruptedException { Query[] receivedQuery = new Query[1]; - var queryable = session.declareQueryable(testKeyExpr).callback(query -> receivedQuery[0] = query).res(); + var config = new QueryableCallbackConfig(query -> receivedQuery[0] = query); + var queryable = session.declareQueryable(testKeyExpr, config); session.get(testKeyExpr).res(); @@ -137,19 +136,20 @@ public void queryTest() throws ZError, InterruptedException { public void queryReplySuccessTest() throws ZError { var message = ZBytes.from("Test message"); var timestamp = TimeStamp.getCurrentTime(); - var queryable = session.declareQueryable(testKeyExpr).callback(query -> - { + QueryableCallbackConfig config = new QueryableCallbackConfig(query -> { try { query.reply(testKeyExpr, message) - .timestamp(timestamp) - .priority(Priority.DATA_HIGH) - .express(true) - .congestionControl(CongestionControl.DROP) - .res(); + .timestamp(timestamp) + .priority(Priority.DATA_HIGH) + .express(true) + .congestionControl(CongestionControl.DROP) + .res(); } catch (ZError e) { throw new RuntimeException(e); } - }).res(); + }); + + Queryable queryable = session.declareQueryable(testKeyExpr, config); Reply[] receivedReply = new Reply[1]; session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); @@ -170,15 +170,16 @@ public void queryReplySuccessTest() throws ZError { @Test public void queryReplyErrorTest() throws ZError, InterruptedException { var errorMessage = ZBytes.from("Error message"); - var queryable = session.declareQueryable(testKeyExpr).callback(query -> - { - try { - query.replyErr(errorMessage).res(); - } catch (ZError e) { - throw new RuntimeException(e); - } + + var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> + { + try { + query.replyErr(errorMessage).res(); + } catch (ZError e) { + throw new RuntimeException(e); } - ).res(); + } + )); Reply[] receivedReply = new Reply[1]; session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); @@ -197,15 +198,13 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { public void queryReplyDeleteTest() throws ZError, InterruptedException { var timestamp = TimeStamp.getCurrentTime(); - var queryable = session.declareQueryable(testKeyExpr).callback(query -> - { - try { - query.replyDel(testKeyExpr).timestamp(timestamp).res(); - } catch (ZError e) { - throw new RuntimeException(e); - } - } - ).res(); + var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { + try { + query.replyDel(testKeyExpr).timestamp(timestamp).res(); + } catch (ZError e) { + throw new RuntimeException(e); + } + })); Reply[] receivedReply = new Reply[1]; session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); @@ -224,7 +223,8 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { @Test public void onCloseTest() throws InterruptedException, ZError { AtomicReference onCloseWasCalled = new AtomicReference<>(false); - var queryable = session.declareQueryable(testKeyExpr).onClose(() -> onCloseWasCalled.set(true)).res(); + var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { + }).onClose(() -> onCloseWasCalled.set(true))); queryable.undeclare(); Thread.sleep(1000); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java index 0c508d01..01ca1255 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java @@ -66,7 +66,7 @@ public void sessionClose_newDeclarationsReturnNullAfterClosingSession() throws Z Session session = Zenoh.open(Config.loadDefault()); session.close(); assertThrows(ZError.class, () -> session.declarePublisher(testKeyExpr)); - assertThrows(ZError.class, () -> session.declareQueryable(testKeyExpr).res()); + assertThrows(ZError.class, () -> session.declareQueryable(testKeyExpr)); assertThrows(ZError.class, () -> session.declareSubscriber(testKeyExpr)); } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 2d282b13..e93a2fee 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -19,6 +19,7 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.pubsub.Subscriber; import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; import io.zenoh.sample.Sample; import org.junit.After; @@ -151,14 +152,14 @@ public void publisherDeleteWithoutAttachmentTest() throws ZError { @Test public void queryWithAttachmentTest() throws ZError { ZBytes[] receivedAttachment = new ZBytes[1]; - var queryable = session.declareQueryable(keyExpr).callback(query -> { + var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { receivedAttachment[0] = query.getAttachment(); try { query.reply(keyExpr, payload).res(); } catch (ZError e) { throw new RuntimeException(e); } - }).res(); + })); session.get(keyExpr).callback(reply -> {}).attachment(attachment).timeout(Duration.ofMillis(1000)).res(); @@ -171,13 +172,13 @@ public void queryWithAttachmentTest() throws ZError { @Test public void queryReplyWithAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; - var queryable = session.declareQueryable(keyExpr).callback(query -> { + var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { try { query.reply(keyExpr, payload).attachment(attachment).res(); } catch (ZError e) { throw new RuntimeException(e); } - }).res(); + })); session.get(keyExpr).callback(reply1 -> reply[0] = reply1).attachment(attachment).timeout(Duration.ofMillis(1000)).res(); @@ -192,13 +193,13 @@ public void queryReplyWithAttachmentTest() throws ZError { @Test public void queryReplyWithoutAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; - var queryable = session.declareQueryable(keyExpr).callback(query -> { + var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { try { query.reply(keyExpr, payload).res(); } catch (ZError e) { throw new RuntimeException(e); } - }).res(); + })); session.get(keyExpr).callback(reply1 -> reply[0] = reply1).timeout(Duration.ofMillis(1000)).res(); queryable.close(); From 66f158f4076aa8a085f03e7147c0432e0e7c6da3 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 25 Nov 2024 14:08:07 -0300 Subject: [PATCH 51/83] Alignment: Subscriber config params refactor --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 33 ++++++++++--- .../kotlin/io/zenoh/jni/JNISession.kt | 40 ++++++++++++---- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 46 ++++++------------- .../src/jvmTest/java/io/zenoh/ConfigTest.java | 6 +-- .../src/jvmTest/java/io/zenoh/DeleteTest.java | 6 +-- .../jvmTest/java/io/zenoh/EncodingTest.java | 6 +-- .../jvmTest/java/io/zenoh/PublisherTest.java | 6 +-- .../src/jvmTest/java/io/zenoh/PutTest.java | 6 +-- .../jvmTest/java/io/zenoh/SubscriberTest.java | 14 ++---- .../java/io/zenoh/UserAttachmentTest.java | 22 +++------ 10 files changed, 93 insertions(+), 92 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index c9f5de58..05920256 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -120,7 +120,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { - return resolveSubscriber(keyExpr, SubscriberConfig()) + return resolveSubscriberWithHandler(keyExpr, SubscriberHandlerConfig(BlockingQueueHandler(LinkedBlockingDeque()))) } /** @@ -129,8 +129,18 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO */ @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberConfig): Subscriber { - return resolveSubscriber(keyExpr, config) + fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberHandlerConfig): Subscriber { + return resolveSubscriberWithHandler(keyExpr, config) + } + + /** + * Declare a [Subscriber] on the session. + * + * TODO + */ + @Throws(ZError::class) + fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberCallbackConfig): Subscriber { + return resolveSubscriberWithCallback(keyExpr, config) } /** @@ -289,11 +299,22 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolveSubscriber( - keyExpr: KeyExpr, config: SubscriberConfig + internal fun resolveSubscriberWithHandler( + keyExpr: KeyExpr, config: SubscriberHandlerConfig ): Subscriber { return jniSession?.run { - val subscriber = declareSubscriber(keyExpr, config) + val subscriber = declareSubscriberWithHandler(keyExpr, config) + declarations.add(subscriber) + subscriber + } ?: throw (sessionClosedException) + } + + @Throws(ZError::class) + internal fun resolveSubscriberWithCallback( + keyExpr: KeyExpr, config: SubscriberCallbackConfig + ): Subscriber { + return jniSession?.run { + val subscriber = declareSubscriberWithCallback(keyExpr, config) declarations.add(subscriber) subscriber } ?: throw (sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 0a99197e..5fee1185 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -80,14 +80,9 @@ internal class JNISession { } @Throws(ZError::class) - fun declareSubscriber( - keyExpr: KeyExpr, config: SubscriberConfig + fun declareSubscriberWithHandler( + keyExpr: KeyExpr, config: SubscriberHandlerConfig ): Subscriber { - val resolvedCallback = config.callback ?: Callback { t: Sample -> config.handler?.handle(t) } - val resolvedOnClose = fun() { - config.handler?.onClose() - config.onClose?.invoke() - } val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null @@ -100,14 +95,41 @@ internal class JNISession { QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), attachmentBytes?.into() ) - resolvedCallback.run(sample) + config.handler?.handle(sample) } val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, resolvedOnClose + keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, fun() { + config.handler?.onClose() + config.onClose?.run() + } ) return Subscriber(keyExpr, config.handler?.receiver(), JNISubscriber(subscriberRawPtr)) } + @Throws(ZError::class) + fun declareSubscriberWithCallback( + keyExpr: KeyExpr, config: SubscriberCallbackConfig + ): Subscriber { + val subCallback = + JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> + val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null + val sample = Sample( + KeyExpr(keyExpr1, null), + payload.into(), + Encoding(encodingId, schema = encodingSchema), + SampleKind.fromInt(kind), + timestamp, + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() + ) + config.callback.run(sample) + } + val subscriberRawPtr = declareSubscriberViaJNI( + keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, fun() { config.onClose?.run() } + ) + return Subscriber(keyExpr, null, JNISubscriber(subscriberRawPtr)) + } + @Throws(ZError::class) fun declareQueryableWithCallback( keyExpr: KeyExpr, config: QueryableCallbackConfig diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index 6acdc309..555a0bef 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -31,33 +31,7 @@ import java.util.* * * Example using the default [BlockingQueueHandler] handler: * - * ```java - * System.out.println("Opening session..."); - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example")) { - * System.out.println("Declaring Subscriber on '" + keyExpr + "'..."); - * try (Subscriber>> subscriber = session.declareSubscriber(keyExpr).res()) { - * BlockingQueue> receiver = subscriber.getReceiver(); - * assert receiver != null; - * while (true) { - * Optional wrapper = receiver.take(); - * if (wrapper.isEmpty()) { - * break; - * } - * Sample sample = wrapper.get(); - * System.out.println(">> [Subscriber] Received " + sample.getKind() + " ('" + sample.getKeyExpr() + "': '" + sample.getValue() + "')"); - * } - * } - * } - * } - * ``` - * - * @param R Receiver type of the [Handler] implementation. If no handler is provided to the builder, R will be [Unit]. - * @property keyExpr The [KeyExpr] to which the subscriber is associated. - * @property receiver Optional [R] that is provided when specifying a [Handler] for the subscriber. - * @property jniSubscriber Delegate object in charge of communicating with the underlying native code. - * @constructor Internal constructor. Instances of Subscriber must be created through the [Builder] obtained after - * calling [Session.declareSubscriber] or alternatively through [newBuilder]. + * TODO */ class Subscriber internal constructor( val keyExpr: KeyExpr, val receiver: R?, private var jniSubscriber: JNISubscriber? @@ -81,8 +55,18 @@ class Subscriber internal constructor( } } -data class SubscriberConfig( - var callback: Callback? = null, +data class SubscriberCallbackConfig( + var callback: Callback +) { + var onClose: Runnable? = null + + fun onClose(onClose: Runnable) = apply { this.onClose = onClose } +} + +data class SubscriberHandlerConfig( var handler: Handler? = null, - var onClose: (() -> Unit)? = null -) +) { + var onClose: Runnable? = null + + fun onClose(onClose: Runnable) = apply { this.onClose = onClose } +} diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java index a5ee9e0d..786f2b25 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.Sample; import org.junit.Test; import org.junit.runner.RunWith; @@ -132,10 +132,8 @@ private void runSessionTest(Config clientConfig, Config serverConfig) throws ZEr final Sample[] receivedSample = new Sample[1]; - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - sessionClient.declareSubscriber(TEST_KEY_EXP, config); + sessionClient.declareSubscriber(TEST_KEY_EXP, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); ZBytes payload = ZBytes.from("example message"); sessionClient.put(TEST_KEY_EXP, payload).res(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java index 26e1d2d1..f8dd081a 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.SampleKind; import io.zenoh.sample.Sample; import org.junit.Test; @@ -35,10 +35,8 @@ public void deleteIsProperlyReceivedBySubscriberTest() throws ZError, Interrupte Session session = Zenoh.open(Config.loadDefault()); final Sample[] receivedSample = new Sample[1]; KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); session.delete(keyExpr).res(); Thread.sleep(1000); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index 2cf206ee..f11c6e3c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -19,7 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; import io.zenoh.query.Selector; @@ -45,10 +45,8 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { // Testing non null schema Sample[] receivedSample = new Sample[1]; - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); session.put(keyExpr, payload).encoding(with_schema).res(); Thread.sleep(200); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 78f92649..592a3271 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -5,7 +5,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; import io.zenoh.pubsub.PublisherConfig; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.qos.QoS; import io.zenoh.qos.Reliability; import io.zenoh.sample.SampleKind; @@ -43,9 +43,7 @@ public void setUp() throws ZError { receivedSamples = new ArrayList<>(); - SubscriberConfig subscriberConfig = new SubscriberConfig<>(); - subscriberConfig.setCallback(sample -> receivedSamples.add(sample)); - subscriber = session.declareSubscriber(keyExpr, subscriberConfig); + subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(receivedSamples::add)); } @After diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java index b758e66a..9e09aeb5 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -19,7 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.Sample; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,10 +40,8 @@ public void putTest() throws ZError { Sample[] receivedSample = new Sample[1]; var keyExpr = KeyExpr.tryFrom(TEST_KEY_EXP); - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); session.put(keyExpr, TEST_PAYLOAD).encoding(Encoding.TEXT_PLAIN).res(); subscriber.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java index 8cdb6618..fdd671f8 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java @@ -19,7 +19,8 @@ import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; +import io.zenoh.pubsub.SubscriberHandlerConfig; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; import io.zenoh.sample.Sample; @@ -70,11 +71,8 @@ public void tearDown() { public void subscriber_runsWithCallback() throws ZError { var receivedSamples = new ArrayList(); - var subscriberConfig = new SubscriberConfig<>(); - subscriberConfig.setCallback(receivedSamples::add); - var subscriber = - session.declareSubscriber(testKeyExpr, subscriberConfig); + session.declareSubscriber(testKeyExpr, new SubscriberCallbackConfig(receivedSamples::add)); TEST_VALUES.forEach(value -> { try { @@ -106,12 +104,8 @@ public void subscriber_runsWithCallback() throws ZError { @Test public void subscriber_runsWithHandler() throws ZError { var handler = new QueueHandler(); - - var subscriberConfig = new SubscriberConfig>(); - subscriberConfig.setHandler(handler); - var subscriber = - session.declareSubscriber(testKeyExpr, subscriberConfig); + session.declareSubscriber(testKeyExpr, new SubscriberHandlerConfig<>(handler)); TEST_VALUES.forEach(value -> { try { diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index e93a2fee..3f2cecfe 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -18,7 +18,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.ZBytes; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberConfig; +import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; import io.zenoh.sample.Sample; @@ -61,10 +61,8 @@ public void tearDown() { @Test public void putWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); session.put(keyExpr, payload).attachment(attachment).res(); @@ -79,10 +77,8 @@ public void putWithAttachmentTest() throws ZError { public void publisherPutWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); publisher.put(payload).attachment(attachment).res(); @@ -98,10 +94,8 @@ public void publisherPutWithAttachmentTest() throws ZError { public void publisherPutWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); publisher.put(payload).res(); @@ -116,10 +110,8 @@ public void publisherPutWithoutAttachmentTest() throws ZError { public void publisherDeleteWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); publisher.delete().attachment(attachment).res(); @@ -135,10 +127,8 @@ public void publisherDeleteWithAttachmentTest() throws ZError { public void publisherDeleteWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - SubscriberConfig config = new SubscriberConfig<>(); - config.setCallback(sample -> receivedSample[0] = sample); Subscriber subscriber = - session.declareSubscriber(keyExpr, config); + session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); publisher.delete().res(); From d9eca7d424ce084285758ed2ef9601d2a01c6791 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 26 Nov 2024 15:22:31 -0300 Subject: [PATCH 52/83] Alignment: Queryable declaration and Query.reply config params. --- examples/src/main/java/io/zenoh/ZDelete.java | 2 +- examples/src/main/java/io/zenoh/ZPut.java | 6 +- .../src/main/java/io/zenoh/ZQueryable.java | 3 +- examples/src/main/java/io/zenoh/ZSubThr.java | 4 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 71 ++++------- .../kotlin/io/zenoh/jni/JNISession.kt | 31 ++--- .../kotlin/io/zenoh/pubsub/Delete.kt | 100 ++------------- .../kotlin/io/zenoh/pubsub/Publisher.kt | 12 +- .../commonMain/kotlin/io/zenoh/pubsub/Put.kt | 117 ++---------------- .../src/commonMain/kotlin/io/zenoh/qos/QoS.kt | 29 ++--- .../commonMain/kotlin/io/zenoh/query/Query.kt | 91 +++++++++----- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 96 ++++++++------ .../src/jvmTest/java/io/zenoh/ConfigTest.java | 2 +- .../src/jvmTest/java/io/zenoh/DeleteTest.java | 2 +- .../jvmTest/java/io/zenoh/EncodingTest.java | 17 ++- .../src/jvmTest/java/io/zenoh/GetTest.java | 2 +- .../src/jvmTest/java/io/zenoh/PutTest.java | 3 +- .../jvmTest/java/io/zenoh/QueryableTest.java | 38 +++--- .../jvmTest/java/io/zenoh/SubscriberTest.java | 11 +- .../java/io/zenoh/UserAttachmentTest.java | 10 +- 20 files changed, 249 insertions(+), 398 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZDelete.java b/examples/src/main/java/io/zenoh/ZDelete.java index 49bae297..9a930a1f 100644 --- a/examples/src/main/java/io/zenoh/ZDelete.java +++ b/examples/src/main/java/io/zenoh/ZDelete.java @@ -23,7 +23,7 @@ public static void main(String[] args) throws ZError { try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { System.out.println("Deleting resources matching '" + keyExpr + "'..."); - session.delete(keyExpr).res(); + session.delete(keyExpr); } } } diff --git a/examples/src/main/java/io/zenoh/ZPut.java b/examples/src/main/java/io/zenoh/ZPut.java index e5a7d48b..a49b97f6 100644 --- a/examples/src/main/java/io/zenoh/ZPut.java +++ b/examples/src/main/java/io/zenoh/ZPut.java @@ -17,6 +17,7 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.PutConfig; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; @@ -26,10 +27,7 @@ public static void main(String[] args) throws ZError { try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { String value = "Put from Java!"; - session.put(keyExpr, ZBytes.from(value)) - .congestionControl(CongestionControl.BLOCK) - .priority(Priority.REALTIME) - .res(); + session.put(keyExpr, ZBytes.from(value), new PutConfig().congestionControl(CongestionControl.BLOCK).priority(Priority.REALTIME)); System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); } } diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index b27ebcb9..9c2cf312 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -19,6 +19,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.query.Query; import io.zenoh.query.Queryable; +import io.zenoh.query.ReplyConfig; import org.apache.commons.net.ntp.TimeStamp; import java.util.Optional; @@ -51,7 +52,7 @@ private static void handleRequests(BlockingQueue> receiver, KeyE String valueInfo = query.getPayload() != null ? " with value '" + query.getPayload() + "'" : ""; System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); try { - query.reply(keyExpr, ZBytes.from("Queryable from Java!")).timestamp(TimeStamp.getCurrentTime()).res(); + query.reply(keyExpr, ZBytes.from("Queryable from Java!"), new ReplyConfig().timestamp(TimeStamp.getCurrentTime())); } catch (Exception e) { System.out.println(">> [Queryable] Error sending reply: " + e); } diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index f4cceceb..97295b71 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import kotlin.Unit; +import io.zenoh.pubsub.SubscriberCallbackConfig; public class ZSubThr { @@ -62,7 +62,7 @@ public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening Session"); try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Subscriber subscriber = session.declareSubscriber(keyExpr).callback(sample -> listener()).res()) { + try (Subscriber subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> listener()))) { System.out.println("Press CTRL-C to quit..."); while (true) { Thread.sleep(1000); diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 05920256..81c0329e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -219,15 +219,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { * Declare a [Get] with a [BlockingQueue] receiver. * * ```java - * try (Session session = Session.open()) { - * try (Selector selector = Selector.tryFrom("demo/java/example")) { - * session.get(selector) - * .consolidation(ConsolidationMode.NONE) - * .withValue("Get value example") - * .with(reply -> System.out.println("Received reply " + reply)) - * .res() - * } - * } + * TODO: provide example * ``` * * @param selector The [KeyExpr] to be used for the get operation. @@ -239,43 +231,30 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Put] with the provided value on the specified key expression. * //TODO update - * Example: - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/greeting")) { - * session.put(keyExpr, Value("Hello!")) - * .congestionControl(CongestionControl.BLOCK) - * .priority(Priority.REALTIME) - * .kind(SampleKind.PUT) - * .res(); - * System.out.println("Put 'Hello' on " + keyExpr + "."); - * } - * } - * ``` - * - * @param keyExpr The [KeyExpr] to be used for the put operation. - * @return A resolvable [Put.Builder]. */ - fun put(keyExpr: KeyExpr, payload: IntoZBytes): Put.Builder = Put.newBuilder(this, keyExpr, payload) + @Throws(ZError::class) + fun put(keyExpr: KeyExpr, payload: IntoZBytes) { + resolvePut(keyExpr, payload, PutConfig()) + } + + @Throws(ZError::class) + fun put(keyExpr: KeyExpr, payload: IntoZBytes, config: PutConfig) { + resolvePut(keyExpr, payload, config) + } /** - * Declare a [Delete]. - * - * Example: - * - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example")) { - * session.delete(keyExpr).res(); - * System.out.println("Performed delete on " + keyExpr + "."); - * } - * } - * ``` - * - * @param keyExpr The [KeyExpr] to be used for the delete operation. - * @return a resolvable [Delete.Builder]. + * TODO */ - fun delete(keyExpr: KeyExpr): Delete.Builder = Delete.newBuilder(this, keyExpr) + fun delete(keyExpr: KeyExpr) { + resolveDelete(keyExpr, DeleteConfig()) + } + + /** + * TODO + */ + fun delete(keyExpr: KeyExpr, config: DeleteConfig) { + resolveDelete(keyExpr, config) + } /** Returns if session is open or has been closed. */ fun isClosed(): Boolean { @@ -362,13 +341,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolvePut(keyExpr: KeyExpr, put: Put) { - jniSession?.run { performPut(keyExpr, put) } + internal fun resolvePut(keyExpr: KeyExpr, payload: IntoZBytes, putConfig: PutConfig) { + jniSession?.run { performPut(keyExpr, payload, putConfig) } } @Throws(ZError::class) - internal fun resolveDelete(keyExpr: KeyExpr, delete: Delete) { - jniSession?.run { performDelete(keyExpr, delete) } + internal fun resolveDelete(keyExpr: KeyExpr, deleteConfig: DeleteConfig) { + jniSession?.run { performDelete(keyExpr, deleteConfig) } } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 5fee1185..da853605 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -288,37 +288,38 @@ internal class JNISession { @Throws(ZError::class) fun performPut( keyExpr: KeyExpr, - put: Put, + payload: IntoZBytes, + config: PutConfig, ) { putViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - put.payload.bytes, - put.encoding.id, - put.encoding.schema, - put.qos.congestionControl.value, - put.qos.priority.value, - put.qos.express, - put.attachment?.into()?.bytes, - put.reliability.ordinal + payload.into().bytes, + config.encoding.id, + config.encoding.schema, + config.qos.congestionControl.value, + config.qos.priority.value, + config.qos.express, + config.attachment?.into()?.bytes, + config.reliability.ordinal ) } @Throws(ZError::class) fun performDelete( keyExpr: KeyExpr, - delete: Delete, + config: DeleteConfig, ) { deleteViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - delete.qos.congestionControl.value, - delete.qos.priority.value, - delete.qos.express, - delete.attachment?.into()?.bytes, - delete.reliability.ordinal + config.qos.congestionControl.value, + config.qos.priority.value, + config.qos.express, + config.attachment?.into()?.bytes, + config.reliability.ordinal ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt index b43dc3c1..f713bef1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt @@ -14,107 +14,29 @@ package io.zenoh.pubsub -import io.zenoh.Resolvable -import io.zenoh.Session import io.zenoh.bytes.IntoZBytes -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.qos.Reliability -import kotlin.Throws /** - * Delete operation to perform on Zenoh on a key expression. - * - * Example: - * ```java - * public void deleteExample() throws ZError { - * System.out.println("Opening session..."); - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/java/example")) { - * session.delete(keyExpr).res(); - * System.out.println("Performed a delete on '" + keyExpr); - * } - * } - * } - * ``` - * - * A delete operation is a special case of a Put operation, it is analogous to perform a Put with an empty value and - * specifying the sample kind to be `DELETE`. + * TODO */ -class Delete private constructor( - val keyExpr: KeyExpr, val qos: QoS, val reliability: Reliability, val attachment: IntoZBytes? +data class DeleteConfig( + var qos: QoS = QoS.defaultQoS(), + var reliability: Reliability = Reliability.RELIABLE, + var attachment: IntoZBytes? = null ) { + fun qos(qos: QoS) = apply { this.qos = qos } - companion object { - /** - * Creates a new [Builder] associated with the specified [session] and [keyExpr]. - * - * @param session The [Session] from which the Delete will be performed. - * @param keyExpr The [KeyExpr] upon which the Delete will be performed. - * @return A [Delete] operation [Builder]. - */ - fun newBuilder(session: Session, keyExpr: KeyExpr): Builder { - return Builder(session, keyExpr) - } - } + fun reliability(reliability: Reliability) = apply { this.reliability = reliability } - /** - * Builder to construct a [Delete] operation. - * - * @property session The [Session] from which the Delete will be performed - * @property keyExpr The [KeyExpr] from which the Delete will be performed - * @constructor Create a [Delete] builder. - */ - class Builder internal constructor( - val session: Session, - val keyExpr: KeyExpr, - ) : Resolvable { + fun attachment(attachment: IntoZBytes?) = apply { this.attachment = attachment } - private var attachment: IntoZBytes? = null - private var reliability: Reliability = Reliability.RELIABLE - private var qosBuilder = QoS.Builder() + fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } - fun attachment(attachment: IntoZBytes) { - this.attachment = attachment - } + fun express(express: Boolean) = apply { this.qos.express = express } - /** - * The [Reliability] wished to be obtained from the network. - */ - fun reliability(reliability: Reliability) = apply { this.reliability = reliability } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(express: Boolean) = apply { qosBuilder.express(express) } - - /** - * Sets the [Priority] of the reply. - */ - fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } - - /** - * Sets the [CongestionControl] of the reply. - * - * @param congestionControl - */ - fun congestionControl(congestionControl: CongestionControl) = - apply { qosBuilder.congestionControl(congestionControl) } - - /** - * Performs a DELETE operation on the specified [keyExpr]. - * - * A successful [Result] only states the Delete request was properly sent through the network, it doesn't mean it - * was properly executed remotely. - */ - @Throws(ZError::class) - override fun res() { - // TODO: replace res() with delete() - val delete = Delete(this.keyExpr, qosBuilder.build(), reliability, attachment) - session.resolveDelete(keyExpr, delete) - } - } + fun priority(priority: Priority) = apply { this.qos.priority = priority } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 22c1b5c7..96efa230 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -141,6 +141,16 @@ class Publisher internal constructor( } } +/** + * TODO + */ data class PublisherConfig(var reliability: Reliability = Reliability.RELIABLE, var qos: QoS = QoS.defaultQoS(), - var encoding: Encoding = Encoding.defaultEncoding()) + var encoding: Encoding = Encoding.defaultEncoding()) { + + fun reliability(reliability: Reliability) = apply { this.reliability = reliability } + + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + + fun qos(qos: QoS) = apply { this.qos = qos } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt index 13c0d863..79e369b6 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt @@ -14,125 +14,34 @@ package io.zenoh.pubsub -import io.zenoh.Resolvable -import io.zenoh.Session import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes -import io.zenoh.bytes.ZBytes -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.qos.Reliability /** - * Put operation. - * - * A put puts a [io.zenoh.sample.Sample] into the specified key expression. - * - * Example: - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { - * String value = "Put from Java!"; - * session.put(keyExpr, value) - * .congestionControl(CongestionControl.BLOCK) - * .priority(Priority.REALTIME) - * .kind(SampleKind.PUT) - * .res(); - * System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); - * } - * } - * ``` - * - * This class is an open class for the sake of the [Delete] operation, which is a special case of [Put] operation. - * - * @property keyExpr The [KeyExpr] to which the put operation will be performed. - * @property value The [Value] to put. - * @property qos The [QoS] configuration. - * @property attachment An optional user attachment. + * TODO */ -class Put private constructor( - val keyExpr: KeyExpr, - val payload: ZBytes, - val encoding: Encoding, - val qos: QoS, - val reliability: Reliability, - val attachment: IntoZBytes? +data class PutConfig( + var encoding: Encoding = Encoding.defaultEncoding(), + var qos: QoS = QoS.defaultQoS(), + var reliability: Reliability = Reliability.RELIABLE, + var attachment: IntoZBytes? = null ) { + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } - companion object { + fun qos(qos: QoS) = apply { this.qos = qos } - /** - * Creates a bew [Builder] associated to the specified [session] and [keyExpr]. - * - * @param session The [Session] from which the put will be performed. - * @param keyExpr The [KeyExpr] upon which the put will be performed. - * // todo - * @return A [Put] operation [Builder]. - */ - internal fun newBuilder(session: Session, keyExpr: KeyExpr, payload: IntoZBytes): Builder { - return Builder(session, keyExpr, payload) - } - } + fun reliability(reliability: Reliability) = apply { this.reliability = reliability } - /** - * Builder to construct a [Put] operation. - * - * @property session The [Session] from which the put operation will be performed. - * @property keyExpr The [KeyExpr] upon which the put operation will be performed. - * @property value The [Value] to put. - * @constructor Create a [Put] builder. - */ - class Builder internal constructor( - private val session: Session, - private val keyExpr: KeyExpr, - private val payload: IntoZBytes, - ): Resolvable { + fun attachment(attachment: IntoZBytes?) = apply { this.attachment = attachment } - private var qosBuilder = QoS.Builder() - private var attachment: IntoZBytes? = null - private var encoding: Encoding? = null - private var reliability: Reliability = Reliability.RELIABLE + fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } - /** Change the [Encoding] of the written data. */ - fun encoding(encoding: Encoding) = apply { - this.encoding = encoding - } + fun express(express: Boolean) = apply { this.qos.express = express } - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun express(express: Boolean) = apply { qosBuilder.express(express) } + fun priority(priority: Priority) = apply { this.qos.priority = priority } - /** - * Sets the [Priority] of the reply. - */ - fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } - - /** - * Sets the [CongestionControl] of the reply. - * - * @param congestionControl - */ - fun congestionControl(congestionControl: CongestionControl) = - apply { qosBuilder.congestionControl(congestionControl) } - - /** - * The [Reliability] wished to be obtained from the network. - */ - fun reliability(reliability: Reliability) = apply { this.reliability = reliability } - - /** Set an attachment to the put operation. */ - fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } - - /** Resolves the put operation, returning a [Result]. */ - @Throws(ZError::class) - override fun res() { - // TODO: rename res() to put() - val put = Put(keyExpr, payload.into(), encoding ?: Encoding.defaultEncoding(), qosBuilder.build(), reliability, attachment) - session.run { resolvePut(keyExpr, put) } - } - } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt index 50b4dd10..28b8c114 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt @@ -22,32 +22,21 @@ package io.zenoh.qos * @property express If true, the message is not batched in order to reduce the latency. */ data class QoS ( - val congestionControl: CongestionControl = CongestionControl.DROP, - val priority: Priority = Priority.DATA, - val express: Boolean = false + var congestionControl: CongestionControl = CongestionControl.DROP, + var priority: Priority = Priority.DATA, + var express: Boolean = false ) { + fun congestionControl(congestionControl: CongestionControl) = apply { this.congestionControl = congestionControl } + + fun priority(priority: Priority) = apply { this.priority = priority } + + fun express(express: Boolean) = apply { this.express = express } + companion object { private val defaultQoS = QoS() @JvmStatic fun defaultQoS() = defaultQoS } - - internal class Builder( - private var express: Boolean = false, - private var congestionControl: CongestionControl = CongestionControl.DROP, - private var priority: Priority = Priority.REALTIME, - ) { - - fun express(value: Boolean) = apply { this.express = value } - - fun priority(priority: Priority) = apply { this.priority = priority } - - fun congestionControl(congestionControl: CongestionControl) = - apply { this.congestionControl = congestionControl } - - fun build() = QoS(congestionControl, priority, express) - } - } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 7266d854..12f1fc59 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -14,7 +14,6 @@ package io.zenoh.query -import io.zenoh.Resolvable import io.zenoh.ZenohType import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes @@ -22,6 +21,7 @@ import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIQuery import io.zenoh.keyexpr.KeyExpr +import io.zenoh.sample.Sample import io.zenoh.sample.SampleKind /** @@ -50,18 +50,70 @@ class Query internal constructor( /** Shortcut to the [selector]'s parameters. */ val parameters = selector.parameters + @Throws(ZError::class) + fun reply(keyExpr: KeyExpr, payload: IntoZBytes) = reply(keyExpr, payload, ReplyConfig()) + /** * Reply to the specified key expression. * * @param keyExpr Key expression to reply to. This parameter must not be necessarily the same * as the key expression from the Query, however it must intersect with the query key. - * @return a [ReplySuccess.Builder] */ - fun reply(keyExpr: KeyExpr, payload: IntoZBytes) = ReplyBuilder(this, keyExpr, payload.into(), SampleKind.PUT) + @Throws(ZError::class) + fun reply(keyExpr: KeyExpr, payload: IntoZBytes, config: ReplyConfig) { + val sample = Sample( + keyExpr, + payload.into(), + config.encoding, + SampleKind.PUT, + config.timeStamp, + config.qos, + config.attachment + ) + jniQuery?.apply { + replySuccess(sample) + jniQuery = null + } ?: throw (ZError("Query is invalid")) + } - fun replyDel(keyExpr: KeyExpr) = ReplyBuilder(this, keyExpr, ZBytes(byteArrayOf()), SampleKind.DELETE) //TODO: refactor + /** + * TODO + */ + @Throws(ZError::class) + fun replyDel(keyExpr: KeyExpr) = replyDel(keyExpr, ReplyDelConfig()) - fun replyErr(payload: IntoZBytes) = ReplyErrBuilder(this, payload.into()) + /** + * TODO + */ + @Throws(ZError::class) + fun replyDel(keyExpr: KeyExpr, config: ReplyDelConfig) { + jniQuery?.apply { + replyDelete( + keyExpr, + config.timeStamp, + config.attachment, + config.qos + ) + jniQuery = null + } ?: throw (ZError("Query is invalid")) + } + + /** + * TODO + */ + @Throws(ZError::class) + fun replyErr(payload: IntoZBytes) = replyErr(payload, ReplyErrConfig()) + + /** + * TODO + */ + @Throws(ZError::class) + fun replyErr(payload: IntoZBytes, config: ReplyErrConfig) { + jniQuery?.apply { + replyError(payload.into(), config.encoding) + jniQuery = null + } ?: throw (ZError("Query is invalid")) + } override fun close() { jniQuery?.apply { @@ -74,33 +126,4 @@ class Query internal constructor( protected fun finalize() { close() } - - /** - * Perform a reply operation to the remote [Query]. - * - * A query can not be replied more than once. After the reply is performed, the query is considered - * to be no more valid and further attempts to reply to it will fail. - * - * @param reply The [Reply] to the Query. - * @return A [Resolvable] that returns a [Result] with the status of the reply operation. - */ - internal fun resolveReply(reply: Reply): Resolvable = Resolvable { - jniQuery?.apply { - val result = when (reply) { - is Reply.Success -> { - if (reply.sample.kind == SampleKind.PUT) { - replySuccess(reply.sample) - } else { - replyDelete(reply.sample.keyExpr, reply.sample.timestamp, reply.sample.attachment, reply.sample.qos) - } - } - is Reply.Error -> { - replyError(reply.error, reply.encoding) - } - } - jniQuery = null - return@Resolvable result - } - throw(ZError("Query is invalid")) - } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index 4a25991f..ebb9e657 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -14,16 +14,12 @@ package io.zenoh.query -import io.zenoh.Resolvable import io.zenoh.ZenohType import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.config.ZenohId -import io.zenoh.exceptions.ZError import io.zenoh.sample.Sample -import io.zenoh.sample.SampleKind -import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS @@ -42,20 +38,10 @@ import org.apache.commons.net.ntp.TimeStamp * Generating a reply only makes sense within the context of a [Query], therefore builders below are meant to only * be accessible from [Query.reply]. * - * Example: - * ```java - * session.declareQueryable(keyExpr).with { query -> - * query.reply(keyExpr) - * .success(Value("Hello")) - * .timestamp(TimeStamp(Date.from(Instant.now()))) - * .res() - * }.res() - * ... - * ``` + * TODO: provide example * * @property replierId: unique ID identifying the replier. */ - sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { class Success internal constructor(replierId: ZenohId?, val sample: Sample) : Reply(replierId) { @@ -96,14 +82,19 @@ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { } } -class ReplyBuilder internal constructor(val query: Query, val keyExpr: KeyExpr, val payload: ZBytes, val kind: SampleKind): Resolvable { - - private var encoding: Encoding = Encoding.defaultEncoding() - private var timeStamp: TimeStamp? = null - private var attachment: ZBytes? = null - private var qosBuilder = QoS.Builder() - +/** + * TODO + */ +data class ReplyConfig( + var encoding: Encoding = Encoding.defaultEncoding(), + var timeStamp: TimeStamp? = null, + var attachment: ZBytes? = null, + var qos: QoS = QoS.defaultQoS() +) { + /** + * Sets the [Encoding] of the reply. + */ fun encoding(encoding: Encoding) = apply { this.encoding = encoding } /** @@ -119,12 +110,12 @@ class ReplyBuilder internal constructor(val query: Query, val keyExpr: KeyExpr, /** * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. */ - fun express(express: Boolean) = apply { qosBuilder.express(express) } + fun express(express: Boolean) = apply { qos.express(express) } /** * Sets the [Priority] of the reply. */ - fun priority(priority: Priority) = apply { qosBuilder.priority(priority) } + fun priority(priority: Priority) = apply { qos.priority(priority) } /** * Sets the [CongestionControl] of the reply. @@ -132,29 +123,54 @@ class ReplyBuilder internal constructor(val query: Query, val keyExpr: KeyExpr, * @param congestionControl */ fun congestionControl(congestionControl: CongestionControl) = - apply { qosBuilder.congestionControl(congestionControl) } + apply { qos.congestionControl(congestionControl) } +} +/** + * TODO + */ +data class ReplyDelConfig( + var timeStamp: TimeStamp? = null, + var attachment: ZBytes? = null, + var qos: QoS = QoS.defaultQoS() +) { /** - * Constructs the reply sample with the provided parameters and triggers the reply to the query. + * Sets the [TimeStamp] of the replied [Sample]. */ - @Throws(ZError::class) - override fun res() { - val sample = Sample(keyExpr, payload, encoding, kind, timeStamp, qosBuilder.build(), attachment) - return query.resolveReply(Reply.Success(null, sample)).res() - } -} + fun timestamp(timeStamp: TimeStamp) = apply { this.timeStamp = timeStamp } -class ReplyErrBuilder internal constructor(val query: Query, val payload: ZBytes): Resolvable { + /** + * Appends an attachment to the reply. + */ + fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment.into() } - private var encoding: Encoding = Encoding.defaultEncoding() + /** + * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. + */ + fun express(express: Boolean) = apply { qos.express(express) } - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + /** + * Sets the [Priority] of the reply. + */ + fun priority(priority: Priority) = apply { qos.priority(priority) } /** - * Constructs the reply sample with the provided parameters and triggers the reply to the query. + * Sets the [CongestionControl] of the reply. + * + * @param congestionControl */ - @Throws(ZError::class) - override fun res() { - return query.resolveReply(Reply.Error(null, payload, encoding)).res() - } + fun congestionControl(congestionControl: CongestionControl) = + apply { qos.congestionControl(congestionControl) } +} + +/** + * TODO + */ +data class ReplyErrConfig internal constructor(var encoding: Encoding = Encoding.defaultEncoding()) { + + /** + * Sets the [Encoding] of the reply. + */ + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java index 786f2b25..3645e840 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -135,7 +135,7 @@ private void runSessionTest(Config clientConfig, Config serverConfig) throws ZEr Subscriber subscriber = sessionClient.declareSubscriber(TEST_KEY_EXP, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); ZBytes payload = ZBytes.from("example message"); - sessionClient.put(TEST_KEY_EXP, payload).res(); + sessionClient.put(TEST_KEY_EXP, payload); Thread.sleep(1000); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java index f8dd081a..40b6d485 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java @@ -37,7 +37,7 @@ public void deleteIsProperlyReceivedBySubscriberTest() throws ZError, Interrupte KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); Subscriber subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); - session.delete(keyExpr).res(); + session.delete(keyExpr); Thread.sleep(1000); subscriber.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index f11c6e3c..7075ed01 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -18,11 +18,10 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.pubsub.SubscriberCallbackConfig; -import io.zenoh.query.QueryableCallbackConfig; -import io.zenoh.query.Reply; -import io.zenoh.query.Selector; +import io.zenoh.query.*; import io.zenoh.sample.Sample; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,7 +47,7 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { Subscriber subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); - session.put(keyExpr, payload).encoding(with_schema).res(); + session.put(keyExpr, payload, new PutConfig().encoding(with_schema)); Thread.sleep(200); assertNotNull(receivedSample[0]); @@ -56,7 +55,7 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { // Testing null schema receivedSample[0] = null; - session.put(keyExpr, payload).encoding(without_schema).res(); + session.put(keyExpr, payload, new PutConfig().encoding(without_schema)); Thread.sleep(200); assertEquals(receivedSample[0].getEncoding(), without_schema); @@ -77,9 +76,9 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { try { KeyExpr queryKeyExpr = query.getKeyExpr(); if (queryKeyExpr.equals(test1.getKeyExpr())) { - query.reply(queryKeyExpr, payload).encoding(without_schema).res(); + query.reply(queryKeyExpr, payload, new ReplyConfig().encoding(without_schema)); } else if (queryKeyExpr.equals(test2.getKeyExpr())) { - query.reply(queryKeyExpr, payload).encoding(with_schema).res(); + query.reply(queryKeyExpr, payload, new ReplyConfig().encoding(with_schema)); } } catch (Exception e) { throw new RuntimeException(e); @@ -126,9 +125,9 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { KeyExpr keyExpr1 = query.getKeyExpr(); try { if (keyExpr1.equals(test1.getKeyExpr())) { - query.replyErr(replyPayload).encoding(without_schema).res(); + query.replyErr(replyPayload, new ReplyErrConfig().encoding(without_schema)); } else if (keyExpr1.equals(test2.getKeyExpr())) { - query.replyErr(replyPayload).encoding(with_schema).res(); + query.replyErr(replyPayload, new ReplyErrConfig().encoding(with_schema)); } } catch (Exception e) { throw new RuntimeException(e); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index e4498c27..bee3ede7 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -37,7 +37,7 @@ public void setUp() throws ZError { queryable = session.declareQueryable(selector.getKeyExpr(), new QueryableCallbackConfig(query -> { try { - query.reply(query.getKeyExpr(), payload).timestamp(timestamp).res(); + query.reply(query.getKeyExpr(), payload, new ReplyConfig().timestamp(timestamp)); } catch (ZError e) { throw new RuntimeException(e); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java index 9e09aeb5..b8908e5c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -18,6 +18,7 @@ import io.zenoh.bytes.Encoding; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.Sample; @@ -43,7 +44,7 @@ public void putTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); - session.put(keyExpr, TEST_PAYLOAD).encoding(Encoding.TEXT_PLAIN).res(); + session.put(keyExpr, TEST_PAYLOAD, new PutConfig().encoding(Encoding.TEXT_PLAIN)); subscriber.close(); session.close(); assertNotNull(receivedSample[0]); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index f8ac9f7a..093893fe 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -60,18 +60,17 @@ public void queryableRunsWithCallback() throws ZError { ); var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> - { - try { - query.reply(testKeyExpr, testPayload) - .timestamp(timestamp) - .congestionControl(QoS.defaultQoS().getCongestionControl()) - .priority(QoS.defaultQoS().getPriority()) - .express(QoS.defaultQoS().getExpress()) - .res(); - } catch (ZError e) { - throw new RuntimeException(e); - } - } + { + try { + query.reply(testKeyExpr, testPayload, new ReplyConfig() + .timestamp(timestamp) + .congestionControl(QoS.defaultQoS().getCongestionControl()) + .priority(QoS.defaultQoS().getPriority()) + .express(QoS.defaultQoS().getExpress())); + } catch (ZError e) { + throw new RuntimeException(e); + } + } )); Reply[] reply = new Reply[1]; @@ -138,12 +137,11 @@ public void queryReplySuccessTest() throws ZError { var timestamp = TimeStamp.getCurrentTime(); QueryableCallbackConfig config = new QueryableCallbackConfig(query -> { try { - query.reply(testKeyExpr, message) + query.reply(testKeyExpr, message, new ReplyConfig() .timestamp(timestamp) .priority(Priority.DATA_HIGH) .express(true) - .congestionControl(CongestionControl.DROP) - .res(); + .congestionControl(CongestionControl.DROP)); } catch (ZError e) { throw new RuntimeException(e); } @@ -174,7 +172,7 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { try { - query.replyErr(errorMessage).res(); + query.replyErr(errorMessage); } catch (ZError e) { throw new RuntimeException(e); } @@ -200,7 +198,9 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { try { - query.replyDel(testKeyExpr).timestamp(timestamp).res(); + var config = new ReplyDelConfig(); + config.setTimeStamp(timestamp); + query.replyDel(testKeyExpr, config); } catch (ZError e) { throw new RuntimeException(e); } @@ -273,6 +273,8 @@ public void reply(Query query) throws ZError { null ); performedReplies.add(sample); - query.reply(query.getKeyExpr(), payload).timestamp(sample.getTimestamp()).res(); + var config = new ReplyConfig(); + config.setTimeStamp(sample.getTimestamp()); + query.reply(query.getKeyExpr(), payload, config); } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java index fdd671f8..7b898bc4 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java @@ -19,6 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.pubsub.SubscriberHandlerConfig; import io.zenoh.qos.CongestionControl; @@ -76,11 +77,10 @@ public void subscriber_runsWithCallback() throws ZError { TEST_VALUES.forEach(value -> { try { - session.put(testKeyExpr, value.getFirst()) + session.put(testKeyExpr, value.getFirst(), new PutConfig() .encoding(value.getSecond()) .priority(TEST_PRIORITY) - .congestionControl(TEST_CONGESTION_CONTROL) - .res(); + .congestionControl(TEST_CONGESTION_CONTROL)); } catch (ZError e) { throw new RuntimeException(e); } @@ -109,11 +109,10 @@ public void subscriber_runsWithHandler() throws ZError { TEST_VALUES.forEach(value -> { try { - session.put(testKeyExpr, value.getFirst()) + session.put(testKeyExpr, value.getFirst(), new PutConfig() .encoding(value.getSecond()) .priority(TEST_PRIORITY) - .congestionControl(TEST_CONGESTION_CONTROL) - .res(); + .congestionControl(TEST_CONGESTION_CONTROL)); } catch (ZError e) { throw new RuntimeException(e); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 3f2cecfe..c7bf129b 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -17,10 +17,12 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.ZBytes; +import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; +import io.zenoh.query.ReplyConfig; import io.zenoh.sample.Sample; import org.junit.After; import org.junit.Before; @@ -64,7 +66,7 @@ public void putWithAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); - session.put(keyExpr, payload).attachment(attachment).res(); + session.put(keyExpr, payload, new PutConfig().attachment(attachment)); subscriber.close(); @@ -145,7 +147,7 @@ public void queryWithAttachmentTest() throws ZError { var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { receivedAttachment[0] = query.getAttachment(); try { - query.reply(keyExpr, payload).res(); + query.reply(keyExpr, payload); } catch (ZError e) { throw new RuntimeException(e); } @@ -164,7 +166,7 @@ public void queryReplyWithAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { try { - query.reply(keyExpr, payload).attachment(attachment).res(); + query.reply(keyExpr, payload, new ReplyConfig().attachment(attachment)); } catch (ZError e) { throw new RuntimeException(e); } @@ -185,7 +187,7 @@ public void queryReplyWithoutAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { try { - query.reply(keyExpr, payload).res(); + query.reply(keyExpr, payload); } catch (ZError e) { throw new RuntimeException(e); } From bebd45f25898c82449dfb8f2ce281456568b67ff Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 26 Nov 2024 17:21:53 -0300 Subject: [PATCH 53/83] Alignment: Get config params --- examples/src/main/java/io/zenoh/ZGet.java | 3 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 100 ++++++--- .../kotlin/io/zenoh/jni/JNISession.kt | 105 +++++++-- .../commonMain/kotlin/io/zenoh/query/Get.kt | 199 ++++-------------- .../jvmTest/java/io/zenoh/EncodingTest.java | 20 +- .../src/jvmTest/java/io/zenoh/GetTest.java | 22 +- .../jvmTest/java/io/zenoh/QueryableTest.java | 15 +- .../java/io/zenoh/UserAttachmentTest.java | 7 +- 8 files changed, 230 insertions(+), 241 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index 1b5be58e..d666301b 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -28,8 +28,7 @@ public static void main(String[] args) throws ZError, InterruptedException { try (Session session = Zenoh.open(Config.loadDefault())) { try (Selector selector = Selector.tryFrom("demo/example/**")) { System.out.println("Performing Get on '" + selector + "'..."); - BlockingQueue> receiver = session.get(selector).res(); - assert receiver != null; + BlockingQueue> receiver = session.get(selector); while (true) { Optional wrapper = receiver.take(); if (wrapper.isEmpty()) { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 81c0329e..f9fe84ef 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -14,12 +14,12 @@ package io.zenoh -import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.config.ZenohId import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback +import io.zenoh.handlers.Handler import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr import io.zenoh.pubsub.* @@ -27,10 +27,8 @@ import io.zenoh.query.* import io.zenoh.query.Query import io.zenoh.query.Queryable import io.zenoh.sample.Sample -import io.zenoh.query.Selector import io.zenoh.session.SessionDeclaration import io.zenoh.session.SessionInfo -import java.time.Duration import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque @@ -120,7 +118,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { - return resolveSubscriberWithHandler(keyExpr, SubscriberHandlerConfig(BlockingQueueHandler(LinkedBlockingDeque()))) + return resolveSubscriberWithHandler( + keyExpr, + SubscriberHandlerConfig(BlockingQueueHandler(LinkedBlockingDeque())) + ) } /** @@ -221,12 +222,56 @@ class Session private constructor(private val config: Config) : AutoCloseable { * ```java * TODO: provide example * ``` - * - * @param selector The [KeyExpr] to be used for the get operation. - * @return a resolvable [Get.Builder] with a [BlockingQueue] receiver. */ - fun get(selector: IntoSelector): Get.Builder>> = Get.newBuilder(this, selector.into()) + fun get(selector: IntoSelector): BlockingQueue> { + val handler = BlockingQueueHandler(LinkedBlockingDeque()) + val config = GetConfig() + return resolveGetWithHandler( + selector, + handler, + config + ) + } + + /** + * TODO + */ + fun get(selector: IntoSelector, config: GetConfig): BlockingQueue> { + val handler = BlockingQueueHandler(LinkedBlockingDeque()) + return resolveGetWithHandler( + selector, + handler, + config + ) + } + + /** + * TODO + */ + fun get(selector: IntoSelector, handler: Handler): R { + return resolveGetWithHandler(selector, handler, GetConfig()) + } + /** + * TODO + */ + fun get(selector: IntoSelector, handler: Handler, config: GetConfig): R { + return resolveGetWithHandler(selector, handler, config) + } + + /** + * TODO + */ + fun get(selector: IntoSelector, callback: Callback) { + return resolveGetWithCallback(selector, callback, GetConfig()) + } + + /** + * TODO + */ + fun get(selector: IntoSelector, callback: Callback, config: GetConfig) { + return resolveGetWithCallback(selector, callback, config) + } /** * Declare a [Put] with the provided value on the specified key expression. @@ -274,7 +319,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { val publisher = declarePublisher(keyExpr, config) declarations.add(publisher) publisher - } ?: throw(sessionClosedException) + } ?: throw (sessionClosedException) } @Throws(ZError::class) @@ -322,22 +367,29 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolveGet( - selector: Selector, + internal fun resolveGetWithHandler( + selector: IntoSelector, + handler: Handler, + config: GetConfig + ): R { + return jniSession?.performGetWithHandler( + selector, + handler, + config + ) ?: throw sessionClosedException + } + + @Throws(ZError::class) + internal fun resolveGetWithCallback( + selector: IntoSelector, callback: Callback, - onClose: () -> Unit, - receiver: R?, - timeout: Duration, - target: QueryTarget, - consolidation: ConsolidationMode, - payload: IntoZBytes?, - encoding: Encoding?, - attachment: IntoZBytes?, - ): R? { - if (jniSession == null) { - throw sessionClosedException - } - return jniSession?.performGet(selector, callback, onClose, receiver, timeout, target, consolidation, payload, encoding, attachment) + config: GetConfig + ) { + return jniSession?.performGetWithCallback( + selector, + callback, + config + ) ?: throw sessionClosedException } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index da853605..ffa592e3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -27,6 +27,7 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.config.ZenohId import io.zenoh.bytes.into import io.zenoh.Config +import io.zenoh.handlers.Handler import io.zenoh.pubsub.* import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority @@ -35,7 +36,6 @@ import io.zenoh.query.* import io.zenoh.sample.Sample import io.zenoh.sample.SampleKind import org.apache.commons.net.ntp.TimeStamp -import java.time.Duration import java.util.concurrent.atomic.AtomicLong /** Adapter class to handle the communication with the Zenoh JNI code for a [Session]. */ @@ -125,7 +125,11 @@ internal class JNISession { config.callback.run(sample) } val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, fun() { config.onClose?.run() } + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + sessionPtr.get(), + subCallback, + fun() { config.onClose?.run() } ) return Subscriber(keyExpr, null, JNISubscriber(subscriberRawPtr)) } @@ -203,18 +207,11 @@ internal class JNISession { } @Throws(ZError::class) - fun performGet( - selector: Selector, + fun performGetWithCallback( + intoSelector: IntoSelector, callback: Callback, - onClose: () -> Unit, - receiver: R, - timeout: Duration, - target: QueryTarget, - consolidation: ConsolidationMode, - payload: IntoZBytes?, - encoding: Encoding?, - attachment: IntoZBytes? - ): R { + config: GetConfig + ) { val getCallback = JNIGetCallback { replierId: ByteArray?, success: Boolean, @@ -253,24 +250,88 @@ internal class JNISession { callback.run(reply) } + val selector = intoSelector.into() + getViaJNI( + selector.keyExpr.jniKeyExpr?.ptr ?: 0, + selector.keyExpr.keyExpr, + selector.parameters.toString(), + sessionPtr.get(), + getCallback, + fun() { config.onClose?.run() }, + config.timeout.toMillis(), + config.target.ordinal, + config.consolidation.ordinal, + config.attachment?.into()?.bytes, + config.payload?.into()?.bytes, + config.encoding?.id ?: Encoding.defaultEncoding().id, + config.encoding?.schema + ) + } + + @Throws(ZError::class) + fun performGetWithHandler( + intoSelector: IntoSelector, + handler: Handler, + config: GetConfig + ): R { + val getCallback = JNIGetCallback { + replierId: ByteArray?, + success: Boolean, + keyExpr: String?, + payload1: ByteArray, + encodingId: Int, + encodingSchema: String?, + kind: Int, + timestampNTP64: Long, + timestampIsValid: Boolean, + attachmentBytes: ByteArray?, + express: Boolean, + priority: Int, + congestionControl: Int, + -> + val reply: Reply + if (success) { + val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null + val sample = Sample( + KeyExpr(keyExpr!!, null), + payload1.into(), + Encoding(encodingId, schema = encodingSchema), + SampleKind.fromInt(kind), + timestamp, + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() + ) + reply = Reply.Success(replierId?.let { ZenohId(it) }, sample) + } else { + reply = Reply.Error( + replierId?.let { ZenohId(it) }, + payload1.into(), + Encoding(encodingId, schema = encodingSchema) + ) + } + handler.handle(reply) + } + + val selector = intoSelector.into() getViaJNI( selector.keyExpr.jniKeyExpr?.ptr ?: 0, selector.keyExpr.keyExpr, selector.parameters.toString(), sessionPtr.get(), getCallback, - onClose, - timeout.toMillis(), - target.ordinal, - consolidation.ordinal, - attachment?.into()?.bytes, - payload?.into()?.bytes, - encoding?.id ?: Encoding.defaultEncoding().id, - encoding?.schema + fun() { config.onClose?.run() }, + config.timeout.toMillis(), + config.target.ordinal, + config.consolidation.ordinal, + config.attachment?.into()?.bytes, + config.payload?.into()?.bytes, + config.encoding?.id ?: Encoding.defaultEncoding().id, + config.encoding?.schema ) - return receiver + return handler.receiver() } + @Throws(ZError::class) fun declareKeyExpr(keyExpr: String): KeyExpr { val ptr = declareKeyExprViaJNI(sessionPtr.get(), keyExpr) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index a1c359ac..850e8154 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -14,180 +14,59 @@ package io.zenoh.query -import io.zenoh.handlers.Callback -import io.zenoh.Session import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes -import io.zenoh.bytes.ZBytes -import io.zenoh.exceptions.ZError -import io.zenoh.handlers.BlockingQueueHandler -import io.zenoh.handlers.Handler import java.time.Duration -import java.util.* -import java.util.concurrent.BlockingQueue -import java.util.concurrent.LinkedBlockingDeque /** * Get to query data from the matching queryables in the system. * - * Example with a [Callback]: - * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/java/example")) { - * session.get(keyExpr) - * .consolidation(ConsolidationMode.NONE) - * .withValue("Get value example") - * .with(reply -> System.out.println("Received reply " + reply)) - * .res() - * } - * } - * ``` - * - * @param R Receiver type of the [Handler] implementation. If no handler is provided to the builder, R will be [Unit]. + * TODO */ -class Get private constructor() { - - companion object { - /** - * Creates a bew [Builder] associated to the specified [session] and [keyExpr]. - * - * @param session The [Session] from which the query will be triggered. - * @param selector The [Selector] with which the query will be performed. - * @return A [Builder] with a default [BlockingQueueHandler] to handle any incoming [Reply]. - */ - fun newBuilder(session: Session, selector: Selector): Builder>> { - return Builder(session, selector, handler = BlockingQueueHandler(LinkedBlockingDeque())) - } +data class GetConfig( + var timeout: Duration = Duration.ofMillis(10000), + var target: QueryTarget = QueryTarget.BEST_MATCHING, + var consolidation: ConsolidationMode = ConsolidationMode.AUTO, + var payload: IntoZBytes? = null, + var encoding: Encoding? = null, + var attachment: IntoZBytes? = null, + var onClose: Runnable? = null, +) { + + /** Specify the [QueryTarget]. */ + fun target(target: QueryTarget) = apply { + this.target = target } - /** - * Builder to construct a [Get]. - * - * Either a [Handler] or a [Callback] must be specified. Note neither of them are stackable and are mutually exclusive, - * meaning that it is not possible to specify multiple callbacks and/or handlers, the builder only considers the - * last one specified. - * - * @param R The receiver type of the [Handler] implementation, defaults to [Unit] when no handler is specified. - * @property session The [Session] from which the query will be performed. - * @property selector The [Selector] with which the get query will be performed. - * @constructor Creates a Builder. This constructor is internal and should not be called directly. Instead, this - * builder should be obtained through the [Session] after calling [Session.get]. - */ - class Builder internal constructor( - private val session: Session, - private val selector: Selector, - private var callback: Callback? = null, - private var handler: Handler? = null, - ) { - - private var timeout = Duration.ofMillis(10000) - private var target: QueryTarget = QueryTarget.BEST_MATCHING - private var consolidation: ConsolidationMode = ConsolidationMode.AUTO - private var payload: ZBytes? = null - private var encoding: Encoding? = null - private var attachment: ZBytes? = null - private var onClose: (() -> Unit)? = null - - private constructor(other: Builder<*>, handler: Handler?) : this(other.session, other.selector) { - this.handler = handler - copyParams(other) - } - - private constructor(other: Builder<*>, callback: Callback?) : this(other.session, other.selector) { - this.callback = callback - copyParams(other) - } - - private fun copyParams(other: Builder<*>) { - this.timeout = other.timeout - this.target = other.target - this.consolidation = other.consolidation - this.payload = other.payload - this.encoding = other.encoding - this.attachment = other.attachment - this.onClose = other.onClose - } - - /** Specify the [QueryTarget]. */ - fun target(target: QueryTarget): Builder { - this.target = target - return this - } - - /** Specify the [ConsolidationMode]. */ - fun consolidation(consolidation: ConsolidationMode): Builder { - this.consolidation = consolidation - return this - } - - /** Specify the timeout. */ - fun timeout(timeout: Duration): Builder { - this.timeout = timeout - return this - } - - fun payload(payload: IntoZBytes): Builder { - this.payload = payload.into() - return this - } - - fun encoding(encoding: Encoding): Builder { - this.encoding = encoding - return this - } - - /** Specify an attachment. */ - fun attachment(attachment: IntoZBytes): Builder { - this.attachment = attachment.into() - return this - } + /** Specify the [ConsolidationMode]. */ + fun consolidation(consolidation: ConsolidationMode) = apply { + this.consolidation = consolidation + } - /** - * Specify an action to be invoked when the Get operation is over. - * - * Zenoh will trigger ths specified action once no more replies are to be expected. - */ - fun onClose(action: () -> Unit): Builder { - this.onClose = action - return this - } + /** Specify the timeout. */ + fun timeout(timeout: Duration) = apply { + this.timeout = timeout + } - /** Specify a [Callback]. Overrides any previously specified callback or handler. */ - fun callback(callback: Callback): Builder = Builder(this, callback) + fun payload(payload: IntoZBytes) = apply { + this.payload = payload.into() + } - /** Specify a [Handler]. Overrides any previously specified callback or handler. */ - fun with(handler: Handler): Builder = Builder(this, handler) + fun encoding(encoding: Encoding) = apply { + this.encoding = encoding + } - /** Specify a [BlockingQueue]. Overrides any previously specified callback or handler. */ - fun with(blockingQueue: BlockingQueue>): Builder>> = Builder(this, BlockingQueueHandler(blockingQueue)) + /** Specify an attachment. */ + fun attachment(attachment: IntoZBytes) = apply { + this.attachment = attachment.into() + } - /** - * Resolve the builder triggering the query. - * - * @return The receiver [R] from the specified [Handler] (if specified). - */ - @Throws(ZError::class) - fun res(): R? { - require(callback != null || handler != null) { "Either a callback or a handler must be provided." } - val resolvedCallback = callback ?: Callback { t: Reply -> handler?.handle(t) } - val resolvedOnClose = fun() { - onClose?.invoke() - handler?.onClose() - } - return session.run { - resolveGet( - selector, - resolvedCallback, - resolvedOnClose, - handler?.receiver(), - timeout, - target, - consolidation, - payload, - encoding, - attachment - ) - } - } + /** + * Specify an action to be invoked when the Get operation is over. + * + * Zenoh will trigger ths specified action once no more replies are to be expected. + */ + fun onClose(action: Runnable) = apply { + this.onClose = action } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index 7075ed01..db53fbb6 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -88,10 +88,10 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { // Testing with null schema on a reply success scenario. Sample[] receivedSample = new Sample[1]; - session.get(test1).callback(reply -> { + session.get(test1, reply -> { assertTrue(reply instanceof Reply.Success); receivedSample[0] = ((Reply.Success) reply).getSample(); - }).res(); + }); Thread.sleep(200); assertNotNull(receivedSample[0]); @@ -99,10 +99,10 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { // Testing with non-null schema on a reply success scenario. receivedSample[0] = null; - session.get(test2).callback(reply -> { + session.get(test2, reply -> { assertTrue(reply instanceof Reply.Success); receivedSample[0] = ((Reply.Success) reply).getSample(); - }).res(); + }); Thread.sleep(200); assertNotNull(receivedSample[0]); @@ -137,14 +137,14 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { // Testing with null schema on a reply error scenario. ZBytes[] errorMessage = new ZBytes[1]; Encoding[] errorEncoding = new Encoding[1]; - session.get(test1).callback(reply -> + session.get(test1, reply -> { assertTrue(reply instanceof Reply.Error); Reply.Error reply1 = (Reply.Error) reply; errorMessage[0] = reply1.getError(); errorEncoding[0] = reply1.getEncoding(); } - ).res(); + ); Thread.sleep(200); assertNotNull(errorMessage[0]); @@ -155,13 +155,13 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { // Testing with non-null schema on a reply error scenario. errorMessage[0] = null; errorEncoding[0] = null; - session.get(test2).callback(reply -> + session.get(test2, reply -> { assertTrue(reply instanceof Reply.Error); Reply.Error error = (Reply.Error) reply; errorMessage[0] = error.getError(); errorEncoding[0] = error.getEncoding(); - }).res(); + }); Thread.sleep(200); assertNotNull(errorMessage[0]); @@ -185,7 +185,7 @@ public void encoding_queryTest() throws ZError, InterruptedException { })); // Testing with null schema - session.get(selector).callback(reply -> {}).payload(payload).encoding(without_schema).res(); + session.get(selector, new GetConfig().payload(payload).encoding(without_schema)); Thread.sleep(200); assertEquals(receivedEncoding[0], without_schema); @@ -194,7 +194,7 @@ public void encoding_queryTest() throws ZError, InterruptedException { // Testing non-null schema receivedEncoding[0] = null; - session.get(selector).callback(reply -> {}).payload(payload).encoding(with_schema).res(); + session.get(selector, new GetConfig().payload(payload).encoding(with_schema)); Thread.sleep(200); assertEquals(receivedEncoding[0], with_schema); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index bee3ede7..b9031065 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -35,13 +35,13 @@ public void setUp() throws ZError { session = Zenoh.open(Config.loadDefault()); selector = Selector.tryFrom("example/testing/keyexpr"); queryable = session.declareQueryable(selector.getKeyExpr(), new QueryableCallbackConfig(query -> - { - try { - query.reply(query.getKeyExpr(), payload, new ReplyConfig().timestamp(timestamp)); - } catch (ZError e) { - throw new RuntimeException(e); - } + { + try { + query.reply(query.getKeyExpr(), payload, new ReplyConfig().timestamp(timestamp)); + } catch (ZError e) { + throw new RuntimeException(e); } + } )); } @@ -53,12 +53,10 @@ public void tearDown() throws ZError { } @Test - public void get_runsWithCallbackTest() throws ZError { + public void get_runsWithCallbackTest() { Reply[] reply = new Reply[1]; - session.get(selector).callback( reply1 -> { - reply[0] = reply1; - }).timeout(Duration.ofMillis(1000)).res(); + session.get(selector, reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); assertNotNull(reply[0]); Sample sample = ((Reply.Success) reply[0]).getSample(); @@ -70,7 +68,7 @@ public void get_runsWithCallbackTest() throws ZError { @Test public void get_runsWithHandlerTest() throws ZError { - ArrayList receiver = session.get(selector).with(new TestHandler()).timeout(Duration.ofMillis(1000)).res(); + ArrayList receiver = session.get(selector, new TestHandler(), new GetConfig().timeout(Duration.ofMillis(1000))); for (Reply reply : receiver) { Sample sample = ((Reply.Success) reply).getSample(); assertEquals(payload, sample.getPayload()); @@ -88,7 +86,7 @@ public void getWithSelectorParamsTest() throws ZError { Parameters params = Parameters.from("arg1=val1&arg2=val2&arg3"); Selector selectorWithParams = new Selector(selector.getKeyExpr(), params); - session.get(selectorWithParams).timeout(Duration.ofMillis(1000)).res(); + session.get(selectorWithParams, new GetConfig().timeout(Duration.ofMillis(1000))); queryable.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index 093893fe..5d51d6bf 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -74,7 +74,7 @@ public void queryableRunsWithCallback() throws ZError { )); Reply[] reply = new Reply[1]; - session.get(testKeyExpr.into()).callback(reply1 -> reply[0] = reply1).timeout(Duration.ofMillis(1000)).res(); + session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); assertNotNull(reply[0]); Sample receivedSample = ((Reply.Success) reply[0]).getSample(); @@ -90,7 +90,7 @@ public void queryableRunsWithHandler() throws ZError, InterruptedException { Thread.sleep(500); Reply[] reply = new Reply[1]; - session.get(testKeyExpr.into()).callback(reply1 -> reply[0] = reply1).res(); + session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1, new GetConfig()); Thread.sleep(500); @@ -104,7 +104,7 @@ public void queryTest() throws ZError, InterruptedException { var config = new QueryableCallbackConfig(query -> receivedQuery[0] = query); var queryable = session.declareQueryable(testKeyExpr, config); - session.get(testKeyExpr).res(); + session.get(testKeyExpr); Thread.sleep(100); @@ -117,8 +117,7 @@ public void queryTest() throws ZError, InterruptedException { receivedQuery[0] = null; var payload = ZBytes.from("Test value"); var attachment = ZBytes.from("Attachment"); - session.get(testKeyExpr).callback(reply -> { - }).payload(payload).encoding(Encoding.ZENOH_STRING).attachment(attachment).res(); + session.get(testKeyExpr, new GetConfig().payload(payload).encoding(Encoding.ZENOH_STRING).attachment(attachment)); Thread.sleep(100); @@ -150,7 +149,7 @@ public void queryReplySuccessTest() throws ZError { Queryable queryable = session.declareQueryable(testKeyExpr, config); Reply[] receivedReply = new Reply[1]; - session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); + session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); queryable.close(); @@ -180,7 +179,7 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { )); Reply[] receivedReply = new Reply[1]; - session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); + session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); Thread.sleep(1000); queryable.close(); @@ -207,7 +206,7 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { })); Reply[] receivedReply = new Reply[1]; - session.get(testKeyExpr).callback(reply -> receivedReply[0] = reply).timeout(Duration.ofMillis(10)).res(); + session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); Thread.sleep(1000); queryable.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index c7bf129b..cbe2af21 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -20,6 +20,7 @@ import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.pubsub.SubscriberCallbackConfig; +import io.zenoh.query.GetConfig; import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; import io.zenoh.query.ReplyConfig; @@ -153,7 +154,7 @@ public void queryWithAttachmentTest() throws ZError { } })); - session.get(keyExpr).callback(reply -> {}).attachment(attachment).timeout(Duration.ofMillis(1000)).res(); + session.get(keyExpr, new GetConfig().attachment(attachment).timeout(Duration.ofMillis(1000))); queryable.close(); @@ -172,7 +173,7 @@ public void queryReplyWithAttachmentTest() throws ZError { } })); - session.get(keyExpr).callback(reply1 -> reply[0] = reply1).attachment(attachment).timeout(Duration.ofMillis(1000)).res(); + session.get(keyExpr, reply1 -> reply[0] = reply1, new GetConfig().attachment(attachment).timeout(Duration.ofMillis(1000))); queryable.close(); @@ -192,7 +193,7 @@ public void queryReplyWithoutAttachmentTest() throws ZError { throw new RuntimeException(e); } })); - session.get(keyExpr).callback(reply1 -> reply[0] = reply1).timeout(Duration.ofMillis(1000)).res(); + session.get(keyExpr, reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); queryable.close(); From 73fad03d5088a8ef23868cbe654ac1beb42db663 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 26 Nov 2024 17:52:39 -0300 Subject: [PATCH 54/83] Alignment: Subscriber config params refactor --- examples/src/main/java/io/zenoh/ZSubThr.java | 3 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 39 ++++++++++++++----- .../kotlin/io/zenoh/jni/JNISession.kt | 12 +++--- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 18 +-------- .../src/jvmTest/java/io/zenoh/ConfigTest.java | 3 +- .../src/jvmTest/java/io/zenoh/DeleteTest.java | 3 +- .../jvmTest/java/io/zenoh/EncodingTest.java | 3 +- .../jvmTest/java/io/zenoh/PublisherTest.java | 3 +- .../src/jvmTest/java/io/zenoh/PutTest.java | 3 +- .../jvmTest/java/io/zenoh/SubscriberTest.java | 6 +-- .../java/io/zenoh/UserAttachmentTest.java | 11 +++--- 11 files changed, 50 insertions(+), 54 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index 97295b71..79fa3210 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -17,7 +17,6 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberCallbackConfig; public class ZSubThr { @@ -62,7 +61,7 @@ public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening Session"); try (Session session = Zenoh.open(Config.loadDefault())) { try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Subscriber subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> listener()))) { + try (Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> listener())) { System.out.println("Press CTRL-C to quit..."); while (true) { Thread.sleep(1000); diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index f9fe84ef..ba7ad222 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -120,7 +120,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { return resolveSubscriberWithHandler( keyExpr, - SubscriberHandlerConfig(BlockingQueueHandler(LinkedBlockingDeque())) + BlockingQueueHandler(LinkedBlockingDeque()), + SubscriberConfig() ) } @@ -130,8 +131,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO */ @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberHandlerConfig): Subscriber { - return resolveSubscriberWithHandler(keyExpr, config) + fun declareSubscriber(keyExpr: KeyExpr, handler: Handler): Subscriber { + return resolveSubscriberWithHandler(keyExpr, handler, SubscriberConfig()) } /** @@ -140,8 +141,28 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO */ @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, config: SubscriberCallbackConfig): Subscriber { - return resolveSubscriberWithCallback(keyExpr, config) + fun declareSubscriber(keyExpr: KeyExpr, handler: Handler, config: SubscriberConfig): Subscriber { + return resolveSubscriberWithHandler(keyExpr, handler, config) + } + + /** + * Declare a [Subscriber] on the session. + * + * TODO + */ + @Throws(ZError::class) + fun declareSubscriber(keyExpr: KeyExpr, callback: Callback): Subscriber { + return resolveSubscriberWithCallback(keyExpr, callback, SubscriberConfig()) + } + + /** + * Declare a [Subscriber] on the session. + * + * TODO + */ + @Throws(ZError::class) + fun declareSubscriber(keyExpr: KeyExpr, callback: Callback, config: SubscriberConfig): Subscriber { + return resolveSubscriberWithCallback(keyExpr, callback, config) } /** @@ -324,10 +345,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriberWithHandler( - keyExpr: KeyExpr, config: SubscriberHandlerConfig + keyExpr: KeyExpr, handler: Handler, config: SubscriberConfig ): Subscriber { return jniSession?.run { - val subscriber = declareSubscriberWithHandler(keyExpr, config) + val subscriber = declareSubscriberWithHandler(keyExpr, handler, config) declarations.add(subscriber) subscriber } ?: throw (sessionClosedException) @@ -335,10 +356,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriberWithCallback( - keyExpr: KeyExpr, config: SubscriberCallbackConfig + keyExpr: KeyExpr, callback: Callback, config: SubscriberConfig ): Subscriber { return jniSession?.run { - val subscriber = declareSubscriberWithCallback(keyExpr, config) + val subscriber = declareSubscriberWithCallback(keyExpr, callback, config) declarations.add(subscriber) subscriber } ?: throw (sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index ffa592e3..401ebbca 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -81,7 +81,7 @@ internal class JNISession { @Throws(ZError::class) fun declareSubscriberWithHandler( - keyExpr: KeyExpr, config: SubscriberHandlerConfig + keyExpr: KeyExpr, handler: Handler, config: SubscriberConfig ): Subscriber { val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> @@ -95,20 +95,20 @@ internal class JNISession { QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), attachmentBytes?.into() ) - config.handler?.handle(sample) + handler.handle(sample) } val subscriberRawPtr = declareSubscriberViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, fun() { - config.handler?.onClose() + handler.onClose() config.onClose?.run() } ) - return Subscriber(keyExpr, config.handler?.receiver(), JNISubscriber(subscriberRawPtr)) + return Subscriber(keyExpr, handler.receiver(), JNISubscriber(subscriberRawPtr)) } @Throws(ZError::class) fun declareSubscriberWithCallback( - keyExpr: KeyExpr, config: SubscriberCallbackConfig + keyExpr: KeyExpr, callback: Callback, config: SubscriberConfig ): Subscriber { val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> @@ -122,7 +122,7 @@ internal class JNISession { QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), attachmentBytes?.into() ) - config.callback.run(sample) + callback.run(sample) } val subscriberRawPtr = declareSubscriberViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index 555a0bef..529369d2 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -14,15 +14,10 @@ package io.zenoh.pubsub -import io.zenoh.* -import io.zenoh.handlers.Callback import io.zenoh.handlers.BlockingQueueHandler -import io.zenoh.handlers.Handler import io.zenoh.jni.JNISubscriber import io.zenoh.keyexpr.KeyExpr -import io.zenoh.sample.Sample import io.zenoh.session.SessionDeclaration -import java.util.* /** * A subscriber that allows listening to updates on a key expression and reacting to changes. @@ -55,18 +50,7 @@ class Subscriber internal constructor( } } -data class SubscriberCallbackConfig( - var callback: Callback -) { - var onClose: Runnable? = null - - fun onClose(onClose: Runnable) = apply { this.onClose = onClose } -} - -data class SubscriberHandlerConfig( - var handler: Handler? = null, -) { - var onClose: Runnable? = null +data class SubscriberConfig(var onClose: Runnable? = null) { fun onClose(onClose: Runnable) = apply { this.onClose = onClose } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java index 3645e840..6d48cf92 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -17,7 +17,6 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.Sample; import org.junit.Test; import org.junit.runner.RunWith; @@ -133,7 +132,7 @@ private void runSessionTest(Config clientConfig, Config serverConfig) throws ZEr final Sample[] receivedSample = new Sample[1]; Subscriber subscriber = - sessionClient.declareSubscriber(TEST_KEY_EXP, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + sessionClient.declareSubscriber(TEST_KEY_EXP, sample -> receivedSample[0] = sample); ZBytes payload = ZBytes.from("example message"); sessionClient.put(TEST_KEY_EXP, payload); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java index 40b6d485..285b14e7 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java @@ -17,7 +17,6 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.SampleKind; import io.zenoh.sample.Sample; import org.junit.Test; @@ -36,7 +35,7 @@ public void deleteIsProperlyReceivedBySubscriberTest() throws ZError, Interrupte final Sample[] receivedSample = new Sample[1]; KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); session.delete(keyExpr); Thread.sleep(1000); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index db53fbb6..5928b89e 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -20,7 +20,6 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.query.*; import io.zenoh.sample.Sample; import org.junit.Test; @@ -45,7 +44,7 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { Sample[] receivedSample = new Sample[1]; Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); session.put(keyExpr, payload, new PutConfig().encoding(with_schema)); Thread.sleep(200); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 592a3271..224b62c8 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -5,7 +5,6 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; import io.zenoh.pubsub.PublisherConfig; -import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.qos.QoS; import io.zenoh.qos.Reliability; import io.zenoh.sample.SampleKind; @@ -43,7 +42,7 @@ public void setUp() throws ZError { receivedSamples = new ArrayList<>(); - subscriber = session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(receivedSamples::add)); + subscriber = session.declareSubscriber(keyExpr, receivedSamples::add); } @After diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java index b8908e5c..624b4e38 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -20,7 +20,6 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.sample.Sample; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +41,7 @@ public void putTest() throws ZError { var keyExpr = KeyExpr.tryFrom(TEST_KEY_EXP); Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); session.put(keyExpr, TEST_PAYLOAD, new PutConfig().encoding(Encoding.TEXT_PLAIN)); subscriber.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java index 7b898bc4..94ee94b3 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java @@ -20,8 +20,6 @@ import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.PutConfig; -import io.zenoh.pubsub.SubscriberCallbackConfig; -import io.zenoh.pubsub.SubscriberHandlerConfig; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; import io.zenoh.sample.Sample; @@ -73,7 +71,7 @@ public void subscriber_runsWithCallback() throws ZError { var receivedSamples = new ArrayList(); var subscriber = - session.declareSubscriber(testKeyExpr, new SubscriberCallbackConfig(receivedSamples::add)); + session.declareSubscriber(testKeyExpr, receivedSamples::add); TEST_VALUES.forEach(value -> { try { @@ -105,7 +103,7 @@ public void subscriber_runsWithCallback() throws ZError { public void subscriber_runsWithHandler() throws ZError { var handler = new QueueHandler(); var subscriber = - session.declareSubscriber(testKeyExpr, new SubscriberHandlerConfig<>(handler)); + session.declareSubscriber(testKeyExpr, handler); TEST_VALUES.forEach(value -> { try { diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index cbe2af21..d2bddaea 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -19,7 +19,6 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberCallbackConfig; import io.zenoh.query.GetConfig; import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; @@ -65,7 +64,7 @@ public void tearDown() { public void putWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); session.put(keyExpr, payload, new PutConfig().attachment(attachment)); @@ -81,7 +80,7 @@ public void publisherPutWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); publisher.put(payload).attachment(attachment).res(); @@ -98,7 +97,7 @@ public void publisherPutWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); publisher.put(payload).res(); @@ -114,7 +113,7 @@ public void publisherDeleteWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); publisher.delete().attachment(attachment).res(); @@ -131,7 +130,7 @@ public void publisherDeleteWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); Subscriber subscriber = - session.declareSubscriber(keyExpr, new SubscriberCallbackConfig(sample -> receivedSample[0] = sample)); + session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); publisher.delete().res(); From 9962353c0e17b09911ca7f2a29d4b121d40f8324 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 27 Nov 2024 10:38:50 -0300 Subject: [PATCH 55/83] Fix config test --- zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java index 6d48cf92..2fe40bac 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -34,7 +34,7 @@ public class ConfigTest { private static final String json5ClientConfigString = "{\n" + " mode: \"peer\",\n" + - " listen: {\n" + + " connect: {\n" + " endpoints: [\"tcp/localhost:7450\"]\n" + " },\n" + " scouting: {\n" + From 6e6c86de2ccd1de03b8623bfa187f6be55dd0a36 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 27 Nov 2024 13:55:41 -0300 Subject: [PATCH 56/83] Alignment - Scouting config params --- .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 55 ++++++++++++++- .../kotlin/io/zenoh/jni/JNIScout.kt | 16 ++++- .../kotlin/io/zenoh/scouting/Scout.kt | 2 +- .../kotlin/io/zenoh/scouting/ScoutBuilder.kt | 67 ------------------- .../kotlin/io/zenoh/scouting/ScoutConfig.kt | 28 ++++++++ .../src/jvmTest/java/io/zenoh/ScoutTest.java | 10 +-- 6 files changed, 102 insertions(+), 76 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index 59df9555..1ace2b50 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -19,7 +19,10 @@ import io.zenoh.scouting.Hello import io.zenoh.scouting.Scout import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler -import io.zenoh.scouting.ScoutBuilder +import io.zenoh.handlers.Callback +import io.zenoh.handlers.Handler +import io.zenoh.jni.JNIScout +import io.zenoh.scouting.ScoutConfig import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque @@ -45,8 +48,54 @@ object Zenoh { * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. */ @JvmStatic - fun scoutBuilder(): ScoutBuilder>> { - return ScoutBuilder(handler = BlockingQueueHandler(queue = LinkedBlockingDeque())) + fun scout(): Scout>> { + val scoutConfig = ScoutConfig() + val handler = BlockingQueueHandler(LinkedBlockingDeque>()) + return JNIScout.scoutWithHandler( + scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutConfig.config + ) + } + + @JvmStatic + fun scout(scoutConfig: ScoutConfig): Scout>> { + val handler = BlockingQueueHandler(LinkedBlockingDeque>()) + return JNIScout.scoutWithHandler( + scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutConfig.config + ) + } + + @JvmStatic + fun scout(handler: Handler): Scout { + val scoutConfig = ScoutConfig() + return JNIScout.scoutWithHandler( + scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutConfig.config + ) + } + + @JvmStatic + fun scout(handler: Handler, scoutConfig: ScoutConfig): Scout { + return JNIScout.scoutWithHandler( + scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutConfig.config + ) + } + + @JvmStatic + fun scout(callback: Callback): Scout { + val scoutConfig = ScoutConfig() + return JNIScout.scoutWithCallback( + scoutConfig.whatAmI, callback, config = scoutConfig.config + ) + } + + @JvmStatic + fun scout(callback: Callback, scoutConfig: ScoutConfig): Scout { + return JNIScout.scoutWithCallback( + scoutConfig.whatAmI, callback, config = scoutConfig.config + ) } /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt index 1db97215..c326e3f2 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt @@ -39,7 +39,7 @@ internal class JNIScout(private val ptr: Long) { } @Throws(ZError::class) - fun scout( + fun scoutWithHandler( whatAmI: Set, callback: Callback, onClose: () -> Unit, @@ -54,6 +54,20 @@ internal class JNIScout(private val ptr: Long) { return Scout(receiver, JNIScout(ptr)) } + @Throws(ZError::class) + fun scoutWithCallback( + whatAmI: Set, + callback: Callback, + config: Config?, + ): Scout { + val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List -> + callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) + } + val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } + val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, fun() {},config?.jniConfig?.ptr ?: 0) + return Scout(null, JNIScout(ptr)) + } + @Throws(ZError::class) private external fun scoutViaJNI( whatAmI: Int, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt index 7c9f98b2..7e1de8c3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt @@ -33,7 +33,7 @@ import io.zenoh.jni.JNIScout * @param receiver Receiver to handle incoming hello messages. */ class Scout internal constructor( - val receiver: R, + val receiver: R?, private var jniScout: JNIScout? ) : AutoCloseable { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt deleted file mode 100644 index 786161f5..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutBuilder.kt +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.scouting - -import io.zenoh.Config -import io.zenoh.Resolvable -import io.zenoh.config.WhatAmI -import io.zenoh.handlers.BlockingQueueHandler -import io.zenoh.handlers.Callback -import io.zenoh.handlers.Handler -import io.zenoh.jni.JNIScout -import java.util.* -import java.util.concurrent.BlockingQueue - -class ScoutBuilder internal constructor( - private var callback: Callback? = null, - private var handler: Handler? = null, - private var config: Config? = null, - private var whatAmI: Set = setOf(WhatAmI.Peer, WhatAmI.Router) -): Resolvable> { - - /** - * Specify a [Callback] to be run when receiving a [Hello] message. Overrides any previously specified callback or handler. - */ - fun callback(callback: Callback): ScoutBuilder = - ScoutBuilder(callback = callback, handler = null, config = config, whatAmI = whatAmI) - - fun whatAmI(whatAmI: Set): ScoutBuilder { - return ScoutBuilder(callback, handler, config, whatAmI) - } - - /** - * Specify a [Handler]. Overrides any previously specified callback or handler. - */ - fun with(handler: Handler): ScoutBuilder = - ScoutBuilder(callback = null, handler = handler, config = config, whatAmI = whatAmI) - - /** Specify a [BlockingQueue]. Overrides any previously specified callback or handler. */ - fun with(blockingQueue: BlockingQueue>): ScoutBuilder>> = - ScoutBuilder(callback = null, handler = BlockingQueueHandler(blockingQueue), config = config, whatAmI = whatAmI) - - /** - * Resolve the builder, creating a [Scout] with the provided parameters. - * - * @return The newly created [Scout]. - */ - override fun res(): Scout { - require(callback != null || handler != null) { "Either a callback or a handler must be provided." } - val resolvedCallback = callback ?: Callback { t: Hello -> handler?.handle(t) } - @Suppress("UNCHECKED_CAST") - return JNIScout.scout(whatAmI = whatAmI, callback = resolvedCallback, onClose = fun() { - handler?.onClose() - }, receiver = handler?.receiver() ?: Unit as R, config = config) - } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt new file mode 100644 index 00000000..8f3ce23e --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt @@ -0,0 +1,28 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.scouting + +import io.zenoh.Config +import io.zenoh.config.WhatAmI + +data class ScoutConfig( + var config: Config? = null, + var whatAmI: Set = setOf(WhatAmI.Peer, WhatAmI.Router) +) { + + fun config(config: Config) = apply { this.config = config } + + fun whatAmI(whatAmI: Set) = apply { this.whatAmI = whatAmI } +} diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java index f01a4c48..93887d0d 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java @@ -18,6 +18,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.scouting.Hello; import io.zenoh.scouting.Scout; +import io.zenoh.scouting.ScoutConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -39,7 +40,7 @@ public void scouting_queueTest() throws ZError, InterruptedException { Thread.sleep(1000); - Scout>> scout = Zenoh.scoutBuilder().res(); + Scout>> scout = Zenoh.scout(); Thread.sleep(1000); scout.close(); @@ -52,6 +53,7 @@ public void scouting_queueTest() throws ZError, InterruptedException { assertTrue(helloList.get(i).isPresent()); } assertTrue(helloList.get(helloList.size() - 1).isEmpty()); + session.close(); } @Test @@ -59,7 +61,7 @@ public void scouting_callbackTest() throws ZError, InterruptedException { Session session = Zenoh.open(Config.loadDefault()); Hello[] hello = new Hello[1]; - Zenoh.scoutBuilder().callback(hello1 -> hello[0] = hello1).res(); + Zenoh.scout(hello1 -> hello[0] = hello1); Thread.sleep(1000); @@ -69,13 +71,13 @@ public void scouting_callbackTest() throws ZError, InterruptedException { @Test public void scouting_whatAmITest() { - var scout = Zenoh.scoutBuilder().whatAmI(Set.of(WhatAmI.Client, WhatAmI.Peer)).res(); + var scout = Zenoh.scout(new ScoutConfig().whatAmI(Set.of(WhatAmI.Client, WhatAmI.Peer))); scout.close(); } @Test public void scouting_onCloseTest() { - Scout>> scout = Zenoh.scoutBuilder().res(); + Scout>> scout = Zenoh.scout(); var receiver = scout.getReceiver(); scout.close(); From 95f86aad18ae4e214127c1f16ae622f36875d564 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 28 Nov 2024 12:11:44 -0300 Subject: [PATCH 57/83] Alignment: adding Liveliness --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 12 +- .../kotlin/io/zenoh/jni/JNILiveliness.kt | 153 +++++++++++ .../kotlin/io/zenoh/jni/JNILivelinessToken.kt | 12 + .../kotlin/io/zenoh/jni/JNISession.kt | 2 +- .../kotlin/io/zenoh/liveliness/Liveliness.kt | 183 +++++++++++++ .../io/zenoh/liveliness/LivelinessToken.kt | 55 ++++ .../jvmTest/java/io/zenoh/LivelinessTest.java | 70 +++++ zenoh-jni/src/lib.rs | 1 + zenoh-jni/src/liveliness.rs | 242 ++++++++++++++++++ zenoh-jni/src/session.rs | 4 +- 10 files changed, 729 insertions(+), 5 deletions(-) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt create mode 100644 zenoh-java/src/jvmTest/java/io/zenoh/LivelinessTest.java create mode 100644 zenoh-jni/src/liveliness.rs diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index ba7ad222..5df70feb 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -22,6 +22,7 @@ import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler import io.zenoh.jni.JNISession import io.zenoh.keyexpr.KeyExpr +import io.zenoh.liveliness.Liveliness import io.zenoh.pubsub.* import io.zenoh.query.* import io.zenoh.query.Query @@ -50,13 +51,13 @@ import java.util.concurrent.LinkedBlockingDeque */ class Session private constructor(private val config: Config) : AutoCloseable { - private var jniSession: JNISession? = JNISession() + internal var jniSession: JNISession? = JNISession() private var declarations = mutableListOf() companion object { - private val sessionClosedException = ZError("Session is closed.") + internal val sessionClosedException = ZError("Session is closed.") /** * Open a [Session] with the provided [Config]. @@ -334,6 +335,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { return SessionInfo(this) } + /** + * Obtain a [Liveliness] instance tied to this Zenoh session. + */ + fun liveliness(): Liveliness { + return Liveliness(this) + } + @Throws(ZError::class) internal fun resolvePublisher(keyExpr: KeyExpr, config: PublisherConfig): Publisher { return jniSession?.run { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt new file mode 100644 index 00000000..47d522e5 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt @@ -0,0 +1,153 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.jni + +import io.zenoh.bytes.Encoding +import io.zenoh.bytes.into +import io.zenoh.config.ZenohId +import io.zenoh.exceptions.ZError +import io.zenoh.handlers.Callback +import io.zenoh.jni.callbacks.JNIGetCallback +import io.zenoh.jni.callbacks.JNIOnCloseCallback +import io.zenoh.jni.callbacks.JNISubscriberCallback +import io.zenoh.keyexpr.KeyExpr +import io.zenoh.liveliness.LivelinessToken +import io.zenoh.pubsub.Subscriber +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS +import io.zenoh.query.Reply +import io.zenoh.sample.Sample +import io.zenoh.sample.SampleKind +import org.apache.commons.net.ntp.TimeStamp +import java.time.Duration + +internal object JNILiveliness { + + @Throws(ZError::class) + fun get( + jniSession: JNISession, + keyExpr: KeyExpr, + callback: Callback, + receiver: R, + timeout: Duration, + onClose: Runnable + ): R { + val getCallback = JNIGetCallback { + replierId: ByteArray?, + success: Boolean, + keyExpr2: String?, + payload: ByteArray, + encodingId: Int, + encodingSchema: String?, + kind: Int, + timestampNTP64: Long, + timestampIsValid: Boolean, + attachmentBytes: ByteArray?, + express: Boolean, + priority: Int, + congestionControl: Int, + -> + val reply: Reply + if (success) { + val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null + val sample = Sample( + KeyExpr(keyExpr2!!, null), + payload.into(), + Encoding(encodingId, schema = encodingSchema), + SampleKind.fromInt(kind), + timestamp, + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() + ) + reply = Reply.Success(replierId?.let { ZenohId(it) }, sample) + } else { + reply = Reply.Error( + replierId?.let { ZenohId(it) }, + payload.into(), + Encoding(encodingId, schema = encodingSchema) + ) + } + callback.run(reply) + } + getViaJNI( + jniSession.sessionPtr.get(), + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + getCallback, + timeout.toMillis(), + onClose::run + ) + return receiver + } + + fun declareToken(jniSession: JNISession, keyExpr: KeyExpr): LivelinessToken { + val ptr = declareTokenViaJNI(jniSession.sessionPtr.get(), keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr) + return LivelinessToken(JNILivelinessToken(ptr)) + } + + fun declareSubscriber( + jniSession: JNISession, + keyExpr: KeyExpr, + callback: Callback, + receiver: R?, + history: Boolean, + onClose: () -> Unit + ): Subscriber { + val subCallback = + JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> + val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null + val sample = Sample( + KeyExpr(keyExpr2, null), + payload.into(), + Encoding(encodingId, schema = encodingSchema), + SampleKind.fromInt(kind), + timestamp, + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() + ) + callback.run(sample) + } + val ptr = declareSubscriberViaJNI( + jniSession.sessionPtr.get(), + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + subCallback, + history, + onClose + ) + return Subscriber(keyExpr, receiver, JNISubscriber(ptr)) + } + + private external fun getViaJNI( + sessionPtr: Long, + keyExprPtr: Long, + keyExprString: String, + callback: JNIGetCallback, + timeoutMs: Long, + onClose: JNIOnCloseCallback + ) + + private external fun declareTokenViaJNI(sessionPtr: Long, keyExprPtr: Long, keyExprString: String): Long + + private external fun declareSubscriberViaJNI( + sessionPtr: Long, + keyExprPtr: Long, + keyExprString: String, + callback: JNISubscriberCallback, + history: Boolean, + onClose: JNIOnCloseCallback + ): Long +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt new file mode 100644 index 00000000..991c860a --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt @@ -0,0 +1,12 @@ +package io.zenoh.jni + +internal class JNILivelinessToken(val ptr: Long) { + + fun undeclare() { + undeclareViaJNI(this.ptr) + } + + companion object { + external fun undeclareViaJNI(ptr: Long) + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 401ebbca..2807f778 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -48,7 +48,7 @@ internal class JNISession { } /* Pointer to the underlying Rust zenoh session. */ - private var sessionPtr: AtomicLong = AtomicLong(0) + internal var sessionPtr: AtomicLong = AtomicLong(0) @Throws(ZError::class) fun open(config: Config) { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt new file mode 100644 index 00000000..d72669bb --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt @@ -0,0 +1,183 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.liveliness + +import io.zenoh.Session +import io.zenoh.handlers.BlockingQueueHandler +import io.zenoh.handlers.Callback +import io.zenoh.handlers.Handler +import io.zenoh.jni.JNILiveliness +import io.zenoh.keyexpr.KeyExpr +import io.zenoh.pubsub.Subscriber +import io.zenoh.query.Reply +import io.zenoh.sample.Sample +import java.time.Duration +import java.util.* +import java.util.concurrent.BlockingQueue +import java.util.concurrent.LinkedBlockingDeque + +/** + * A structure with functions to declare a [LivelinessToken], + * query existing [LivelinessToken]s and subscribe to liveliness changes. + * + * A [LivelinessToken] is a token which liveliness is tied + * to the Zenoh [Session] and can be monitored by remote applications. + * + * The [Liveliness] instance can be obtained with the [Session.liveliness] function + * of the [Session] instance. + */ +class Liveliness internal constructor(private val session: Session) { + + /** + * Create a LivelinessToken for the given key expression. + */ + fun declareToken(keyExpr: KeyExpr): LivelinessToken { + val jniSession = session.jniSession ?: throw Session.sessionClosedException + return JNILiveliness.declareToken(jniSession, keyExpr) + } + + /** + * Query the liveliness tokens with matching key expressions. + * + * @param keyExpr The [KeyExpr] for the query. + * @param timeout Optional timeout of the query, defaults to 10 secs. + */ + @JvmOverloads + fun get( + keyExpr: KeyExpr, + timeout: Duration = Duration.ofMillis(10000), + ): BlockingQueue> { + val jniSession = session.jniSession ?: throw Session.sessionClosedException + val handler = BlockingQueueHandler(LinkedBlockingDeque()) + return JNILiveliness.get(jniSession, + keyExpr, + handler::handle, + receiver = handler.receiver(), + timeout, + onClose = handler::onClose + ) + } + + /** + * Query the liveliness tokens with matching key expressions. + * + * @param keyExpr The [KeyExpr] for the query. + * @param callback [Callback] to handle the incoming replies. + * @param timeout Optional timeout of the query, defaults to 10 secs. + */ + @JvmOverloads + fun get( + keyExpr: KeyExpr, callback: Callback, timeout: Duration = Duration.ofMillis(10000) + ) { + val jniSession = session.jniSession ?: throw Session.sessionClosedException + return JNILiveliness.get(jniSession, keyExpr, callback, Unit, timeout, {}) + } + + /** + * Query the liveliness tokens with matching key expressions. + * + * @param R The [Handler.receiver] type. + * @param keyExpr The [KeyExpr] for the query. + * @param handler [Handler] to deal with the incoming replies. + * @param timeout Optional timeout of the query, defaults to 10 secs. + */ + @JvmOverloads + fun get( + keyExpr: KeyExpr, handler: Handler, timeout: Duration = Duration.ofMillis(10000) + ): R { + val jniSession = session.jniSession ?: throw Session.sessionClosedException + val callback = handler::handle + return JNILiveliness.get( + jniSession, + keyExpr, + callback, + handler.receiver(), + timeout, + onClose = handler::onClose + ) + } + + /** + * Create a [Subscriber] for liveliness changes matching the given key expression. + * + * @param keyExpr The [KeyExpr] the subscriber will be listening to. + * @param callback The [Callback] to be run when a liveliness change is received. + */ + @JvmOverloads + fun declareSubscriber( + keyExpr: KeyExpr, + callback: Callback, + config: SubscriberConfig = SubscriberConfig() + ): Subscriber { + val jniSession = session.jniSession ?: throw Session.sessionClosedException + return JNILiveliness.declareSubscriber( + jniSession, + keyExpr, + callback, + null, + config.history, + fun() { config.onClose?.run() }) + } + + /** + * Create a [Subscriber] for liveliness changes matching the given key expression. + * + * @param R The [Handler.receiver] type. + * @param keyExpr The [KeyExpr] the subscriber will be listening to. + * @param handler [Handler] to handle liveliness changes events. + */ + @JvmOverloads + fun declareSubscriber( + keyExpr: KeyExpr, + handler: Handler, + config: SubscriberConfig = SubscriberConfig() + ): Subscriber { + val jniSession = session.jniSession ?: throw Session.sessionClosedException + return JNILiveliness.declareSubscriber( + jniSession, + keyExpr, + handler::handle, + handler.receiver(), + config.history, + fun() { + handler.onClose() + config.onClose?.run() + }) + } + + @JvmOverloads + fun declareSubscriber( + keyExpr: KeyExpr, + config: SubscriberConfig = SubscriberConfig() + ): Subscriber>> { + val handler = BlockingQueueHandler(LinkedBlockingDeque()) + val jniSession = session.jniSession ?: throw Session.sessionClosedException + return JNILiveliness.declareSubscriber( + jniSession, + keyExpr, + handler::handle, + handler.receiver(), + config.history, + fun() { + handler.onClose() + config.onClose?.run() + }) + } + + data class SubscriberConfig(var history: Boolean = false, var onClose: Runnable? = null) { + fun history(history: Boolean) = apply { this.history = history } + fun onClose(onClose: Runnable) = apply { this.onClose = onClose } + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt new file mode 100644 index 00000000..386b84e0 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt @@ -0,0 +1,55 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.liveliness + +import io.zenoh.jni.JNILivelinessToken +import io.zenoh.session.SessionDeclaration + +/** + * A token whose liveliness is tied to the Zenoh [Session]. + * + * A declared liveliness token will be seen as alive by any other Zenoh + * application in the system that monitors it while the liveliness token + * is not undeclared or dropped, while the Zenoh application that declared + * it is alive (didn't stop or crashed) and while the Zenoh application + * that declared the token has Zenoh connectivity with the Zenoh application + * that monitors it. + * + * Liveliness tokens are automatically undeclared when dropped. + * + * TODO: provide example + */ +class LivelinessToken internal constructor(private var jniLivelinessToken: JNILivelinessToken?): SessionDeclaration, AutoCloseable { + + /** + * Undeclares the token. + */ + override fun undeclare() { + jniLivelinessToken?.undeclare() + jniLivelinessToken = null + } + + /** + * Closes the token. This function is equivalent to [undeclare]. + * When using try-with-resources, this function is called automatically. + */ + override fun close() { + undeclare() + } + + protected fun finalize() { + undeclare() + } +} diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/LivelinessTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/LivelinessTest.java new file mode 100644 index 00000000..a43741c6 --- /dev/null +++ b/zenoh-java/src/jvmTest/java/io/zenoh/LivelinessTest.java @@ -0,0 +1,70 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.liveliness.LivelinessToken; +import io.zenoh.query.Reply; +import io.zenoh.sample.Sample; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.junit.Assert.assertNotNull; + +@RunWith(JUnit4.class) +public class LivelinessTest { + + @Test + public void getLivelinessTest() throws ZError, InterruptedException { + Session sessionA = Zenoh.open(Config.loadDefault()); + Session sessionB = Zenoh.open(Config.loadDefault()); + + var keyExpr = KeyExpr.tryFrom("test/liveliness"); + LivelinessToken token = sessionA.liveliness().declareToken(keyExpr); + + Reply[] receivedReply = new Reply[1]; + sessionB.liveliness().get(KeyExpr.tryFrom("test/**"), reply -> receivedReply[0] = reply); + + Thread.sleep(1000); + + assertNotNull(receivedReply[0]); + token.close(); + sessionA.close(); + sessionB.close(); + } + + @Test + public void livelinessSubscriberTest() throws ZError, InterruptedException { + Session sessionA = Zenoh.open(Config.loadDefault()); + Session sessionB = Zenoh.open(Config.loadDefault()); + + Sample[] receivedSample = new Sample[1]; + + var subscriber = sessionA.liveliness().declareSubscriber(KeyExpr.tryFrom("test/**"), sample -> receivedSample[0] = sample); + + var token = sessionB.liveliness().declareToken(KeyExpr.tryFrom("test/liveliness")); + + Thread.sleep(1000); + + assertNotNull(receivedSample[0]); + + token.close(); + subscriber.close(); + sessionA.close(); + sessionB.close(); + } +} diff --git a/zenoh-jni/src/lib.rs b/zenoh-jni/src/lib.rs index 51b710b9..bf012f13 100644 --- a/zenoh-jni/src/lib.rs +++ b/zenoh-jni/src/lib.rs @@ -15,6 +15,7 @@ mod config; mod errors; mod key_expr; +mod liveliness; mod logger; mod publisher; mod query; diff --git a/zenoh-jni/src/liveliness.rs b/zenoh-jni/src/liveliness.rs new file mode 100644 index 00000000..8b05c925 --- /dev/null +++ b/zenoh-jni/src/liveliness.rs @@ -0,0 +1,242 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{ptr::null, sync::Arc, time::Duration}; + +use jni::{ + objects::{JByteArray, JClass, JObject, JString, JValue}, + sys::{jboolean, jint, jlong}, + JNIEnv, +}; + +use zenoh::{ + internal::runtime::ZRuntime, key_expr::KeyExpr, liveliness::LivelinessToken, + pubsub::Subscriber, sample::Sample, Session, Wait, +}; + +use crate::{ + errors::ZResult, + key_expr::process_kotlin_key_expr, + session::{on_reply_error, on_reply_success}, + throw_exception, + utils::{ + bytes_to_java_array, get_callback_global_ref, get_java_vm, load_on_close, + slice_to_java_string, + }, + zerror, +}; + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNILiveliness_getViaJNI( + mut env: JNIEnv, + _class: JClass, + session_ptr: *const Session, + key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, + key_expr_str: JString, + callback: JObject, + timeout_ms: jlong, + on_close: JObject, +) { + let session = unsafe { Arc::from_raw(session_ptr) }; + let _ = || -> ZResult<()> { + let key_expr = unsafe { process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr) }?; + let java_vm = Arc::new(get_java_vm(&mut env)?); + let callback_global_ref = get_callback_global_ref(&mut env, callback)?; + let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; + let on_close = load_on_close(&java_vm, on_close_global_ref); + let timeout = Duration::from_millis(timeout_ms as u64); + let replies = session + .liveliness() + .get(key_expr.to_owned()) + .timeout(timeout) + .wait() + .map_err(|err| zerror!(err))?; + + ZRuntime::Application.spawn(async move { + on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure + while let Ok(reply) = replies.recv_async().await { + || -> ZResult<()> { + tracing::debug!("Receiving liveliness reply through JNI: {:?}", reply); + let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { + zerror!( + "Unable to attach thread for GET liveliness query callback: {}.", + err + ) + })?; + match reply.result() { + Ok(sample) => on_reply_success( + &mut env, + reply.replier_id(), + sample, + &callback_global_ref, + ), + Err(error) => on_reply_error( + &mut env, + reply.replier_id(), + error, + &callback_global_ref, + ), + } + }() + .unwrap_or_else(|err| tracing::error!("Error on get liveliness callback: {err}.")); + } + }); + Ok(()) + }() + .map_err(|err| { + throw_exception!(env, err); + }); + std::mem::forget(session); +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNILiveliness_declareTokenViaJNI( + mut env: JNIEnv, + _class: JClass, + session_ptr: *const Session, + key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, + key_expr_str: JString, +) -> *const LivelinessToken { + let session = unsafe { Arc::from_raw(session_ptr) }; + let ptr = || -> ZResult<*const LivelinessToken> { + let key_expr = unsafe { process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr) }?; + tracing::trace!("Declaring liveliness token on '{key_expr}'."); + let token = session + .liveliness() + .declare_token(key_expr) + .wait() + .map_err(|err| zerror!(err))?; + Ok(Arc::into_raw(Arc::new(token))) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + null() + }); + std::mem::forget(session); + ptr +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNILivelinessToken_00024Companion_undeclareViaJNI( + _env: JNIEnv, + _: JClass, + token_ptr: *const LivelinessToken, +) { + unsafe { Arc::from_raw(token_ptr) }; +} + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn Java_io_zenoh_jni_JNILiveliness_declareSubscriberViaJNI( + mut env: JNIEnv, + _class: JClass, + session_ptr: *const Session, + key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, + key_expr_str: JString, + callback: JObject, + history: jboolean, + on_close: JObject, +) -> *const Subscriber<()> { + let session = unsafe { Arc::from_raw(session_ptr) }; + || -> ZResult<*const Subscriber<()>> { + let java_vm = Arc::new(get_java_vm(&mut env)?); + let callback_global_ref = get_callback_global_ref(&mut env, callback)?; + let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; + let on_close = load_on_close(&java_vm, on_close_global_ref); + + let key_expr = unsafe { process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr) }?; + tracing::debug!("Declaring liveliness subscriber on '{}'...", key_expr); + + let result = session + .liveliness() + .declare_subscriber(key_expr.to_owned()) + .history(history != 0) + .callback(move |sample: Sample| { + let _ = || -> ZResult<()> { + on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure + let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { + zerror!("Unable to attach thread for liveliness subscriber: {}", err) + })?; + let byte_array = bytes_to_java_array(&env, sample.payload()) + .map(|array| env.auto_local(array))?; + + let encoding_id: jint = sample.encoding().id() as jint; + let encoding_schema = match sample.encoding().schema() { + Some(schema) => slice_to_java_string(&env, schema)?, + None => JString::default(), + }; + let kind = sample.kind() as jint; + let (timestamp, is_valid) = sample + .timestamp() + .map(|timestamp| (timestamp.get_time().as_u64(), true)) + .unwrap_or((0, false)); + + let attachment_bytes = sample + .attachment() + .map_or_else( + || Ok(JByteArray::default()), + |attachment| bytes_to_java_array(&env, attachment), + ) + .map(|array| env.auto_local(array)) + .map_err(|err| zerror!("Error processing attachment: {}", err))?; + + let key_expr_str = env.auto_local( + env.new_string(sample.key_expr().to_string()) + .map_err(|err| zerror!("Error processing sample key expr: {}", err))?, + ); + + let express = sample.express(); + let priority = sample.priority() as jint; + let cc = sample.congestion_control() as jint; + + env.call_method( + &callback_global_ref, + "run", + "(Ljava/lang/String;[BILjava/lang/String;IJZ[BZII)V", + &[ + JValue::from(&key_expr_str), + JValue::from(&byte_array), + JValue::from(encoding_id), + JValue::from(&encoding_schema), + JValue::from(kind), + JValue::from(timestamp as i64), + JValue::from(is_valid), + JValue::from(&attachment_bytes), + JValue::from(express), + JValue::from(priority), + JValue::from(cc), + ], + ) + .map_err(|err| zerror!(err))?; + Ok(()) + }() + .map_err(|err| tracing::error!("On liveliness subscriber callback error: {err}")); + }) + .wait(); + + let subscriber = + result.map_err(|err| zerror!("Unable to declare liveliness subscriber: {}", err))?; + + tracing::debug!("Subscriber declared on '{}'.", key_expr); + std::mem::forget(session); + Ok(Arc::into_raw(Arc::new(subscriber))) + }() + .unwrap_or_else(|err| { + throw_exception!(env, err); + null() + }) +} diff --git a/zenoh-jni/src/session.rs b/zenoh-jni/src/session.rs index 4521fe4b..43017c0d 100644 --- a/zenoh-jni/src/session.rs +++ b/zenoh-jni/src/session.rs @@ -888,7 +888,7 @@ pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getViaJNI( std::mem::forget(session); } -fn on_reply_success( +pub(crate) fn on_reply_success( env: &mut JNIEnv, replier_id: Option, sample: &Sample, @@ -974,7 +974,7 @@ fn on_reply_success( result } -fn on_reply_error( +pub(crate) fn on_reply_error( env: &mut JNIEnv, replier_id: Option, reply_error: &ReplyError, From 8c59360e78514f24b252f48d23425e6c3da4682e Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 28 Nov 2024 12:13:40 -0300 Subject: [PATCH 58/83] Gitignore update --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 86cb1e5f..53d109f6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ /examples/build/ /build/ /.gradle/ +*/build/ From 6b35c684739c3d2635a45e67672ea2710717765e Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 28 Nov 2024 12:50:53 -0300 Subject: [PATCH 59/83] Alignment: fix logging --- zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt | 3 ++- zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt index 540e004c..eba6681c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt @@ -23,7 +23,8 @@ internal class Logger { internal const val LOG_ENV: String = "RUST_LOG" - fun start(filter: String) = runCatching { + @Throws(ZError::class) + fun start(filter: String) { startLogsViaJNI(filter) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index 1ace2b50..9a105194 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -127,7 +127,7 @@ object Zenoh { * @see Logger */ @JvmStatic - fun initLogFromEnvOr(fallbackFilter: String): Result = runCatching { + fun initLogFromEnvOr(fallbackFilter: String) { ZenohLoad val logLevelProp = System.getenv(LOG_ENV) logLevelProp?.let { Logger.start(it) } ?: Logger.start(fallbackFilter) From b580619a9355eb3fe5502d1eb2b693edc790beca Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 29 Nov 2024 11:35:57 -0300 Subject: [PATCH 60/83] Alignment: publisher put and delete config param --- .../kotlin/io/zenoh/pubsub/Publisher.kt | 48 +++++++------------ .../jvmTest/java/io/zenoh/PublisherTest.java | 7 +-- .../jvmTest/java/io/zenoh/SessionTest.java | 2 +- .../java/io/zenoh/UserAttachmentTest.java | 9 ++-- 4 files changed, 26 insertions(+), 40 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 96efa230..615bc900 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -80,14 +80,22 @@ class Publisher internal constructor( fun priority() = qos.priority /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ - fun put(payload: IntoZBytes) = PutBuilder(jniPublisher, payload, encoding) + @JvmOverloads + @Throws(ZError::class) + fun put(payload: IntoZBytes, config: PutConfig = PutConfig()) { + jniPublisher?.put(payload, config.encoding, config.attachment) ?: throw publisherNotValid + } /** * Performs a DELETE operation on the specified [keyExpr] * * @return A [Resolvable] operation. */ - fun delete() = DeleteBuilder(jniPublisher) + @JvmOverloads + @Throws(ZError::class) + fun delete(config: DeleteConfig = DeleteConfig()) { + jniPublisher?.delete(config.attachment) ?: throw(publisherNotValid) + } /** * Returns `true` if the publisher is still running. @@ -109,36 +117,6 @@ class Publisher internal constructor( protected fun finalize() { jniPublisher?.close() } - - class PutBuilder internal constructor( - private var jniPublisher: JNIPublisher?, - val payload: IntoZBytes, - var encoding: Encoding? = null, - var attachment: IntoZBytes? = null - ) { - - fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } - - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } - - @Throws(ZError::class) - fun res() { - jniPublisher?.put(payload, encoding, attachment) ?: throw(publisherNotValid) - } - } - - class DeleteBuilder internal constructor( - private var jniPublisher: JNIPublisher?, - var attachment: IntoZBytes? = null - ) { - - fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment } - - @Throws(ZError::class) - fun res() { - jniPublisher?.delete(attachment) ?: throw(publisherNotValid) - } - } } /** @@ -153,4 +131,10 @@ data class PublisherConfig(var reliability: Reliability = Reliability.RELIABLE, fun encoding(encoding: Encoding) = apply { this.encoding = encoding } fun qos(qos: QoS) = apply { this.qos = qos } + + fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } + + fun express(express: Boolean) = apply { this.qos.express = express } + + fun priority(priority: Priority) = apply { this.qos.priority = priority } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 224b62c8..6353b1e3 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -5,6 +5,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.PutConfig; import io.zenoh.qos.QoS; import io.zenoh.qos.Reliability; import io.zenoh.sample.SampleKind; @@ -64,7 +65,7 @@ public void putTest() { testPayloads.forEach(value -> { try { - publisher.put(value.getFirst()).encoding(value.getSecond()).res(); + publisher.put(value.getFirst(), new PutConfig().encoding(value.getSecond())); } catch (ZError e) { throw new RuntimeException(e); } @@ -80,14 +81,14 @@ public void putTest() { @Test public void deleteTest() throws ZError { - publisher.delete().res(); + publisher.delete(); assertEquals(1, receivedSamples.size()); assertEquals(SampleKind.DELETE, receivedSamples.get(0).getKind()); } @Test public void shouldFallbackToPublisherEncodingWhenEncodingNotProvided() throws ZError { - publisher.put(ZBytes.from("Test")).res(); + publisher.put(ZBytes.from("Test")); assertEquals(1, receivedSamples.size()); assertEquals(Encoding.ZENOH_STRING, receivedSamples.get(0).getEncoding()); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java index 01ca1255..18e3b855 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SessionTest.java @@ -58,7 +58,7 @@ public void sessionClose_declarationsAreUndeclaredAfterClosingSessionTest() thro assertFalse(subscriber.isValid()); assertFalse(publisher.isValid()); - assertThrows(ZError.class, () -> publisher.put(ZBytes.from("Test")).res()); + assertThrows(ZError.class, () -> publisher.put(ZBytes.from("Test"))); } @Test diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index d2bddaea..d096a4f2 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -17,6 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.ZBytes; +import io.zenoh.pubsub.DeleteConfig; import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.query.GetConfig; @@ -82,7 +83,7 @@ public void publisherPutWithAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - publisher.put(payload).attachment(attachment).res(); + publisher.put(payload, new PutConfig().attachment(attachment)); publisher.close(); subscriber.close(); @@ -99,7 +100,7 @@ public void publisherPutWithoutAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - publisher.put(payload).res(); + publisher.put(payload); publisher.close(); subscriber.close(); @@ -115,7 +116,7 @@ public void publisherDeleteWithAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - publisher.delete().attachment(attachment).res(); + publisher.delete(new DeleteConfig().attachment(attachment)); publisher.close(); subscriber.close(); @@ -132,7 +133,7 @@ public void publisherDeleteWithoutAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - publisher.delete().res(); + publisher.delete(); publisher.close(); subscriber.close(); From 2cc4260db260e568c5324834a1544857898e809b Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 29 Nov 2024 11:39:28 -0300 Subject: [PATCH 61/83] Alignment: examples - adding picocli for CLI args --- examples/build.gradle.kts | 3 + examples/src/main/java/io/zenoh/Config.kt | 74 +++++++++ examples/src/main/java/io/zenoh/ZDelete.java | 81 ++++++++- examples/src/main/java/io/zenoh/ZGet.java | 134 +++++++++++++-- examples/src/main/java/io/zenoh/ZPub.java | 117 +++++++++++-- examples/src/main/java/io/zenoh/ZPubThr.java | 134 +++++++++++++-- examples/src/main/java/io/zenoh/ZPut.java | 105 +++++++++++- .../src/main/java/io/zenoh/ZQueryable.java | 110 +++++++++++-- examples/src/main/java/io/zenoh/ZSub.java | 108 ++++++++++-- examples/src/main/java/io/zenoh/ZSubThr.java | 155 ++++++++++++++---- 10 files changed, 899 insertions(+), 122 deletions(-) create mode 100644 examples/src/main/java/io/zenoh/Config.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 6afd9c21..bd705c32 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -14,6 +14,7 @@ plugins { kotlin("jvm") + kotlin("plugin.serialization") version "1.9.0" } kotlin { @@ -23,6 +24,8 @@ kotlin { dependencies { implementation(project(":zenoh-java")) implementation("commons-net:commons-net:3.9.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") + implementation("info.picocli:picocli:4.7.4") } tasks { diff --git a/examples/src/main/java/io/zenoh/Config.kt b/examples/src/main/java/io/zenoh/Config.kt new file mode 100644 index 00000000..c8102728 --- /dev/null +++ b/examples/src/main/java/io/zenoh/Config.kt @@ -0,0 +1,74 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlin.io.path.Path + +@Serializable +data class ConfigData( + @SerialName("connect") var connect: Connect? = null, + @SerialName("listen") var listen: Listen? = null, + @SerialName("mode") var mode: String? = null, + @SerialName("scouting") var scouting: Scouting? = null, +) + +@Serializable +data class Connect( + @SerialName("endpoints") var endpoints: List +) + +@Serializable +data class Listen( + @SerialName("endpoints") var endpoints: List +) + +@Serializable +data class Scouting( + @SerialName("multicast") var multicast: Multicast, +) + +@Serializable +data class Multicast( + @SerialName("enabled") var enabled: Boolean, +) + +internal fun loadConfig( + emptyArgs: Boolean, + configFile: String?, + connectEndpoints: List?, + listenEndpoints: List?, + noMulticastScouting: Boolean?, + mode: String? +): Config { + return if (emptyArgs) { + Config.loadDefault() + } else { + configFile?.let { + Config.fromFile(path = Path(it)) + } ?: run { + val connect = connectEndpoints?.let {Connect(it)} + val listen = listenEndpoints?.let {Listen(it)} + val scouting = noMulticastScouting?.let { Scouting(Multicast(!it)) } + val configData = ConfigData(connect, listen, mode, scouting) + val jsonConfig = Json.encodeToJsonElement(configData).toString() + println(jsonConfig) + Config.fromJson(jsonConfig) + } + } +} diff --git a/examples/src/main/java/io/zenoh/ZDelete.java b/examples/src/main/java/io/zenoh/ZDelete.java index 9a930a1f..13d0063e 100644 --- a/examples/src/main/java/io/zenoh/ZDelete.java +++ b/examples/src/main/java/io/zenoh/ZDelete.java @@ -16,15 +16,82 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; +import picocli.CommandLine; -public class ZDelete { - public static void main(String[] args) throws ZError { +import java.util.List; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZDelete", + mixinStandardHelpOptions = true, + description = "Zenoh Delete example" +) +public class ZDelete implements Callable { + + private final Boolean emptyArgs; + + ZDelete(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to delete [default: demo/example/zenoh-java-delete].", + defaultValue = "demo/example/zenoh-java-delete" + ) + private String key; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws ZError { + Zenoh.initLogFromEnvOr("error"); System.out.println("Opening session..."); - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { - System.out.println("Deleting resources matching '" + keyExpr + "'..."); - session.delete(keyExpr); - } + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Deleting resources matching '" + keyExpr + "'..."); + session.delete(keyExpr); } + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZDelete(args.length == 0)).execute(args); + System.exit(exitCode); } } diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index d666301b..c376d79a 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -15,35 +15,133 @@ package io.zenoh; import io.zenoh.exceptions.ZError; -import io.zenoh.query.Reply; import io.zenoh.query.Selector; +import io.zenoh.query.Reply; +import io.zenoh.sample.SampleKind; +import picocli.CommandLine; +import java.util.List; import java.util.Optional; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZGet", + mixinStandardHelpOptions = true, + description = "Zenoh Get example" +) +public class ZGet implements Callable { + + private final Boolean emptyArgs; + + ZGet(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-s", "--selector"}, + description = "The selection of resources to query [default: demo/example/**].", + defaultValue = "demo/example/**" + ) + private String selectorOpt; + + @CommandLine.Option( + names = {"-p", "--payload"}, + description = "An optional payload to put in the query." + ) + private String payload; + + @CommandLine.Option( + names = {"-t", "--target"}, + description = "The target queryables of the query. Default: BEST_MATCHING. " + + "[possible values: BEST_MATCHING, ALL, ALL_COMPLETE]" + ) + private String target; + + @CommandLine.Option( + names = {"-o", "--timeout"}, + description = "The query timeout in milliseconds [default: 10000].", + defaultValue = "10000" + ) + private long timeout; -public class ZGet { + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; - public static void main(String[] args) throws ZError, InterruptedException { + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-a", "--attach"}, + description = "The attachment to add to the get. The key-value pairs are &-separated, and = serves as the separator between key and value." + ) + private String attachment; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws ZError, InterruptedException { + Zenoh.initLogFromEnvOr("error"); System.out.println("Opening session..."); - try (Session session = Zenoh.open(Config.loadDefault())) { - try (Selector selector = Selector.tryFrom("demo/example/**")) { - System.out.println("Performing Get on '" + selector + "'..."); - BlockingQueue> receiver = session.get(selector); - while (true) { - Optional wrapper = receiver.take(); - if (wrapper.isEmpty()) { - break; - } - Reply reply = wrapper.get(); - if (reply instanceof Reply.Success) { - Reply.Success successReply = (Reply.Success) reply; + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + try (Session session = Zenoh.open(config)) { + Selector selector = Selector.tryFrom(this.selectorOpt); + System.out.println("Performing Get on '" + selector + "'..."); + BlockingQueue> receiver = session.get(selector); + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + Reply reply = wrapper.get(); + if (reply instanceof Reply.Success) { + Reply.Success successReply = (Reply.Success) reply; + if (successReply.getSample().getKind() == SampleKind.PUT) { System.out.println("Received ('" + successReply.getSample().getKeyExpr() + "': '" + successReply.getSample().getPayload() + "')"); - } else { - Reply.Error errorReply = (Reply.Error) reply; - System.out.println("Received (ERROR: '" + errorReply.getError() + "')"); + } else if (successReply.getSample().getKind() == SampleKind.DELETE) { + System.out.println("Received (DELETE '" + successReply.getSample().getKeyExpr() + "')"); } + } else { + Reply.Error errorReply = (Reply.Error) reply; + System.out.println("Received (ERROR: '" + errorReply.getError() + "')"); } } + } + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZGet(args.length == 0)).execute(args); + System.exit(exitCode); } } diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index 8bf7fc63..5cef5ee4 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -18,25 +18,114 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; +import io.zenoh.pubsub.PutConfig; +import picocli.CommandLine; + +import java.util.List; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZPub", + mixinStandardHelpOptions = true, + description = "Zenoh Pub example" +) +public class ZPub implements Callable { + + private final Boolean emptyArgs; + + ZPub(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to write to [default: demo/example/zenoh-java-pub].", + defaultValue = "demo/example/zenoh-java-pub" + ) + private String key; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"-v", "--value"}, + description = "The value to write. [default: 'Pub from Java!']", + defaultValue = "Pub from Java!" + ) + private String value; + + @CommandLine.Option( + names = {"-a", "--attach"}, + description = "The attachments to add to each put. The key-value pairs are &-separated, and = serves as the separator between key and value." + ) + private String attachment; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws ZError { + Zenoh.initLogFromEnvOr("error"); + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); -public class ZPub { - public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening session..."); - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-pub")) { - System.out.println("Declaring publisher on '" + keyExpr + "'..."); - try (Publisher publisher = session.declarePublisher(keyExpr)) { - System.out.println("Press CTRL-C to quit..."); - int idx = 0; - while (true) { - Thread.sleep(1000); - String payload = String.format("[%4s] Pub from Java!", idx); - System.out.println("Putting Data ('" + keyExpr + "': '"+payload+"')..."); - publisher.put(ZBytes.from(payload)).res(); - idx++; + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Declaring publisher on '" + keyExpr + "'..."); + try (Publisher publisher = session.declarePublisher(keyExpr)) { + System.out.println("Press CTRL-C to quit..."); + ZBytes attachmentBytes = attachment != null ? ZBytes.from(attachment) : null; + int idx = 0; + while (true) { + Thread.sleep(1000); + String payload = String.format("[%4d] %s", idx, value); + System.out.println("Putting Data ('" + keyExpr + "': '" + payload + "')..."); + if (attachmentBytes != null) { + publisher.put(ZBytes.from(payload), new PutConfig().attachment(attachmentBytes)); + } else { + publisher.put(ZBytes.from(payload)); } + idx++; } } + } catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + return 1; } } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZPub(args.length == 0)).execute(args); + System.exit(exitCode); + } } diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index d04bd448..0c417c08 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -15,28 +15,136 @@ package io.zenoh; import io.zenoh.bytes.ZBytes; -import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; +import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.qos.CongestionControl; +import io.zenoh.qos.Priority; +import picocli.CommandLine; -public class ZPubThr { +import java.util.List; +import java.util.concurrent.Callable; - public static void main(String[] args) throws ZError { - int size = 8; - byte[] data = new byte[size]; - for (int i = 0; i < size; i++) { +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZPubThr", + mixinStandardHelpOptions = true, + description = "Zenoh Throughput example" +) +public class ZPubThr implements Callable { + + private final Boolean emptyArgs; + + ZPubThr(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Parameters( + index = "0", + description = "Sets the size of the payload to publish [default: 8].", + defaultValue = "8" + ) + private int payloadSize; + + @CommandLine.Option( + names = {"-p", "--priority"}, + description = "Priority for sending data." + ) + private Integer priorityInput; + + @CommandLine.Option( + names = {"-n", "--number"}, + description = "Number of messages in each throughput measurement [default: 100000].", + defaultValue = "100000" + ) + private long number; + + @CommandLine.Option( + names = {"-t", "--print"}, + description = "Print the statistics.", + defaultValue = "true" + ) + private boolean statsPrint; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + byte[] data = new byte[payloadSize]; + for (int i = 0; i < payloadSize; i++) { data[i] = (byte) (i % 10); } - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Publisher publisher = session.declarePublisher(keyExpr)) { - System.out.println("Publisher declared on test/thr."); - System.out.println("Press CTRL-C to quit..."); - while (true) { - publisher.put(ZBytes.from(data)).res(); + ZBytes payload = ZBytes.from(data); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom("test/thr"); + var publisherConfig = new PublisherConfig() + .congestionControl(CongestionControl.BLOCK) + .priority(priorityInput != null ? Priority.getEntries().get(priorityInput) : Priority.DATA); + try (Publisher publisher = session.declarePublisher(keyExpr, publisherConfig)) { + System.out.println("Publisher declared on test/thr."); + long count = 0; + long start = System.currentTimeMillis(); + System.out.println("Press CTRL-C to quit..."); + + while (true) { + publisher.put(payload); + + if (statsPrint) { + if (count < number) { + count++; + } else { + long elapsedTime = System.currentTimeMillis() - start; + long throughput = (count * 1000) / elapsedTime; + System.out.println(throughput + " msgs/s"); + count = 0; + start = System.currentTimeMillis(); + } } } } } } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZPubThr(args.length == 0)).execute(args); + System.exit(exitCode); + } } diff --git a/examples/src/main/java/io/zenoh/ZPut.java b/examples/src/main/java/io/zenoh/ZPut.java index a49b97f6..6a2b9b53 100644 --- a/examples/src/main/java/io/zenoh/ZPut.java +++ b/examples/src/main/java/io/zenoh/ZPut.java @@ -18,18 +18,105 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.PutConfig; -import io.zenoh.qos.CongestionControl; -import io.zenoh.qos.Priority; +import picocli.CommandLine; + +import java.util.List; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZPut", + mixinStandardHelpOptions = true, + description = "Zenoh Put example" +) +public class ZPut implements Callable { + + private final Boolean emptyArgs; + + ZPut(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to write to [default: demo/example/zenoh-java-put].", + defaultValue = "demo/example/zenoh-java-put" + ) + private String key; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"-v", "--value"}, + description = "The value to write. [default: 'Put from Java!'].", + defaultValue = "Put from Java!" + ) + private String value; + + @CommandLine.Option( + names = {"-a", "--attach"}, + description = "The attachment to add to the put. The key-value pairs are &-separated, and = serves as the separator between key and value." + ) + private String attachment; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); -public class ZPut { - public static void main(String[] args) throws ZError { System.out.println("Opening session..."); - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-put")) { - String value = "Put from Java!"; - session.put(keyExpr, ZBytes.from(value), new PutConfig().congestionControl(CongestionControl.BLOCK).priority(Priority.REALTIME)); - System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); + if (attachment != null) { + session.put(keyExpr, ZBytes.from(value), new PutConfig().attachment(ZBytes.from(attachment))); + } else { + session.put(keyExpr, ZBytes.from(value)); } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; } + + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZPut(args.length == 0)).execute(args); + System.exit(exitCode); } } diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index 9c2cf312..e46dc478 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -21,28 +21,101 @@ import io.zenoh.query.Queryable; import io.zenoh.query.ReplyConfig; import org.apache.commons.net.ntp.TimeStamp; +import picocli.CommandLine; +import java.util.List; import java.util.Optional; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; -public class ZQueryable { - - public static void main(String[] args) throws ZError, InterruptedException { - String keyExprString = "demo/example/zenoh-java-queryable"; - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom(keyExprString)) { - System.out.println("Declaring Queryable on " + keyExprString + "..."); - try (Queryable>> queryable = session.declareQueryable(keyExpr)) { - BlockingQueue> receiver = queryable.getReceiver(); - assert receiver != null; - System.out.println("Press CTRL-C to quit..."); - handleRequests(receiver, keyExpr); - } +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZQueryable", + mixinStandardHelpOptions = true, + description = "Zenoh Queryable example" +) +public class ZQueryable implements Callable { + + private final Boolean emptyArgs; + + ZQueryable(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to write to [default: demo/example/zenoh-java-queryable].", + defaultValue = "demo/example/zenoh-java-queryable" + ) + private String key; + + @CommandLine.Option( + names = {"-v", "--value"}, + description = "The value to reply to queries [default: 'Queryable from Java!'].", + defaultValue = "Queryable from Java!" + ) + private String value; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Declaring Queryable on " + key + "..."); + try (Queryable>> queryable = session.declareQueryable(keyExpr)) { + BlockingQueue> receiver = queryable.getReceiver(); + assert receiver != null; + System.out.println("Press CTRL-C to quit..."); + handleRequests(receiver, keyExpr); } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; } + + return 0; } - private static void handleRequests(BlockingQueue> receiver, KeyExpr keyExpr) throws InterruptedException { + private void handleRequests(BlockingQueue> receiver, KeyExpr keyExpr) throws InterruptedException { while (true) { Optional wrapper = receiver.take(); if (wrapper.isEmpty()) { @@ -52,10 +125,15 @@ private static void handleRequests(BlockingQueue> receiver, KeyE String valueInfo = query.getPayload() != null ? " with value '" + query.getPayload() + "'" : ""; System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); try { - query.reply(keyExpr, ZBytes.from("Queryable from Java!"), new ReplyConfig().timestamp(TimeStamp.getCurrentTime())); + query.reply(keyExpr, ZBytes.from(value), new ReplyConfig().timestamp(TimeStamp.getCurrentTime())); } catch (Exception e) { - System.out.println(">> [Queryable] Error sending reply: " + e); + System.err.println(">> [Queryable] Error sending reply: " + e.getMessage()); } } } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZQueryable(args.length == 0)).execute(args); + System.exit(exitCode); + } } diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index b4a68656..f52813df 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -16,33 +16,107 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.sample.Sample; import io.zenoh.pubsub.Subscriber; +import io.zenoh.sample.Sample; +import picocli.CommandLine; +import java.util.List; import java.util.Optional; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZSub", + mixinStandardHelpOptions = true, + description = "Zenoh Sub example" +) +public class ZSub implements Callable { + + private final Boolean emptyArgs; + + ZSub(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to subscribe to [default: demo/example/**].", + defaultValue = "demo/example/**" + ) + private String key; -public class ZSub { + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - public static void main(String[] args) throws ZError, InterruptedException { System.out.println("Opening session..."); - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/**")) { - System.out.println("Declaring Subscriber on '" + keyExpr + "'..."); - try (Subscriber>> subscriber = session.declareSubscriber(keyExpr)) { - BlockingQueue> receiver = subscriber.getReceiver(); - assert receiver != null; - System.out.println("Press CTRL-C to quit..."); - while (true) { - Optional wrapper = receiver.take(); - if (wrapper.isEmpty()) { - break; - } - Sample sample = wrapper.get(); - System.out.println(">> [Subscriber] Received " + sample.getKind() + " ('" + sample.getKeyExpr() + "': '" + sample.getPayload() + "')"); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Declaring Subscriber on '" + keyExpr + "'..."); + try (Subscriber>> subscriber = session.declareSubscriber(keyExpr)) { + BlockingQueue> receiver = subscriber.getReceiver(); + assert receiver != null; + System.out.println("Press CTRL-C to quit..."); + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; } + Sample sample = wrapper.get(); + String attachment = sample.getAttachment() != null ? ", with attachment: " + sample.getAttachment() : ""; + System.out.println(">> [Subscriber] Received " + sample.getKind() + + " ('" + sample.getKeyExpr() + "': '" + sample.getPayload() + "'" + attachment + ")"); } } + + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; } + + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZSub(args.length == 0)).execute(args); + System.exit(exitCode); } } diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index 79fa3210..0f3d1201 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -17,57 +17,156 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; +import picocli.CommandLine; -public class ZSubThr { +import java.util.List; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZSubThr", + mixinStandardHelpOptions = true, + description = "Zenoh Subscriber Throughput test" +) +public class ZSubThr implements Callable { + + private final Boolean emptyArgs; + + ZSubThr(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } private static final long NANOS_TO_SEC = 1_000_000_000L; - private static final long n = 50000L; - private static int batchCount = 0; - private static int count = 0; - private static long startTimestampNs = 0; - private static long globalStartTimestampNs = 0; + private long batchCount = 0; + private long count = 0; + private long startTimestampNs = 0; + private long globalStartTimestampNs = 0; + + @CommandLine.Option( + names = {"-s", "--samples"}, + description = "Number of throughput measurements [default: 10].", + defaultValue = "10" + ) + private long samples; + + @CommandLine.Option( + names = {"-n", "--number"}, + description = "Number of messages in each throughput measurement [default: 100000].", + defaultValue = "100000" + ) + private long number; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + private Subscriber subscriber; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening Session"); + try (Session session = Zenoh.open(config)) { + try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { + subscriber = session.declareSubscriber(keyExpr, sample -> listener(number)); + System.out.println("Press CTRL-C to quit..."); + + while (subscriber.isValid()) { + Thread.sleep(1000); + } + } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + return 0; + } + + private void listener(long number) { + if (batchCount > samples) { + closeSubscriber(); + report(); + return; + } - public static void listener() { if (count == 0) { startTimestampNs = System.nanoTime(); - if (globalStartTimestampNs == 0L) { + if (globalStartTimestampNs == 0) { globalStartTimestampNs = startTimestampNs; } count++; return; } - if (count < n) { + + if (count < number) { count++; return; } + long stop = System.nanoTime(); - double msgs = (double) (n * NANOS_TO_SEC) / (stop - startTimestampNs); - System.out.println(msgs + " msgs/sec"); + double elapsedTimeSecs = (double) (stop - startTimestampNs) / NANOS_TO_SEC; + double messagesPerSec = number / elapsedTimeSecs; + System.out.printf("%.2f msgs/sec%n", messagesPerSec); batchCount++; count = 0; } - // TODO: perform report at end of measurement - public static void report() { + private void report() { long end = System.nanoTime(); - long total = batchCount * n + count; - double msgs = (double) (end - globalStartTimestampNs) / NANOS_TO_SEC; - double avg = (double) (total * NANOS_TO_SEC) / (end - globalStartTimestampNs); - System.out.println("Received " + total + " messages in " + msgs + - ": averaged " + avg + " msgs/sec"); + long totalMessages = batchCount * number + count; + double elapsedTimeSecs = (double) (end - globalStartTimestampNs) / NANOS_TO_SEC; + double averageMessagesPerSec = totalMessages / elapsedTimeSecs; + + System.out.printf("Received %d messages in %.2f seconds: averaged %.2f msgs/sec%n", + totalMessages, elapsedTimeSecs, averageMessagesPerSec); } - public static void main(String[] args) throws ZError, InterruptedException { - System.out.println("Opening Session"); - try (Session session = Zenoh.open(Config.loadDefault())) { - try (KeyExpr keyExpr = KeyExpr.tryFrom("test/thr")) { - try (Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> listener())) { - System.out.println("Press CTRL-C to quit..."); - while (true) { - Thread.sleep(1000); - } - } + private void closeSubscriber() { + if (subscriber != null && subscriber.isValid()) { + try { + subscriber.close(); + } catch (Exception e) { + System.err.println("Error closing subscriber: " + e.getMessage()); } } } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZSubThr(args.length == 0)).execute(args); + System.exit(exitCode); + } } From 931b980189770ed5d2caf70be8057e2b8db2206d Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 29 Nov 2024 14:16:47 -0300 Subject: [PATCH 62/83] Alignment: examples - adding missing examples --- examples/build.gradle.kts | 5 + .../main/java/io/zenoh/ZGetLiveliness.java | 126 +++++++++++++++++ examples/src/main/java/io/zenoh/ZInfo.java | 96 +++++++++++++ .../src/main/java/io/zenoh/ZLiveliness.java | 105 ++++++++++++++ examples/src/main/java/io/zenoh/ZScout.java | 66 +++++++++ .../main/java/io/zenoh/ZSubLiveliness.java | 132 ++++++++++++++++++ .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 2 + 7 files changed, 532 insertions(+) create mode 100644 examples/src/main/java/io/zenoh/ZGetLiveliness.java create mode 100644 examples/src/main/java/io/zenoh/ZInfo.java create mode 100644 examples/src/main/java/io/zenoh/ZLiveliness.java create mode 100644 examples/src/main/java/io/zenoh/ZScout.java create mode 100644 examples/src/main/java/io/zenoh/ZSubLiveliness.java diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index bd705c32..0b01936b 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -32,11 +32,16 @@ tasks { val examples = listOf( "ZDelete", "ZGet", + "ZGetLiveliness", + "ZInfo", + "ZLiveliness", "ZPub", "ZPubThr", "ZPut", "ZQueryable", + "ZScout", "ZSub", + "ZSubLiveliness", "ZSubThr" ) diff --git a/examples/src/main/java/io/zenoh/ZGetLiveliness.java b/examples/src/main/java/io/zenoh/ZGetLiveliness.java new file mode 100644 index 00000000..bfc9ad5f --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZGetLiveliness.java @@ -0,0 +1,126 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.query.Reply; +import picocli.CommandLine; + +import java.time.Duration; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZGetLiveliness", + mixinStandardHelpOptions = true, + description = "Zenoh Sub Liveliness example" +) +public class ZGetLiveliness implements Callable { + + private final Boolean emptyArgs; + + ZGetLiveliness(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression matching liveliness tokens to query. [default: group1/**].", + defaultValue = "group1/**" + ) + private String key; + + @CommandLine.Option( + names = {"-o", "--timeout"}, + description = "The query timeout in milliseconds [default: 10000].", + defaultValue = "10000" + ) + private long timeout; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + try (KeyExpr keyExpr = KeyExpr.tryFrom(key)) { + BlockingQueue> replyQueue = session.liveliness().get(keyExpr, Duration.ofMillis(timeout)); + System.out.println("Listening for liveliness tokens..."); + while (true) { + Optional wrapper = replyQueue.take(); + if (wrapper.isEmpty()) { + break; + } + Reply reply = wrapper.get(); + if (reply instanceof Reply.Success) { + System.out.println(">> Alive token ('" + ((Reply.Success) reply).getSample().getKeyExpr() + "')"); + } else if (reply instanceof Reply.Error) { + System.out.println(">> Received (ERROR: '" + ((Reply.Error) reply).getError() + "')"); + } + } + } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZGetLiveliness(args.length == 0)).execute(args); + System.exit(exitCode); + } +} diff --git a/examples/src/main/java/io/zenoh/ZInfo.java b/examples/src/main/java/io/zenoh/ZInfo.java new file mode 100644 index 00000000..9718930f --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZInfo.java @@ -0,0 +1,96 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.session.SessionInfo; +import picocli.CommandLine; + +import java.util.List; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZInfo", + mixinStandardHelpOptions = true, + description = "Zenoh Info example" +) +public class ZInfo implements Callable { + + private final Boolean emptyArgs; + + ZInfo(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + SessionInfo info = session.info(); + System.out.println("zid: " + info.zid()); + System.out.println("routers zid: " + info.routersZid()); + System.out.println("peers zid: " + info.peersZid()); + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZInfo(args.length == 0)).execute(args); + System.exit(exitCode); + } +} diff --git a/examples/src/main/java/io/zenoh/ZLiveliness.java b/examples/src/main/java/io/zenoh/ZLiveliness.java new file mode 100644 index 00000000..2b39dbc2 --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZLiveliness.java @@ -0,0 +1,105 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import picocli.CommandLine; + +import java.util.List; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZLiveliness", + mixinStandardHelpOptions = true, + description = "Zenoh Liveliness example" +) +public class ZLiveliness implements Callable { + + private final Boolean emptyArgs; + + ZLiveliness(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to declare liveliness tokens for [default: group1/zenoh-java].", + defaultValue = "group1/zenoh-java" + ) + private String key; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + try (KeyExpr keyExpr = KeyExpr.tryFrom(key)) { + session.liveliness().declareToken(keyExpr); + System.out.println("Liveliness token declared for key: " + key); + while (true) { + Thread.sleep(1000); + } + } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZLiveliness(args.length == 0)).execute(args); + System.exit(exitCode); + } +} diff --git a/examples/src/main/java/io/zenoh/ZScout.java b/examples/src/main/java/io/zenoh/ZScout.java new file mode 100644 index 00000000..45999e1f --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZScout.java @@ -0,0 +1,66 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.config.WhatAmI; +import io.zenoh.scouting.Hello; +import io.zenoh.scouting.Scout; +import io.zenoh.scouting.ScoutConfig; +import picocli.CommandLine; + +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; + +@CommandLine.Command( + name = "ZScout", + mixinStandardHelpOptions = true, + description = "Zenoh Scouting example" +) +public class ZScout implements Callable { + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + System.out.println("Scouting..."); + + Scout>> scout = Zenoh.scout(new ScoutConfig().whatAmI(Set.of(WhatAmI.Peer, WhatAmI.Router))); + BlockingQueue> receiver = scout.getReceiver(); + assert receiver != null; + + try { + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + + Hello hello = wrapper.get(); + System.out.println(hello); + } + } finally { + scout.stop(); + } + + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZScout()).execute(args); + System.exit(exitCode); + } +} diff --git a/examples/src/main/java/io/zenoh/ZSubLiveliness.java b/examples/src/main/java/io/zenoh/ZSubLiveliness.java new file mode 100644 index 00000000..5176b263 --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZSubLiveliness.java @@ -0,0 +1,132 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.liveliness.Liveliness; +import io.zenoh.pubsub.Subscriber; +import io.zenoh.sample.Sample; +import io.zenoh.sample.SampleKind; +import picocli.CommandLine; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZSubLiveliness", + mixinStandardHelpOptions = true, + description = "Zenoh Sub Liveliness example" +) +public class ZSubLiveliness implements Callable { + + private final Boolean emptyArgs; + + ZSubLiveliness(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-k", "--key"}, + description = "The key expression to subscribe to [default: group1/**].", + defaultValue = "group1/**" + ) + private String key; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--history"}, + description = "Get historical liveliness tokens.", + defaultValue = "false" + ) + private boolean history; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + try (KeyExpr keyExpr = KeyExpr.tryFrom(key)) { + Subscriber>> subscriber = + session.liveliness().declareSubscriber(keyExpr, new Liveliness.SubscriberConfig().history(history)); + + BlockingQueue> receiver = subscriber.getReceiver(); + System.out.println("Listening for liveliness tokens..."); + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + + Sample sample = wrapper.get(); + if (sample.getKind() == SampleKind.PUT) { + System.out.println(">> [LivelinessSubscriber] New alive token ('" + sample.getKeyExpr() + "')"); + } else if (sample.getKind() == SampleKind.DELETE) { + System.out.println(">> [LivelinessSubscriber] Dropped token ('" + sample.getKeyExpr() + "')"); + } + } + } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZSubLiveliness(args.length == 0)).execute(args); + System.exit(exitCode); + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index 9a105194..8d242670 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -108,6 +108,7 @@ object Zenoh { * @see Logger */ @JvmStatic + @Throws(ZError::class) fun tryInitLogFromEnv() { val logEnv = System.getenv(LOG_ENV) if (logEnv != null) { @@ -127,6 +128,7 @@ object Zenoh { * @see Logger */ @JvmStatic + @Throws(ZError::class) fun initLogFromEnvOr(fallbackFilter: String) { ZenohLoad val logLevelProp = System.getenv(LOG_ENV) From bbf20c2d2584ba925f4a2a919b52732d344cdeff Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Fri, 29 Nov 2024 18:02:35 -0300 Subject: [PATCH 63/83] Alignment: examples - adding ping and pong examples --- examples/build.gradle.kts | 2 + examples/src/main/java/io/zenoh/ZPing.java | 159 +++++++++++++++++++++ examples/src/main/java/io/zenoh/ZPong.java | 121 ++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 examples/src/main/java/io/zenoh/ZPing.java create mode 100644 examples/src/main/java/io/zenoh/ZPong.java diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 0b01936b..683709d3 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -35,6 +35,8 @@ tasks { "ZGetLiveliness", "ZInfo", "ZLiveliness", + "ZPing", + "ZPong", "ZPub", "ZPubThr", "ZPut", diff --git a/examples/src/main/java/io/zenoh/ZPing.java b/examples/src/main/java/io/zenoh/ZPing.java new file mode 100644 index 00000000..d39996b2 --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZPing.java @@ -0,0 +1,159 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.bytes.ZBytes; +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Publisher; +import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.qos.CongestionControl; +import io.zenoh.sample.Sample; +import picocli.CommandLine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZPing", + mixinStandardHelpOptions = true, + description = "Zenoh Ping example" +) +public class ZPing implements Callable { + + @CommandLine.Parameters( + paramLabel = "payload_size", + description = "Sets the size of the payload to publish [default: 8].", + defaultValue = "8" + ) + private int payloadSize; + + @CommandLine.Option( + names = "--no-express", + description = "Express for sending data.", + defaultValue = "false" + ) + private boolean noExpress; + + @CommandLine.Option( + names = {"-w", "--warmup"}, + description = "The number of seconds to warm up [default: 1.0].", + defaultValue = "1.0" + ) + private double warmup; + + @CommandLine.Option( + names = {"-n", "--samples"}, + description = "The number of round-trips to measure [default: 100].", + defaultValue = "100" + ) + private int n; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + // Load Zenoh configuration + Config config = loadConfig(true, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); + KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); + + BlockingQueue> receiverQueue = + session.declareSubscriber(keyExprPong).getReceiver(); + Publisher publisher = + session.declarePublisher(keyExprPing, new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress)); + + byte[] data = new byte[payloadSize]; + for (int i = 0; i < payloadSize; i++) { + data[i] = (byte) (i % 10); + } + ZBytes payload = ZBytes.from(data); + + // Warm-up + System.out.println("Warming up for " + warmup + " seconds..."); + long warmupEnd = System.currentTimeMillis() + (long) (warmup * 1000); + while (System.currentTimeMillis() < warmupEnd) { + publisher.put(payload); + receiverQueue.take(); + } + + List samples = new ArrayList<>(); + for (int i = 0; i < n; i++) { + long startTime = System.nanoTime(); + publisher.put(payload); + receiverQueue.take(); + long elapsedTime = (System.nanoTime() - startTime) / 1000; // Convert to microseconds + samples.add(elapsedTime); + } + + for (int i = 0; i < samples.size(); i++) { + long rtt = samples.get(i); + System.out.printf("%d bytes: seq=%d rtt=%dµs lat=%dµs%n", payloadSize, i, rtt, rtt / 2); + } + } catch (ZError e) { + System.err.println("Error: " + e.getMessage()); + return 1; + } + + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new ZPing()).execute(args); + System.exit(exitCode); + } +} diff --git a/examples/src/main/java/io/zenoh/ZPong.java b/examples/src/main/java/io/zenoh/ZPong.java new file mode 100644 index 00000000..4c60fc78 --- /dev/null +++ b/examples/src/main/java/io/zenoh/ZPong.java @@ -0,0 +1,121 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh; + +import io.zenoh.exceptions.ZError; +import io.zenoh.keyexpr.KeyExpr; +import io.zenoh.pubsub.Publisher; +import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.qos.CongestionControl; +import picocli.CommandLine; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; + +import static io.zenoh.ConfigKt.loadConfig; + +@CommandLine.Command( + name = "ZPong", + mixinStandardHelpOptions = true, + description = "Zenoh ZPong example" +) +public class ZPong implements Callable { + + @CommandLine.Option( + names = "--no-express", + description = "Express for sending data.", + defaultValue = "false" + ) + private boolean noExpress; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + private static final CountDownLatch latch = new CountDownLatch(1); + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(true, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); + KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); + + Publisher publisher = session.declarePublisher( + keyExprPong, + new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress) + ); + + session.declareSubscriber(keyExprPing, sample -> { + try { + publisher.put(sample.getPayload()); + } catch (ZError e) { + System.err.println("Error responding to ping: " + e.getMessage()); + } + }); + + latch.await(); + } catch (ZError e) { + System.err.println("Error: " + e.getMessage()); + return 1; + } + return 0; + } + + public static void main(String[] args) { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + System.out.println("Shutting down..."); + latch.countDown(); + })); + + int exitCode = new CommandLine(new ZPong()).execute(args); + System.exit(exitCode); + } +} From da98b95dd3be6a345df6ec616685f9c0ff73f1c9 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 2 Dec 2024 01:29:54 -0300 Subject: [PATCH 64/83] Alignment: examples refactor + refactor queryable config logic --- .../src/main/java/io/zenoh/QueueHandler.java | 33 +++++ examples/src/main/java/io/zenoh/ZGet.java | 139 +++++++++++++----- .../main/java/io/zenoh/ZGetLiveliness.java | 104 ++++++++----- examples/src/main/java/io/zenoh/ZInfo.java | 43 +++--- .../src/main/java/io/zenoh/ZLiveliness.java | 48 +++--- examples/src/main/java/io/zenoh/ZPing.java | 109 +++++++------- examples/src/main/java/io/zenoh/ZPong.java | 69 +++++---- examples/src/main/java/io/zenoh/ZPub.java | 79 ++++++---- examples/src/main/java/io/zenoh/ZPubThr.java | 89 +++++------ examples/src/main/java/io/zenoh/ZPut.java | 51 ++++--- .../src/main/java/io/zenoh/ZQueryable.java | 116 +++++++++------ examples/src/main/java/io/zenoh/ZSub.java | 107 +++++++++----- .../main/java/io/zenoh/ZSubLiveliness.java | 118 ++++++++++----- examples/src/main/java/io/zenoh/ZSubThr.java | 129 ++++++++-------- .../src/commonMain/kotlin/io/zenoh/Session.kt | 29 ++-- .../kotlin/io/zenoh/jni/JNISession.kt | 12 +- .../kotlin/io/zenoh/query/Queryable.kt | 19 +-- .../jvmTest/java/io/zenoh/EncodingTest.java | 12 +- .../src/jvmTest/java/io/zenoh/GetTest.java | 31 ++-- .../jvmTest/java/io/zenoh/QueryableTest.java | 27 ++-- .../java/io/zenoh/UserAttachmentTest.java | 13 +- 21 files changed, 843 insertions(+), 534 deletions(-) create mode 100644 examples/src/main/java/io/zenoh/QueueHandler.java diff --git a/examples/src/main/java/io/zenoh/QueueHandler.java b/examples/src/main/java/io/zenoh/QueueHandler.java new file mode 100644 index 00000000..cf56fbf4 --- /dev/null +++ b/examples/src/main/java/io/zenoh/QueueHandler.java @@ -0,0 +1,33 @@ +package io.zenoh; + +import io.zenoh.handlers.Handler; + +import java.util.ArrayDeque; + +/** + * Sample handler for the sake of the examples. + * + * A custom handler can be implemented to handle incoming samples, queries or replies for + * subscribers, get operations, query operations or queryables. + * + * The example below shows a queue handler, in which an ArrayDeque is specified as the receiver type. + * The function handle will be called everytime an element of type T is received and in our example + * implementation, elements are simply enqueued into the queue, which can later be retrieved. + */ +class QueueHandler implements Handler> { + + final ArrayDeque queue = new ArrayDeque<>(); + + @Override + public void handle(T t) { + queue.add(t); + } + + @Override + public ArrayDeque receiver() { + return queue; + } + + @Override + public void onClose() {} +} diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index c376d79a..704ab587 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -14,12 +14,16 @@ package io.zenoh; +import io.zenoh.bytes.Encoding; +import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; +import io.zenoh.query.GetConfig; import io.zenoh.query.Selector; import io.zenoh.query.Reply; import io.zenoh.sample.SampleKind; import picocli.CommandLine; +import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.concurrent.BlockingQueue; @@ -34,6 +38,108 @@ ) public class ZGet implements Callable { + @Override + public Integer call() throws ZError, InterruptedException { + Zenoh.initLogFromEnvOr("error"); + System.out.println("Opening session..."); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + Selector selector = Selector.tryFrom(this.selectorOpt); + + // A GET query can be performed in different ways, by default (using a blocking queue), using a callback + // or providing a handler. Uncomment one of the function calls below to try out different implementations: + // Implementation with a blocking queue + getExampleDefault(config, selector); + // getExampleWithCallback(config, selector); + // getExampleWithHandler(config, selector); + // getExampleProvidingConfig(config, selector); + + return 0; + } + + private void getExampleDefault(Config config, Selector selector) throws ZError, InterruptedException { + try (Session session = Zenoh.open(config)) { + System.out.println("Performing Get on '" + selector + "'..."); + BlockingQueue> receiver = session.get(selector); + + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + Reply reply = wrapper.get(); + handleReply(reply); + } + } + } + + /** + * Example using a simple callback for handling the replies. + * @see io.zenoh.handlers.Callback + */ + private void getExampleWithCallback(Config config, Selector selector) throws ZError { + try (Session session = Zenoh.open(config)) { + System.out.println("Performing Get on '" + selector + "'..."); + session.get(selector, this::handleReply); + } + } + + /** + * Example using a custom implementation of a Handler. + * @see QueueHandler + * @see io.zenoh.handlers.Handler + */ + private void getExampleWithHandler(Config config, Selector selector) throws ZError { + try (Session session = Zenoh.open(config)) { + System.out.println("Performing Get on '" + selector + "'..."); + QueueHandler queueHandler = new QueueHandler<>(); + session.get(selector, queueHandler); + } + } + + /** + * The purpose of this example is to show how to provide configuration parameters + * to the get query. For this, you can optionally provide a GetConfig parameter. + * @see GetConfig + */ + private void getExampleProvidingConfig(Config config, Selector selector) throws ZError { + try (Session session = Zenoh.open(config)) { + System.out.println("Performing Get on '" + selector + "'..."); + + // Build the config + GetConfig getConfig = new GetConfig(); + getConfig.setTimeout(Duration.ofMillis(1000)); + getConfig.setEncoding(Encoding.ZENOH_STRING); + getConfig.setPayload(ZBytes.from("Example payload")); + + // Note the syntax below is valid as well + GetConfig getConfig2 = new GetConfig() + .timeout(Duration.ofMillis(1000)) + .encoding(Encoding.ZENOH_STRING) + .payload(ZBytes.from("Example payload")); + + // Apply the config + session.get(selector, this::handleReply, getConfig); + } + } + + private void handleReply(Reply reply) { + if (reply instanceof Reply.Success) { + Reply.Success successReply = (Reply.Success) reply; + if (successReply.getSample().getKind() == SampleKind.PUT) { + System.out.println("Received ('" + successReply.getSample().getKeyExpr() + "': '" + successReply.getSample().getPayload() + "')"); + } else if (successReply.getSample().getKind() == SampleKind.DELETE) { + System.out.println("Received (DELETE '" + successReply.getSample().getKeyExpr() + "')"); + } + } else { + Reply.Error errorReply = (Reply.Error) reply; + System.out.println("Received (ERROR: '" + errorReply.getError() + "')"); + } + } + + /** + * ----- Example CLI arguments and private fields ----- + */ private final Boolean emptyArgs; ZGet(Boolean emptyArgs) { @@ -107,39 +213,6 @@ public class ZGet implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws ZError, InterruptedException { - Zenoh.initLogFromEnvOr("error"); - System.out.println("Opening session..."); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - try (Session session = Zenoh.open(config)) { - Selector selector = Selector.tryFrom(this.selectorOpt); - System.out.println("Performing Get on '" + selector + "'..."); - BlockingQueue> receiver = session.get(selector); - while (true) { - Optional wrapper = receiver.take(); - if (wrapper.isEmpty()) { - break; - } - Reply reply = wrapper.get(); - if (reply instanceof Reply.Success) { - Reply.Success successReply = (Reply.Success) reply; - if (successReply.getSample().getKind() == SampleKind.PUT) { - System.out.println("Received ('" + successReply.getSample().getKeyExpr() + "': '" + successReply.getSample().getPayload() + "')"); - } else if (successReply.getSample().getKind() == SampleKind.DELETE) { - System.out.println("Received (DELETE '" + successReply.getSample().getKeyExpr() + "')"); - } - } else { - Reply.Error errorReply = (Reply.Error) reply; - System.out.println("Received (ERROR: '" + errorReply.getError() + "')"); - } - } - - } - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZGet(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZGetLiveliness.java b/examples/src/main/java/io/zenoh/ZGetLiveliness.java index bfc9ad5f..423bf402 100644 --- a/examples/src/main/java/io/zenoh/ZGetLiveliness.java +++ b/examples/src/main/java/io/zenoh/ZGetLiveliness.java @@ -3,8 +3,7 @@ // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0. // // SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 // @@ -30,10 +29,78 @@ @CommandLine.Command( name = "ZGetLiveliness", mixinStandardHelpOptions = true, - description = "Zenoh Sub Liveliness example" + description = "Zenoh Get Liveliness example" ) public class ZGetLiveliness implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + KeyExpr keyExpr = KeyExpr.tryFrom(this.key); + + // Uncomment one of the lines below to try out different implementations: + getLivelinessWithBlockingQueue(config, keyExpr); + // getLivelinessWithCallback(config, keyExpr); + // getLivelinessWithHandler(config, keyExpr); + + return 0; + } + + /** + * Default implementation using a blocking queue to handle replies. + */ + private void getLivelinessWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { + try (Session session = Zenoh.open(config)) { + BlockingQueue> replyQueue = session.liveliness().get(keyExpr, Duration.ofMillis(timeout)); + + while (true) { + Optional wrapper = replyQueue.take(); + if (wrapper.isEmpty()) { + break; + } + handleReply(wrapper.get()); + } + } + } + + /** + * Example using a callback to handle liveliness replies asynchronously. + * @see io.zenoh.handlers.Callback + */ + private void getLivelinessWithCallback(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + session.liveliness().get(keyExpr, this::handleReply, Duration.ofMillis(timeout)); + } + } + + /** + * Example using a custom handler to process liveliness replies. + * @see QueueHandler + * @see io.zenoh.handlers.Handler + */ + private void getLivelinessWithHandler(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + QueueHandler queueHandler = new QueueHandler<>(); + session.liveliness().get(keyExpr, queueHandler, Duration.ofMillis(timeout)); + } + } + + private void handleReply(Reply reply) { + if (reply instanceof Reply.Success) { + Reply.Success successReply = (Reply.Success) reply; + System.out.println(">> Alive token ('" + successReply.getSample().getKeyExpr() + "')"); + } else if (reply instanceof Reply.Error) { + Reply.Error errorReply = (Reply.Error) reply; + System.out.println(">> Received (ERROR: '" + errorReply.getError() + "')"); + } + } + + /** + * ----- Example arguments and private fields ----- + */ + private final Boolean emptyArgs; ZGetLiveliness(Boolean emptyArgs) { @@ -88,37 +155,6 @@ public class ZGetLiveliness implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - try (KeyExpr keyExpr = KeyExpr.tryFrom(key)) { - BlockingQueue> replyQueue = session.liveliness().get(keyExpr, Duration.ofMillis(timeout)); - System.out.println("Listening for liveliness tokens..."); - while (true) { - Optional wrapper = replyQueue.take(); - if (wrapper.isEmpty()) { - break; - } - Reply reply = wrapper.get(); - if (reply instanceof Reply.Success) { - System.out.println(">> Alive token ('" + ((Reply.Success) reply).getSample().getKeyExpr() + "')"); - } else if (reply instanceof Reply.Error) { - System.out.println(">> Received (ERROR: '" + ((Reply.Error) reply).getError() + "')"); - } - } - } - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZGetLiveliness(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZInfo.java b/examples/src/main/java/io/zenoh/ZInfo.java index 9718930f..4d4bdb53 100644 --- a/examples/src/main/java/io/zenoh/ZInfo.java +++ b/examples/src/main/java/io/zenoh/ZInfo.java @@ -30,6 +30,30 @@ ) public class ZInfo implements Callable { + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + SessionInfo info = session.info(); + System.out.println("zid: " + info.zid()); + System.out.println("routers zid: " + info.routersZid()); + System.out.println("peers zid: " + info.peersZid()); + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + return 0; + } + + /** + * ----- Example CLI arguments and private fields ----- + */ + private final Boolean emptyArgs; ZInfo(Boolean emptyArgs) { @@ -70,25 +94,6 @@ public class ZInfo implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - SessionInfo info = session.info(); - System.out.println("zid: " + info.zid()); - System.out.println("routers zid: " + info.routersZid()); - System.out.println("peers zid: " + info.peersZid()); - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZInfo(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZLiveliness.java b/examples/src/main/java/io/zenoh/ZLiveliness.java index 2b39dbc2..b1df3c29 100644 --- a/examples/src/main/java/io/zenoh/ZLiveliness.java +++ b/examples/src/main/java/io/zenoh/ZLiveliness.java @@ -30,6 +30,34 @@ ) public class ZLiveliness implements Callable { + + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + session.liveliness().declareToken(keyExpr); + System.out.println("Liveliness token declared for key: " + key); + + while (true) { + Thread.sleep(1000); + } + + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + private final Boolean emptyArgs; ZLiveliness(Boolean emptyArgs) { @@ -77,26 +105,6 @@ public class ZLiveliness implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - try (KeyExpr keyExpr = KeyExpr.tryFrom(key)) { - session.liveliness().declareToken(keyExpr); - System.out.println("Liveliness token declared for key: " + key); - while (true) { - Thread.sleep(1000); - } - } - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - } public static void main(String[] args) { int exitCode = new CommandLine(new ZLiveliness(args.length == 0)).execute(args); diff --git a/examples/src/main/java/io/zenoh/ZPing.java b/examples/src/main/java/io/zenoh/ZPing.java index d39996b2..e2c7b409 100644 --- a/examples/src/main/java/io/zenoh/ZPing.java +++ b/examples/src/main/java/io/zenoh/ZPing.java @@ -38,6 +38,63 @@ ) public class ZPing implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + // Load Zenoh configuration + Config config = loadConfig(true, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); + KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); + + BlockingQueue> receiverQueue = + session.declareSubscriber(keyExprPong).getReceiver(); + Publisher publisher = + session.declarePublisher(keyExprPing, new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress)); + + byte[] data = new byte[payloadSize]; + for (int i = 0; i < payloadSize; i++) { + data[i] = (byte) (i % 10); + } + ZBytes payload = ZBytes.from(data); + + // Warm-up + System.out.println("Warming up for " + warmup + " seconds..."); + long warmupEnd = System.currentTimeMillis() + (long) (warmup * 1000); + while (System.currentTimeMillis() < warmupEnd) { + publisher.put(payload); + receiverQueue.take(); + } + + List samples = new ArrayList<>(); + for (int i = 0; i < n; i++) { + long startTime = System.nanoTime(); + publisher.put(payload); + receiverQueue.take(); + long elapsedTime = (System.nanoTime() - startTime) / 1000; // Convert to microseconds + samples.add(elapsedTime); + } + + for (int i = 0; i < samples.size(); i++) { + long rtt = samples.get(i); + System.out.printf("%d bytes: seq=%d rtt=%dµs lat=%dµs%n", payloadSize, i, rtt, rtt / 2); + } + } catch (ZError e) { + System.err.println("Error: " + e.getMessage()); + return 1; + } + + return 0; + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + @CommandLine.Parameters( paramLabel = "payload_size", description = "Sets the size of the payload to publish [default: 8].", @@ -100,58 +157,6 @@ public class ZPing implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - // Load Zenoh configuration - Config config = loadConfig(true, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); - KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); - - BlockingQueue> receiverQueue = - session.declareSubscriber(keyExprPong).getReceiver(); - Publisher publisher = - session.declarePublisher(keyExprPing, new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress)); - - byte[] data = new byte[payloadSize]; - for (int i = 0; i < payloadSize; i++) { - data[i] = (byte) (i % 10); - } - ZBytes payload = ZBytes.from(data); - - // Warm-up - System.out.println("Warming up for " + warmup + " seconds..."); - long warmupEnd = System.currentTimeMillis() + (long) (warmup * 1000); - while (System.currentTimeMillis() < warmupEnd) { - publisher.put(payload); - receiverQueue.take(); - } - - List samples = new ArrayList<>(); - for (int i = 0; i < n; i++) { - long startTime = System.nanoTime(); - publisher.put(payload); - receiverQueue.take(); - long elapsedTime = (System.nanoTime() - startTime) / 1000; // Convert to microseconds - samples.add(elapsedTime); - } - - for (int i = 0; i < samples.size(); i++) { - long rtt = samples.get(i); - System.out.printf("%d bytes: seq=%d rtt=%dµs lat=%dµs%n", payloadSize, i, rtt, rtt / 2); - } - } catch (ZError e) { - System.err.println("Error: " + e.getMessage()); - return 1; - } - - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZPing()).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZPong.java b/examples/src/main/java/io/zenoh/ZPong.java index 4c60fc78..0527d595 100644 --- a/examples/src/main/java/io/zenoh/ZPong.java +++ b/examples/src/main/java/io/zenoh/ZPong.java @@ -34,6 +34,43 @@ ) public class ZPong implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(true, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); + KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); + + Publisher publisher = session.declarePublisher( + keyExprPong, + new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress) + ); + + session.declareSubscriber(keyExprPing, sample -> { + try { + publisher.put(sample.getPayload()); + } catch (ZError e) { + System.err.println("Error responding to ping: " + e.getMessage()); + } + }); + + latch.await(); + } catch (ZError e) { + System.err.println("Error: " + e.getMessage()); + return 1; + } + return 0; + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + @CommandLine.Option( names = "--no-express", description = "Express for sending data.", @@ -77,38 +114,6 @@ public class ZPong implements Callable { private static final CountDownLatch latch = new CountDownLatch(1); - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(true, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); - KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); - - Publisher publisher = session.declarePublisher( - keyExprPong, - new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress) - ); - - session.declareSubscriber(keyExprPing, sample -> { - try { - publisher.put(sample.getPayload()); - } catch (ZError e) { - System.err.println("Error responding to ping: " + e.getMessage()); - } - }); - - latch.await(); - } catch (ZError e) { - System.err.println("Error: " + e.getMessage()); - return 1; - } - return 0; - } - public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("Shutting down..."); diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index 5cef5ee4..78f8c1da 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -14,11 +14,15 @@ package io.zenoh; +import io.zenoh.bytes.Encoding; import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; +import io.zenoh.pubsub.PublisherConfig; import io.zenoh.pubsub.PutConfig; +import io.zenoh.qos.CongestionControl; +import io.zenoh.qos.Reliability; import picocli.CommandLine; import java.util.List; @@ -33,6 +37,50 @@ ) public class ZPub implements Callable { + @Override + public Integer call() throws ZError { + Zenoh.initLogFromEnvOr("error"); + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Declaring publisher on '" + keyExpr + "'..."); + + // A publisher config can optionally be provided. + PublisherConfig publisherConfig = new PublisherConfig() + .encoding(Encoding.ZENOH_STRING) + .congestionControl(CongestionControl.BLOCK) + .reliability(Reliability.RELIABLE); + + // Declare the publisher + Publisher publisher = session.declarePublisher(keyExpr, publisherConfig); + + System.out.println("Press CTRL-C to quit..."); + ZBytes attachmentBytes = attachment != null ? ZBytes.from(attachment) : null; + int idx = 0; + while (true) { + Thread.sleep(1000); + String payload = String.format("[%4d] %s", idx, value); + System.out.println("Putting Data ('" + keyExpr + "': '" + payload + "')..."); + if (attachmentBytes != null) { + publisher.put(ZBytes.from(payload), new PutConfig().attachment(attachmentBytes)); + } else { + publisher.put(ZBytes.from(payload)); + } + idx++; + } + } catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + return 1; + } + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + private final Boolean emptyArgs; ZPub(Boolean emptyArgs) { @@ -93,37 +141,6 @@ public class ZPub implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws ZError { - Zenoh.initLogFromEnvOr("error"); - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExpr = KeyExpr.tryFrom(key); - System.out.println("Declaring publisher on '" + keyExpr + "'..."); - try (Publisher publisher = session.declarePublisher(keyExpr)) { - System.out.println("Press CTRL-C to quit..."); - ZBytes attachmentBytes = attachment != null ? ZBytes.from(attachment) : null; - int idx = 0; - while (true) { - Thread.sleep(1000); - String payload = String.format("[%4d] %s", idx, value); - System.out.println("Putting Data ('" + keyExpr + "': '" + payload + "')..."); - if (attachmentBytes != null) { - publisher.put(ZBytes.from(payload), new PutConfig().attachment(attachmentBytes)); - } else { - publisher.put(ZBytes.from(payload)); - } - idx++; - } - } - } catch (Exception e) { - System.err.println("Error: " + e.getMessage()); - return 1; - } - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZPub(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index 0c417c08..98979926 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -34,6 +34,53 @@ ) public class ZPubThr implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + byte[] data = new byte[payloadSize]; + for (int i = 0; i < payloadSize; i++) { + data[i] = (byte) (i % 10); + } + ZBytes payload = ZBytes.from(data); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom("test/thr"); + var publisherConfig = new PublisherConfig() + .congestionControl(CongestionControl.BLOCK) + .priority(priorityInput != null ? Priority.getEntries().get(priorityInput) : Priority.DATA); + try (Publisher publisher = session.declarePublisher(keyExpr, publisherConfig)) { + System.out.println("Publisher declared on test/thr."); + long count = 0; + long start = System.currentTimeMillis(); + System.out.println("Press CTRL-C to quit..."); + + while (true) { + publisher.put(payload); + + if (statsPrint) { + if (count < number) { + count++; + } else { + long elapsedTime = System.currentTimeMillis() - start; + long throughput = (count * 1000) / elapsedTime; + System.out.println(throughput + " msgs/s"); + count = 0; + start = System.currentTimeMillis(); + } + } + } + } + } + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + private final Boolean emptyArgs; ZPubThr(Boolean emptyArgs) { @@ -101,48 +148,6 @@ public class ZPubThr implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - byte[] data = new byte[payloadSize]; - for (int i = 0; i < payloadSize; i++) { - data[i] = (byte) (i % 10); - } - ZBytes payload = ZBytes.from(data); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - try (Session session = Zenoh.open(config)) { - KeyExpr keyExpr = KeyExpr.tryFrom("test/thr"); - var publisherConfig = new PublisherConfig() - .congestionControl(CongestionControl.BLOCK) - .priority(priorityInput != null ? Priority.getEntries().get(priorityInput) : Priority.DATA); - try (Publisher publisher = session.declarePublisher(keyExpr, publisherConfig)) { - System.out.println("Publisher declared on test/thr."); - long count = 0; - long start = System.currentTimeMillis(); - System.out.println("Press CTRL-C to quit..."); - - while (true) { - publisher.put(payload); - - if (statsPrint) { - if (count < number) { - count++; - } else { - long elapsedTime = System.currentTimeMillis() - start; - long throughput = (count * 1000) / elapsedTime; - System.out.println(throughput + " msgs/s"); - count = 0; - start = System.currentTimeMillis(); - } - } - } - } - } - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZPubThr(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZPut.java b/examples/src/main/java/io/zenoh/ZPut.java index 6a2b9b53..989e337f 100644 --- a/examples/src/main/java/io/zenoh/ZPut.java +++ b/examples/src/main/java/io/zenoh/ZPut.java @@ -32,6 +32,34 @@ ) public class ZPut implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + + System.out.println("Opening session..."); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); + if (attachment != null) { + session.put(keyExpr, ZBytes.from(value), new PutConfig().attachment(ZBytes.from(attachment))); + } else { + session.put(keyExpr, ZBytes.from(value)); + } + } catch (ZError e) { + System.err.println("Error during Zenoh operation: " + e.getMessage()); + return 1; + } + + return 0; + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + private final Boolean emptyArgs; ZPut(Boolean emptyArgs) { @@ -92,29 +120,6 @@ public class ZPut implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExpr = KeyExpr.tryFrom(key); - System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); - if (attachment != null) { - session.put(keyExpr, ZBytes.from(value), new PutConfig().attachment(ZBytes.from(attachment))); - } else { - session.put(keyExpr, ZBytes.from(value)); - } - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZPut(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index e46dc478..e0e3f488 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -19,6 +19,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.query.Query; import io.zenoh.query.Queryable; +import io.zenoh.query.QueryableConfig; import io.zenoh.query.ReplyConfig; import org.apache.commons.net.ntp.TimeStamp; import picocli.CommandLine; @@ -37,6 +38,80 @@ ) public class ZQueryable implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + KeyExpr keyExpr = KeyExpr.tryFrom(this.key); + + // A Queryable can be implemented in multiple ways. Uncomment one to try: + declareQueryableWithBlockingQueue(config, keyExpr); + // declareQueryableWithCallback(config, keyExpr); + // declareQueryableProvidingConfig(config, keyExpr); + + return 0; + } + + /** + * Default implementation using a blocking queue to handle incoming queries. + */ + private void declareQueryableWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { + try (Session session = Zenoh.open(config)) { + Queryable>> queryable = session.declareQueryable(keyExpr); + BlockingQueue> receiver = queryable.getReceiver(); + assert receiver != null; + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + Query query = wrapper.get(); + handleQuery(query); + } + } + } + + /** + * Example using a callback to handle incoming queries asynchronously. + * + * @see io.zenoh.handlers.Callback + */ + private void declareQueryableWithCallback(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + session.declareQueryable(keyExpr, this::handleQuery); + } + } + + /** + * Example demonstrating the use of QueryableConfig to declare a Queryable. + * + * @see QueryableConfig + */ + private void declareQueryableProvidingConfig(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + QueryableConfig queryableConfig = new QueryableConfig(); + queryableConfig.setComplete(true); + queryableConfig.setOnClose(() -> System.out.println("Queryable closed...")); + + session.declareQueryable(keyExpr, this::handleQuery, queryableConfig); + } + } + + private void handleQuery(Query query) { + try { + String valueInfo = query.getPayload() != null ? " with value '" + query.getPayload() + "'" : ""; + System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); + query.reply(query.getKeyExpr(), ZBytes.from(value), new ReplyConfig().timestamp(TimeStamp.getCurrentTime())); + } catch (Exception e) { + System.err.println(">> [Queryable] Error sending reply: " + e.getMessage()); + } + } + + /** + * ----- Example arguments and private fields ----- + */ + private final Boolean emptyArgs; ZQueryable(Boolean emptyArgs) { @@ -91,47 +166,6 @@ public class ZQueryable implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExpr = KeyExpr.tryFrom(key); - System.out.println("Declaring Queryable on " + key + "..."); - try (Queryable>> queryable = session.declareQueryable(keyExpr)) { - BlockingQueue> receiver = queryable.getReceiver(); - assert receiver != null; - System.out.println("Press CTRL-C to quit..."); - handleRequests(receiver, keyExpr); - } - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - - return 0; - } - - private void handleRequests(BlockingQueue> receiver, KeyExpr keyExpr) throws InterruptedException { - while (true) { - Optional wrapper = receiver.take(); - if (wrapper.isEmpty()) { - break; - } - Query query = wrapper.get(); - String valueInfo = query.getPayload() != null ? " with value '" + query.getPayload() + "'" : ""; - System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); - try { - query.reply(keyExpr, ZBytes.from(value), new ReplyConfig().timestamp(TimeStamp.getCurrentTime())); - } catch (Exception e) { - System.err.println(">> [Queryable] Error sending reply: " + e.getMessage()); - } - } - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZQueryable(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index f52813df..54c92a2d 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -15,13 +15,16 @@ package io.zenoh; import io.zenoh.exceptions.ZError; +import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.sample.Sample; import picocli.CommandLine; import java.util.List; import java.util.Optional; +import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; @@ -34,6 +37,76 @@ ) public class ZSub implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + KeyExpr keyExpr = KeyExpr.tryFrom(this.key); + + // Subscribers can be declared in different ways. + // Uncomment one of the lines below to try out different implementations: + subscribeWithBlockingQueue(config, keyExpr); + // subscribeWithCallback(config, keyExpr); + // subscribeWithHandler(config, keyExpr); + + return 0; + } + + /** + * Default implementation using a blocking queue to handle incoming samples. + */ + private void subscribeWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { + try (Session session = Zenoh.open(config)) { + try (Subscriber>> subscriber = session.declareSubscriber(keyExpr)) { + BlockingQueue> receiver = subscriber.getReceiver(); + assert receiver != null; + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + handleSample(wrapper.get()); + } + } + } + } + + /** + * Example using a callback to handle incoming samples asynchronously. + * @see io.zenoh.handlers.Callback + */ + private void subscribeWithCallback(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + session.declareSubscriber(keyExpr, this::handleSample); + } + } + + /** + * Example using a custom implementation of the Handler. + * @see QueueHandler + * @see Handler + */ + private void subscribeWithHandler(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + QueueHandler queueHandler = new QueueHandler<>(); + session.declareSubscriber(keyExpr, queueHandler); + } + } + + /** + * Handles a single Sample and prints relevant information. + */ + private void handleSample(Sample sample) { + String attachment = sample.getAttachment() != null ? ", with attachment: " + sample.getAttachment() : ""; + System.out.println(">> [Subscriber] Received " + sample.getKind() + + " ('" + sample.getKeyExpr() + "': '" + sample.getPayload() + "'" + attachment + ")"); + } + + /** + * ----- Example arguments and private fields ----- + */ + private final Boolean emptyArgs; ZSub(Boolean emptyArgs) { @@ -81,40 +154,6 @@ public class ZSub implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExpr = KeyExpr.tryFrom(key); - System.out.println("Declaring Subscriber on '" + keyExpr + "'..."); - try (Subscriber>> subscriber = session.declareSubscriber(keyExpr)) { - BlockingQueue> receiver = subscriber.getReceiver(); - assert receiver != null; - System.out.println("Press CTRL-C to quit..."); - while (true) { - Optional wrapper = receiver.take(); - if (wrapper.isEmpty()) { - break; - } - Sample sample = wrapper.get(); - String attachment = sample.getAttachment() != null ? ", with attachment: " + sample.getAttachment() : ""; - System.out.println(">> [Subscriber] Received " + sample.getKind() + - " ('" + sample.getKeyExpr() + "': '" + sample.getPayload() + "'" + attachment + ")"); - } - } - - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZSub(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZSubLiveliness.java b/examples/src/main/java/io/zenoh/ZSubLiveliness.java index 5176b263..d3b6fc86 100644 --- a/examples/src/main/java/io/zenoh/ZSubLiveliness.java +++ b/examples/src/main/java/io/zenoh/ZSubLiveliness.java @@ -36,6 +36,89 @@ ) public class ZSubLiveliness implements Callable { + @Override + public Integer call() throws Exception { + Zenoh.initLogFromEnvOr("error"); + + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + KeyExpr keyExpr = KeyExpr.tryFrom(this.key); + + // Subscribing to liveliness tokens can be implemented in multiple ways. + // Uncomment the desired implementation: + subscribeToLivelinessWithBlockingQueue(config, keyExpr); + // subscribeToLivelinessWithCallback(config, keyExpr); + // subscribeToLivelinessWithHandler(config, keyExpr); + + return 0; + } + + /** + * Default implementation using a blocking queue to handle incoming liveliness tokens. + */ + private void subscribeToLivelinessWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { + try (Session session = Zenoh.open(config)) { + Subscriber>> subscriber = + session.liveliness().declareSubscriber(keyExpr, new Liveliness.SubscriberConfig().history(history)); + + BlockingQueue> receiver = subscriber.getReceiver(); + System.out.println("Listening for liveliness tokens..."); + while (true) { + Optional wrapper = receiver.take(); + if (wrapper.isEmpty()) { + break; + } + handleLivelinessSample(wrapper.get()); + } + } + } + + /** + * Example using a callback to handle incoming liveliness tokens asynchronously. + * + * @see io.zenoh.handlers.Callback + */ + private void subscribeToLivelinessWithCallback(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + session.liveliness().declareSubscriber( + keyExpr, + this::handleLivelinessSample, + new Liveliness.SubscriberConfig().history(history) + ); + } + } + + /** + * Example using a handler to handle incoming liveliness tokens asynchronously. + * + * @see io.zenoh.handlers.Handler + * @see QueueHandler + */ + private void subscribeToLivelinessWithHandler(Config config, KeyExpr keyExpr) throws ZError { + try (Session session = Zenoh.open(config)) { + QueueHandler queueHandler = new QueueHandler<>(); + session.liveliness().declareSubscriber( + keyExpr, + queueHandler, + new Liveliness.SubscriberConfig().history(history) + ); + } + } + + /** + * Handles a single liveliness token sample. + */ + private void handleLivelinessSample(Sample sample) { + if (sample.getKind() == SampleKind.PUT) { + System.out.println(">> [LivelinessSubscriber] New alive token ('" + sample.getKeyExpr() + "')"); + } else if (sample.getKind() == SampleKind.DELETE) { + System.out.println(">> [LivelinessSubscriber] Dropped token ('" + sample.getKeyExpr() + "')"); + } + } + + /** + * ----- Example arguments and private fields ----- + */ + private final Boolean emptyArgs; ZSubLiveliness(Boolean emptyArgs) { @@ -90,41 +173,6 @@ public class ZSubLiveliness implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws Exception { - Zenoh.initLogFromEnvOr("error"); - - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - - System.out.println("Opening session..."); - try (Session session = Zenoh.open(config)) { - try (KeyExpr keyExpr = KeyExpr.tryFrom(key)) { - Subscriber>> subscriber = - session.liveliness().declareSubscriber(keyExpr, new Liveliness.SubscriberConfig().history(history)); - - BlockingQueue> receiver = subscriber.getReceiver(); - System.out.println("Listening for liveliness tokens..."); - while (true) { - Optional wrapper = receiver.take(); - if (wrapper.isEmpty()) { - break; - } - - Sample sample = wrapper.get(); - if (sample.getKind() == SampleKind.PUT) { - System.out.println(">> [LivelinessSubscriber] New alive token ('" + sample.getKeyExpr() + "')"); - } else if (sample.getKind() == SampleKind.DELETE) { - System.out.println(">> [LivelinessSubscriber] Dropped token ('" + sample.getKeyExpr() + "')"); - } - } - } - } catch (ZError e) { - System.err.println("Error during Zenoh operation: " + e.getMessage()); - return 1; - } - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZSubLiveliness(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index 0f3d1201..ebd74c8c 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -31,68 +31,6 @@ ) public class ZSubThr implements Callable { - private final Boolean emptyArgs; - - ZSubThr(Boolean emptyArgs) { - this.emptyArgs = emptyArgs; - } - - private static final long NANOS_TO_SEC = 1_000_000_000L; - private long batchCount = 0; - private long count = 0; - private long startTimestampNs = 0; - private long globalStartTimestampNs = 0; - - @CommandLine.Option( - names = {"-s", "--samples"}, - description = "Number of throughput measurements [default: 10].", - defaultValue = "10" - ) - private long samples; - - @CommandLine.Option( - names = {"-n", "--number"}, - description = "Number of messages in each throughput measurement [default: 100000].", - defaultValue = "100000" - ) - private long number; - - @CommandLine.Option( - names = {"-c", "--config"}, - description = "A configuration file." - ) - private String configFile; - - @CommandLine.Option( - names = {"-e", "--connect"}, - description = "Endpoints to connect to.", - split = "," - ) - private List connect; - - @CommandLine.Option( - names = {"-l", "--listen"}, - description = "Endpoints to listen on.", - split = "," - ) - private List listen; - - @CommandLine.Option( - names = {"-m", "--mode"}, - description = "The session mode. Default: peer. Possible values: [peer, client, router].", - defaultValue = "peer" - ) - private String mode; - - @CommandLine.Option( - names = {"--no-multicast-scouting"}, - description = "Disable the multicast-based scouting mechanism.", - defaultValue = "false" - ) - private boolean noMulticastScouting; - - private Subscriber subscriber; - @Override public Integer call() throws Exception { Zenoh.initLogFromEnvOr("error"); @@ -165,6 +103,73 @@ private void closeSubscriber() { } } + + /** + * ----- Example arguments and private fields ----- + */ + + private final Boolean emptyArgs; + + ZSubThr(Boolean emptyArgs) { + this.emptyArgs = emptyArgs; + } + + private static final long NANOS_TO_SEC = 1_000_000_000L; + private long batchCount = 0; + private long count = 0; + private long startTimestampNs = 0; + private long globalStartTimestampNs = 0; + + @CommandLine.Option( + names = {"-s", "--samples"}, + description = "Number of throughput measurements [default: 10].", + defaultValue = "10" + ) + private long samples; + + @CommandLine.Option( + names = {"-n", "--number"}, + description = "Number of messages in each throughput measurement [default: 100000].", + defaultValue = "100000" + ) + private long number; + + @CommandLine.Option( + names = {"-c", "--config"}, + description = "A configuration file." + ) + private String configFile; + + @CommandLine.Option( + names = {"-e", "--connect"}, + description = "Endpoints to connect to.", + split = "," + ) + private List connect; + + @CommandLine.Option( + names = {"-l", "--listen"}, + description = "Endpoints to listen on.", + split = "," + ) + private List listen; + + @CommandLine.Option( + names = {"-m", "--mode"}, + description = "The session mode. Default: peer. Possible values: [peer, client, router].", + defaultValue = "peer" + ) + private String mode; + + @CommandLine.Option( + names = {"--no-multicast-scouting"}, + description = "Disable the multicast-based scouting mechanism.", + defaultValue = "false" + ) + private boolean noMulticastScouting; + + private Subscriber subscriber; + public static void main(String[] args) { int exitCode = new CommandLine(new ZSubThr(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 5df70feb..632857a1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -171,8 +171,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * TODO */ - fun declareQueryable(keyExpr: KeyExpr): Queryable>> { - return resolveQueryableWithHandler(keyExpr, QueryableHandlerConfig(BlockingQueueHandler(LinkedBlockingDeque()))) + @Throws(ZError::class) + @JvmOverloads + fun declareQueryable( + keyExpr: KeyExpr, + config: QueryableConfig = QueryableConfig() + ): Queryable>> { + return resolveQueryableWithHandler(keyExpr, BlockingQueueHandler(LinkedBlockingDeque()), config) } /** @@ -180,8 +185,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * TODO */ - fun declareQueryable(keyExpr: KeyExpr, config: QueryableHandlerConfig): Queryable { - return resolveQueryableWithHandler(keyExpr, config) + @Throws(ZError::class) + @JvmOverloads + fun declareQueryable(keyExpr: KeyExpr, handler: Handler, config: QueryableConfig = QueryableConfig()): Queryable { + return resolveQueryableWithHandler(keyExpr, handler, config) } /** @@ -189,8 +196,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * TODO */ - fun declareQueryable(keyExpr: KeyExpr, config: QueryableCallbackConfig): Queryable { - return resolveQueryableWithCallback(keyExpr, config) + @Throws(ZError::class) + @JvmOverloads + fun declareQueryable(keyExpr: KeyExpr, callback: Callback, config: QueryableConfig = QueryableConfig()): Queryable { + return resolveQueryableWithCallback(keyExpr, callback, config) } /** @@ -375,10 +384,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithHandler( - keyExpr: KeyExpr, config: QueryableHandlerConfig + keyExpr: KeyExpr, handler: Handler, config: QueryableConfig ): Queryable { return jniSession?.run { - val queryable = declareQueryableWithHandler(keyExpr, config) + val queryable = declareQueryableWithHandler(keyExpr, handler, config) declarations.add(queryable) queryable } ?: throw (sessionClosedException) @@ -386,10 +395,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithCallback( - keyExpr: KeyExpr, config: QueryableCallbackConfig + keyExpr: KeyExpr, callback: Callback, config: QueryableConfig ): Queryable { return jniSession?.run { - val queryable = declareQueryableWithCallback(keyExpr, config) + val queryable = declareQueryableWithCallback(keyExpr, callback, config) declarations.add(queryable) queryable } ?: throw (sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 2807f778..65f80140 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -136,7 +136,7 @@ internal class JNISession { @Throws(ZError::class) fun declareQueryableWithCallback( - keyExpr: KeyExpr, config: QueryableCallbackConfig + keyExpr: KeyExpr, callback: Callback, config: QueryableConfig ): Queryable { val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> @@ -155,7 +155,7 @@ internal class JNISession { attachmentBytes?.into(), jniQuery ) - config.callback.run(query) + callback.run(query) } val queryableRawPtr = declareQueryableViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, @@ -170,10 +170,10 @@ internal class JNISession { @Throws(ZError::class) fun declareQueryableWithHandler( - keyExpr: KeyExpr, config: QueryableHandlerConfig + keyExpr: KeyExpr, handler: Handler, config: QueryableConfig ): Queryable { val resolvedOnClose: (() -> Unit) = fun() { - config.handler.onClose() + handler.onClose() config.onClose?.run() } val queryCallback = @@ -193,7 +193,7 @@ internal class JNISession { attachmentBytes?.into(), jniQuery ) - config.handler.handle(query) + handler.handle(query) } val queryableRawPtr = declareQueryableViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, @@ -203,7 +203,7 @@ internal class JNISession { resolvedOnClose, config.complete ) - return Queryable(keyExpr, config.handler.receiver(), JNIQueryable(queryableRawPtr)) + return Queryable(keyExpr, handler.receiver(), JNIQueryable(queryableRawPtr)) } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index 72eccc42..1f9696cd 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -93,25 +93,10 @@ class Queryable internal constructor( /** * TODO: add doc */ -data class QueryableCallbackConfig( - var callback: Callback, -) { - var complete: Boolean = false +data class QueryableConfig( + var complete: Boolean = false, var onClose: Runnable? = null - - fun complete(complete: Boolean) = apply { this.complete = complete } - fun onClose(onClose: Runnable) = apply { this.onClose = onClose } -} - -/** - * TODO: add doc - */ -data class QueryableHandlerConfig( - var handler: Handler, ) { - var complete: Boolean = false - var onClose: Runnable? = null - fun complete(complete: Boolean) = apply { this.complete = complete } fun onClose(onClose: Runnable) = apply { this.onClose = onClose } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index 5928b89e..c8b004ba 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -70,7 +70,7 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { Selector test1 = Selector.tryFrom("example/testing/reply_success"); Selector test2 = Selector.tryFrom("example/testing/reply_success_with_schema"); - var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> + var queryable = session.declareQueryable(keyExpr, query -> { try { KeyExpr queryKeyExpr = query.getKeyExpr(); @@ -83,7 +83,7 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { throw new RuntimeException(e); } } - )); + ); // Testing with null schema on a reply success scenario. Sample[] receivedSample = new Sample[1]; @@ -119,7 +119,7 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { Selector test2 = Selector.tryFrom("example/testing/reply_error_with_schema"); ZBytes replyPayload = ZBytes.from("test"); - var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> + var queryable = session.declareQueryable(keyExpr, query -> { KeyExpr keyExpr1 = query.getKeyExpr(); try { @@ -131,7 +131,7 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { } catch (Exception e) { throw new RuntimeException(e); } - })); + }); // Testing with null schema on a reply error scenario. ZBytes[] errorMessage = new ZBytes[1]; @@ -177,11 +177,11 @@ public void encoding_queryTest() throws ZError, InterruptedException { Selector selector = Selector.tryFrom("example/testing/keyexpr"); Encoding[] receivedEncoding = new Encoding[1]; - var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> + var queryable = session.declareQueryable(keyExpr, query -> { receivedEncoding[0] = query.getEncoding(); query.close(); - })); + }); // Testing with null schema session.get(selector, new GetConfig().payload(payload).encoding(without_schema)); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index b9031065..b5c323ec 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -34,15 +34,15 @@ public class GetTest { public void setUp() throws ZError { session = Zenoh.open(Config.loadDefault()); selector = Selector.tryFrom("example/testing/keyexpr"); - queryable = session.declareQueryable(selector.getKeyExpr(), new QueryableCallbackConfig(query -> - { - try { - query.reply(query.getKeyExpr(), payload, new ReplyConfig().timestamp(timestamp)); - } catch (ZError e) { - throw new RuntimeException(e); - } - } - )); + queryable = session.declareQueryable(selector.getKeyExpr(), query -> + { + try { + query.reply(query.getKeyExpr(), payload, new ReplyConfig().timestamp(timestamp)); + } catch (ZError e) { + throw new RuntimeException(e); + } + } + ); } @After @@ -80,9 +80,9 @@ public void get_runsWithHandlerTest() throws ZError { public void getWithSelectorParamsTest() throws ZError { Parameters[] receivedParams = new Parameters[1]; - Queryable queryable = session.declareQueryable(selector.getKeyExpr(), new QueryableCallbackConfig(query -> - receivedParams[0] = query.getParameters() - )); + Queryable queryable = session.declareQueryable(selector.getKeyExpr(), query -> + receivedParams[0] = query.getParameters() + ); Parameters params = Parameters.from("arg1=val1&arg2=val2&arg3"); Selector selectorWithParams = new Selector(selector.getKeyExpr(), params); @@ -94,7 +94,9 @@ public void getWithSelectorParamsTest() throws ZError { } } -/** A dummy handler for get operations. */ +/** + * A dummy handler for get operations. + */ class TestHandler implements Handler> { static final ArrayList performedReplies = new ArrayList<>(); @@ -110,5 +112,6 @@ public ArrayList receiver() { } @Override - public void onClose() {} + public void onClose() { + } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index 5d51d6bf..d56e2301 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -59,7 +59,7 @@ public void queryableRunsWithCallback() throws ZError { null ); - var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> + var queryable = session.declareQueryable(testKeyExpr, query -> { try { query.reply(testKeyExpr, testPayload, new ReplyConfig() @@ -70,8 +70,7 @@ public void queryableRunsWithCallback() throws ZError { } catch (ZError e) { throw new RuntimeException(e); } - } - )); + }); Reply[] reply = new Reply[1]; session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); @@ -84,8 +83,7 @@ public void queryableRunsWithCallback() throws ZError { @Test public void queryableRunsWithHandler() throws ZError, InterruptedException { - var config = new QueryableHandlerConfig<>(new QueryHandler()); - var queryable = session.declareQueryable(testKeyExpr, config); + var queryable = session.declareQueryable(testKeyExpr, new QueryHandler()); Thread.sleep(500); @@ -101,8 +99,7 @@ public void queryableRunsWithHandler() throws ZError, InterruptedException { @Test public void queryTest() throws ZError, InterruptedException { Query[] receivedQuery = new Query[1]; - var config = new QueryableCallbackConfig(query -> receivedQuery[0] = query); - var queryable = session.declareQueryable(testKeyExpr, config); + var queryable = session.declareQueryable(testKeyExpr, query -> receivedQuery[0] = query); session.get(testKeyExpr); @@ -134,7 +131,8 @@ public void queryTest() throws ZError, InterruptedException { public void queryReplySuccessTest() throws ZError { var message = ZBytes.from("Test message"); var timestamp = TimeStamp.getCurrentTime(); - QueryableCallbackConfig config = new QueryableCallbackConfig(query -> { + + Queryable queryable = session.declareQueryable(testKeyExpr, query -> { try { query.reply(testKeyExpr, message, new ReplyConfig() .timestamp(timestamp) @@ -146,8 +144,6 @@ public void queryReplySuccessTest() throws ZError { } }); - Queryable queryable = session.declareQueryable(testKeyExpr, config); - Reply[] receivedReply = new Reply[1]; session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); @@ -168,7 +164,7 @@ public void queryReplySuccessTest() throws ZError { public void queryReplyErrorTest() throws ZError, InterruptedException { var errorMessage = ZBytes.from("Error message"); - var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> + var queryable = session.declareQueryable(testKeyExpr, query -> { try { query.replyErr(errorMessage); @@ -176,7 +172,7 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { throw new RuntimeException(e); } } - )); + ); Reply[] receivedReply = new Reply[1]; session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); @@ -195,7 +191,7 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { public void queryReplyDeleteTest() throws ZError, InterruptedException { var timestamp = TimeStamp.getCurrentTime(); - var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { + var queryable = session.declareQueryable(testKeyExpr, query -> { try { var config = new ReplyDelConfig(); config.setTimeStamp(timestamp); @@ -203,7 +199,7 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { } catch (ZError e) { throw new RuntimeException(e); } - })); + }); Reply[] receivedReply = new Reply[1]; session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); @@ -222,8 +218,7 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { @Test public void onCloseTest() throws InterruptedException, ZError { AtomicReference onCloseWasCalled = new AtomicReference<>(false); - var queryable = session.declareQueryable(testKeyExpr, new QueryableCallbackConfig(query -> { - }).onClose(() -> onCloseWasCalled.set(true))); + var queryable = session.declareQueryable(testKeyExpr, new QueryableConfig().onClose(() -> onCloseWasCalled.set(true))); queryable.undeclare(); Thread.sleep(1000); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index d096a4f2..6e0ea776 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -21,7 +21,6 @@ import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.query.GetConfig; -import io.zenoh.query.QueryableCallbackConfig; import io.zenoh.query.Reply; import io.zenoh.query.ReplyConfig; import io.zenoh.sample.Sample; @@ -145,14 +144,14 @@ public void publisherDeleteWithoutAttachmentTest() throws ZError { @Test public void queryWithAttachmentTest() throws ZError { ZBytes[] receivedAttachment = new ZBytes[1]; - var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { + var queryable = session.declareQueryable(keyExpr, query -> { receivedAttachment[0] = query.getAttachment(); try { query.reply(keyExpr, payload); } catch (ZError e) { throw new RuntimeException(e); } - })); + }); session.get(keyExpr, new GetConfig().attachment(attachment).timeout(Duration.ofMillis(1000))); @@ -165,13 +164,13 @@ public void queryWithAttachmentTest() throws ZError { @Test public void queryReplyWithAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; - var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { + var queryable = session.declareQueryable(keyExpr, query -> { try { query.reply(keyExpr, payload, new ReplyConfig().attachment(attachment)); } catch (ZError e) { throw new RuntimeException(e); } - })); + }); session.get(keyExpr, reply1 -> reply[0] = reply1, new GetConfig().attachment(attachment).timeout(Duration.ofMillis(1000))); @@ -186,13 +185,13 @@ public void queryReplyWithAttachmentTest() throws ZError { @Test public void queryReplyWithoutAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; - var queryable = session.declareQueryable(keyExpr, new QueryableCallbackConfig(query -> { + var queryable = session.declareQueryable(keyExpr, query -> { try { query.reply(keyExpr, payload); } catch (ZError e) { throw new RuntimeException(e); } - })); + }); session.get(keyExpr, reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); queryable.close(); From e18807a856ce8e725729a24cf894d7ffae78573f Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Mon, 2 Dec 2024 10:57:00 -0300 Subject: [PATCH 65/83] Alignment: fix publisher put encoding fallback --- examples/src/main/java/io/zenoh/ZDelete.java | 31 ++++++++------ examples/src/main/java/io/zenoh/ZGet.java | 2 + .../kotlin/io/zenoh/jni/JNISession.kt | 5 ++- .../pubsub/{Delete.kt => DeleteConfig.kt} | 0 .../kotlin/io/zenoh/pubsub/Publisher.kt | 32 ++++----------- .../kotlin/io/zenoh/pubsub/PublisherConfig.kt | 41 +++++++++++++++++++ .../io/zenoh/pubsub/{Put.kt => PutConfig.kt} | 2 +- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 5 --- .../io/zenoh/pubsub/SubscriberConfig.kt | 20 +++++++++ 9 files changed, 93 insertions(+), 45 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/{Delete.kt => DeleteConfig.kt} (100%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt rename zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/{Put.kt => PutConfig.kt} (96%) create mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt diff --git a/examples/src/main/java/io/zenoh/ZDelete.java b/examples/src/main/java/io/zenoh/ZDelete.java index 13d0063e..03afce62 100644 --- a/examples/src/main/java/io/zenoh/ZDelete.java +++ b/examples/src/main/java/io/zenoh/ZDelete.java @@ -30,6 +30,24 @@ ) public class ZDelete implements Callable { + @Override + public Integer call() throws ZError { + Zenoh.initLogFromEnvOr("error"); + System.out.println("Opening session..."); + Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); + try (Session session = Zenoh.open(config)) { + KeyExpr keyExpr = KeyExpr.tryFrom(key); + System.out.println("Deleting resources matching '" + keyExpr + "'..."); + session.delete(keyExpr); + } + return 0; + } + + + /** + * ----- Example CLI arguments and private fields ----- + */ + private final Boolean emptyArgs; ZDelete(Boolean emptyArgs) { @@ -77,19 +95,6 @@ public class ZDelete implements Callable { ) private boolean noMulticastScouting; - @Override - public Integer call() throws ZError { - Zenoh.initLogFromEnvOr("error"); - System.out.println("Opening session..."); - Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); - try (Session session = Zenoh.open(config)) { - KeyExpr keyExpr = KeyExpr.tryFrom(key); - System.out.println("Deleting resources matching '" + keyExpr + "'..."); - session.delete(keyExpr); - } - return 0; - } - public static void main(String[] args) { int exitCode = new CommandLine(new ZDelete(args.length == 0)).execute(args); System.exit(exitCode); diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index 704ab587..3810c4d9 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -137,9 +137,11 @@ private void handleReply(Reply reply) { } } + /** * ----- Example CLI arguments and private fields ----- */ + private final Boolean emptyArgs; ZGet(Boolean emptyArgs) { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 65f80140..dd67281a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -352,13 +352,14 @@ internal class JNISession { payload: IntoZBytes, config: PutConfig, ) { + val encoding = config.encoding ?: Encoding.defaultEncoding() putViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), payload.into().bytes, - config.encoding.id, - config.encoding.schema, + encoding.id, + encoding.schema, config.qos.congestionControl.value, config.qos.priority.value, config.qos.express, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteConfig.kt similarity index 100% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Delete.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteConfig.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 615bc900..4529916f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -23,7 +23,6 @@ import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS -import io.zenoh.qos.Reliability import io.zenoh.session.SessionDeclaration import kotlin.Throws @@ -80,10 +79,15 @@ class Publisher internal constructor( fun priority() = qos.priority /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ - @JvmOverloads @Throws(ZError::class) - fun put(payload: IntoZBytes, config: PutConfig = PutConfig()) { - jniPublisher?.put(payload, config.encoding, config.attachment) ?: throw publisherNotValid + fun put(payload: IntoZBytes) { + jniPublisher?.put(payload, encoding, null) ?: throw publisherNotValid + } + + /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ + @Throws(ZError::class) + fun put(payload: IntoZBytes, config: PutConfig) { + jniPublisher?.put(payload, config.encoding ?: this.encoding, config.attachment) ?: throw publisherNotValid } /** @@ -118,23 +122,3 @@ class Publisher internal constructor( jniPublisher?.close() } } - -/** - * TODO - */ -data class PublisherConfig(var reliability: Reliability = Reliability.RELIABLE, - var qos: QoS = QoS.defaultQoS(), - var encoding: Encoding = Encoding.defaultEncoding()) { - - fun reliability(reliability: Reliability) = apply { this.reliability = reliability } - - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } - - fun qos(qos: QoS) = apply { this.qos = qos } - - fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } - - fun express(express: Boolean) = apply { this.qos.express = express } - - fun priority(priority: Priority) = apply { this.qos.priority = priority } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt new file mode 100644 index 00000000..cfa63615 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt @@ -0,0 +1,41 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.pubsub + +import io.zenoh.bytes.Encoding +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority +import io.zenoh.qos.QoS +import io.zenoh.qos.Reliability + +/** + * TODO + */ +data class PublisherConfig(var reliability: Reliability = Reliability.RELIABLE, + var qos: QoS = QoS.defaultQoS(), + var encoding: Encoding = Encoding.defaultEncoding()) { + + fun reliability(reliability: Reliability) = apply { this.reliability = reliability } + + fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + + fun qos(qos: QoS) = apply { this.qos = qos } + + fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } + + fun express(express: Boolean) = apply { this.qos.express = express } + + fun priority(priority: Priority) = apply { this.qos.priority = priority } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutConfig.kt similarity index 96% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutConfig.kt index 79e369b6..1d8c1703 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Put.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutConfig.kt @@ -25,7 +25,7 @@ import io.zenoh.qos.Reliability * TODO */ data class PutConfig( - var encoding: Encoding = Encoding.defaultEncoding(), + var encoding: Encoding? = null, var qos: QoS = QoS.defaultQoS(), var reliability: Reliability = Reliability.RELIABLE, var attachment: IntoZBytes? = null diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index 529369d2..6363fd70 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -49,8 +49,3 @@ class Subscriber internal constructor( jniSubscriber?.close() } } - -data class SubscriberConfig(var onClose: Runnable? = null) { - - fun onClose(onClose: Runnable) = apply { this.onClose = onClose } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt new file mode 100644 index 00000000..0653d4ca --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt @@ -0,0 +1,20 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.pubsub + +data class SubscriberConfig(var onClose: Runnable? = null) { + + fun onClose(onClose: Runnable) = apply { this.onClose = onClose } +} From 997108aa68e841903109e9f8c453d428413c17d6 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 4 Dec 2024 13:01:59 -0300 Subject: [PATCH 66/83] Alignment: removing SubscriberConfig.kt --- examples/src/main/java/io/zenoh/ZGet.java | 6 ------ examples/src/main/java/io/zenoh/ZSub.java | 2 -- .../kotlin/io/zenoh/jni/JNISession.kt | 19 ++++++------------ .../io/zenoh/pubsub/SubscriberConfig.kt | 20 ------------------- 4 files changed, 6 insertions(+), 41 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index 3810c4d9..c0365670 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -112,12 +112,6 @@ private void getExampleProvidingConfig(Config config, Selector selector) throws getConfig.setEncoding(Encoding.ZENOH_STRING); getConfig.setPayload(ZBytes.from("Example payload")); - // Note the syntax below is valid as well - GetConfig getConfig2 = new GetConfig() - .timeout(Duration.ofMillis(1000)) - .encoding(Encoding.ZENOH_STRING) - .payload(ZBytes.from("Example payload")); - // Apply the config session.get(selector, this::handleReply, getConfig); } diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index 54c92a2d..a7c4c274 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -18,13 +18,11 @@ import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Subscriber; -import io.zenoh.pubsub.SubscriberConfig; import io.zenoh.sample.Sample; import picocli.CommandLine; import java.util.List; import java.util.Optional; -import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index dd67281a..112e897a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -81,7 +81,7 @@ internal class JNISession { @Throws(ZError::class) fun declareSubscriberWithHandler( - keyExpr: KeyExpr, handler: Handler, config: SubscriberConfig + keyExpr: KeyExpr, handler: Handler ): Subscriber { val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> @@ -98,17 +98,14 @@ internal class JNISession { handler.handle(sample) } val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, fun() { - handler.onClose() - config.onClose?.run() - } + keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, handler::onClose ) return Subscriber(keyExpr, handler.receiver(), JNISubscriber(subscriberRawPtr)) } @Throws(ZError::class) fun declareSubscriberWithCallback( - keyExpr: KeyExpr, callback: Callback, config: SubscriberConfig + keyExpr: KeyExpr, callback: Callback ): Subscriber { val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> @@ -129,7 +126,7 @@ internal class JNISession { keyExpr.keyExpr, sessionPtr.get(), subCallback, - fun() { config.onClose?.run() } + fun() {} ) return Subscriber(keyExpr, null, JNISubscriber(subscriberRawPtr)) } @@ -162,7 +159,7 @@ internal class JNISession { keyExpr.keyExpr, sessionPtr.get(), queryCallback, - fun() { config.onClose?.run() }, + fun() {}, config.complete ) return Queryable(keyExpr, null, JNIQueryable(queryableRawPtr)) @@ -172,10 +169,6 @@ internal class JNISession { fun declareQueryableWithHandler( keyExpr: KeyExpr, handler: Handler, config: QueryableConfig ): Queryable { - val resolvedOnClose: (() -> Unit) = fun() { - handler.onClose() - config.onClose?.run() - } val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> val jniQuery = JNIQuery(queryPtr) @@ -200,7 +193,7 @@ internal class JNISession { keyExpr.keyExpr, sessionPtr.get(), queryCallback, - resolvedOnClose, + handler::onClose, config.complete ) return Queryable(keyExpr, handler.receiver(), JNIQueryable(queryableRawPtr)) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt deleted file mode 100644 index 0653d4ca..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/SubscriberConfig.kt +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.pubsub - -data class SubscriberConfig(var onClose: Runnable? = null) { - - fun onClose(onClose: Runnable) = apply { this.onClose = onClose } -} From 4e1bc019aafe03cf997b4af5ba6c5621e53b13c7 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 4 Dec 2024 13:13:28 -0300 Subject: [PATCH 67/83] Alignment: renaming PublisherConfig to PublisherOptions --- examples/src/main/java/io/zenoh/ZPing.java | 4 +- examples/src/main/java/io/zenoh/ZPong.java | 4 +- examples/src/main/java/io/zenoh/ZPub.java | 10 +++-- examples/src/main/java/io/zenoh/ZPubThr.java | 4 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 43 +++++-------------- .../kotlin/io/zenoh/jni/JNISession.kt | 14 +++--- ...PublisherConfig.kt => PublisherOptions.kt} | 6 +-- .../jvmTest/java/io/zenoh/PublisherTest.java | 4 +- 8 files changed, 35 insertions(+), 54 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/{PublisherConfig.kt => PublisherOptions.kt} (83%) diff --git a/examples/src/main/java/io/zenoh/ZPing.java b/examples/src/main/java/io/zenoh/ZPing.java index e2c7b409..8cacb161 100644 --- a/examples/src/main/java/io/zenoh/ZPing.java +++ b/examples/src/main/java/io/zenoh/ZPing.java @@ -18,7 +18,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; -import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.PublisherOptions; import io.zenoh.qos.CongestionControl; import io.zenoh.sample.Sample; import picocli.CommandLine; @@ -53,7 +53,7 @@ public Integer call() throws Exception { BlockingQueue> receiverQueue = session.declareSubscriber(keyExprPong).getReceiver(); Publisher publisher = - session.declarePublisher(keyExprPing, new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress)); + session.declarePublisher(keyExprPing, new PublisherOptions().congestionControl(CongestionControl.BLOCK).express(!noExpress)); byte[] data = new byte[payloadSize]; for (int i = 0; i < payloadSize; i++) { diff --git a/examples/src/main/java/io/zenoh/ZPong.java b/examples/src/main/java/io/zenoh/ZPong.java index 0527d595..0a24c3dc 100644 --- a/examples/src/main/java/io/zenoh/ZPong.java +++ b/examples/src/main/java/io/zenoh/ZPong.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; -import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.PublisherOptions; import io.zenoh.qos.CongestionControl; import picocli.CommandLine; @@ -47,7 +47,7 @@ public Integer call() throws Exception { Publisher publisher = session.declarePublisher( keyExprPong, - new PublisherConfig().congestionControl(CongestionControl.BLOCK).express(!noExpress) + new PublisherOptions().congestionControl(CongestionControl.BLOCK).express(!noExpress) ); session.declareSubscriber(keyExprPing, sample -> { diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index 78f8c1da..796be4ea 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -19,7 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; -import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.PublisherOptions; import io.zenoh.pubsub.PutConfig; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Reliability; @@ -48,13 +48,13 @@ public Integer call() throws ZError { System.out.println("Declaring publisher on '" + keyExpr + "'..."); // A publisher config can optionally be provided. - PublisherConfig publisherConfig = new PublisherConfig() + PublisherOptions publisherOptions = new PublisherOptions() // PublisherOpts .encoding(Encoding.ZENOH_STRING) .congestionControl(CongestionControl.BLOCK) .reliability(Reliability.RELIABLE); // Declare the publisher - Publisher publisher = session.declarePublisher(keyExpr, publisherConfig); + Publisher publisher = session.declarePublisher(keyExpr, publisherOptions); System.out.println("Press CTRL-C to quit..."); ZBytes attachmentBytes = attachment != null ? ZBytes.from(attachment) : null; @@ -64,7 +64,9 @@ public Integer call() throws ZError { String payload = String.format("[%4d] %s", idx, value); System.out.println("Putting Data ('" + keyExpr + "': '" + payload + "')..."); if (attachmentBytes != null) { - publisher.put(ZBytes.from(payload), new PutConfig().attachment(attachmentBytes)); + PutConfig putConfig = new PutConfig(); + putConfig.setAttachment(attachmentBytes); + publisher.put(ZBytes.from(payload), putConfig); } else { publisher.put(ZBytes.from(payload)); } diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index 98979926..f70f2fde 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -17,7 +17,7 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; -import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.PublisherOptions; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; import picocli.CommandLine; @@ -48,7 +48,7 @@ public Integer call() throws Exception { try (Session session = Zenoh.open(config)) { KeyExpr keyExpr = KeyExpr.tryFrom("test/thr"); - var publisherConfig = new PublisherConfig() + var publisherConfig = new PublisherOptions() .congestionControl(CongestionControl.BLOCK) .priority(priorityInput != null ? Priority.getEntries().get(priorityInput) : Priority.DATA); try (Publisher publisher = session.declarePublisher(keyExpr, publisherConfig)) { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 632857a1..8fc5fdb7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -101,15 +101,15 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * TODO */ - fun declarePublisher(keyExpr: KeyExpr): Publisher = declarePublisher(keyExpr, PublisherConfig()) + fun declarePublisher(keyExpr: KeyExpr): Publisher = declarePublisher(keyExpr, PublisherOptions()) /** * Declare a [Publisher] on the session. * * TODO */ - fun declarePublisher(keyExpr: KeyExpr, publisherConfig: PublisherConfig): Publisher { - return resolvePublisher(keyExpr, publisherConfig) + fun declarePublisher(keyExpr: KeyExpr, publisherOptions: PublisherOptions): Publisher { + return resolvePublisher(keyExpr, publisherOptions) } /** @@ -121,8 +121,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { return resolveSubscriberWithHandler( keyExpr, - BlockingQueueHandler(LinkedBlockingDeque()), - SubscriberConfig() + BlockingQueueHandler(LinkedBlockingDeque()) ) } @@ -133,17 +132,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun declareSubscriber(keyExpr: KeyExpr, handler: Handler): Subscriber { - return resolveSubscriberWithHandler(keyExpr, handler, SubscriberConfig()) - } - - /** - * Declare a [Subscriber] on the session. - * - * TODO - */ - @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, handler: Handler, config: SubscriberConfig): Subscriber { - return resolveSubscriberWithHandler(keyExpr, handler, config) + return resolveSubscriberWithHandler(keyExpr, handler) } /** @@ -153,17 +142,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun declareSubscriber(keyExpr: KeyExpr, callback: Callback): Subscriber { - return resolveSubscriberWithCallback(keyExpr, callback, SubscriberConfig()) - } - - /** - * Declare a [Subscriber] on the session. - * - * TODO - */ - @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, callback: Callback, config: SubscriberConfig): Subscriber { - return resolveSubscriberWithCallback(keyExpr, callback, config) + return resolveSubscriberWithCallback(keyExpr, callback) } /** @@ -352,7 +331,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolvePublisher(keyExpr: KeyExpr, config: PublisherConfig): Publisher { + internal fun resolvePublisher(keyExpr: KeyExpr, config: PublisherOptions): Publisher { return jniSession?.run { val publisher = declarePublisher(keyExpr, config) declarations.add(publisher) @@ -362,10 +341,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriberWithHandler( - keyExpr: KeyExpr, handler: Handler, config: SubscriberConfig + keyExpr: KeyExpr, handler: Handler ): Subscriber { return jniSession?.run { - val subscriber = declareSubscriberWithHandler(keyExpr, handler, config) + val subscriber = declareSubscriberWithHandler(keyExpr, handler) declarations.add(subscriber) subscriber } ?: throw (sessionClosedException) @@ -373,10 +352,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriberWithCallback( - keyExpr: KeyExpr, callback: Callback, config: SubscriberConfig + keyExpr: KeyExpr, callback: Callback ): Subscriber { return jniSession?.run { - val subscriber = declareSubscriberWithCallback(keyExpr, callback, config) + val subscriber = declareSubscriberWithCallback(keyExpr, callback) declarations.add(subscriber) subscriber } ?: throw (sessionClosedException) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 112e897a..0d0eb670 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -61,20 +61,20 @@ internal class JNISession { } @Throws(ZError::class) - fun declarePublisher(keyExpr: KeyExpr, publisherConfig: PublisherConfig): Publisher { + fun declarePublisher(keyExpr: KeyExpr, publisherOptions: PublisherOptions): Publisher { val publisherRawPtr = declarePublisherViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - publisherConfig.qos.congestionControl.value, - publisherConfig.qos.priority.value, - publisherConfig.qos.express, - publisherConfig.reliability.ordinal + publisherOptions.qos.congestionControl.value, + publisherOptions.qos.priority.value, + publisherOptions.qos.express, + publisherOptions.reliability.ordinal ) return Publisher( keyExpr, - publisherConfig.qos, - publisherConfig.encoding, + publisherOptions.qos, + publisherOptions.encoding, JNIPublisher(publisherRawPtr), ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt similarity index 83% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt index cfa63615..36ad4651 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherConfig.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt @@ -23,9 +23,9 @@ import io.zenoh.qos.Reliability /** * TODO */ -data class PublisherConfig(var reliability: Reliability = Reliability.RELIABLE, - var qos: QoS = QoS.defaultQoS(), - var encoding: Encoding = Encoding.defaultEncoding()) { +data class PublisherOptions(var reliability: Reliability = Reliability.RELIABLE, + var qos: QoS = QoS.defaultQoS(), + var encoding: Encoding = Encoding.defaultEncoding()) { fun reliability(reliability: Reliability) = apply { this.reliability = reliability } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 6353b1e3..24520b5d 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -4,7 +4,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; -import io.zenoh.pubsub.PublisherConfig; +import io.zenoh.pubsub.PublisherOptions; import io.zenoh.pubsub.PutConfig; import io.zenoh.qos.QoS; import io.zenoh.qos.Reliability; @@ -38,7 +38,7 @@ public void setUp() throws ZError { session = Zenoh.open(Config.loadDefault()); keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); - var config = new PublisherConfig(Reliability.RELIABLE, QoS.defaultQoS(), Encoding.ZENOH_STRING); + var config = new PublisherOptions(Reliability.RELIABLE, QoS.defaultQoS(), Encoding.ZENOH_STRING); publisher = session.declarePublisher(keyExpr, config); receivedSamples = new ArrayList<>(); From 7affa1953f880311c2bdbfba6368a37b83942605 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 4 Dec 2024 14:46:49 -0300 Subject: [PATCH 68/83] Alignment: renaming DeleteConfig to DeleteOptions and removing 'builder' functions in it. --- .../src/commonMain/kotlin/io/zenoh/Session.kt | 8 ++++---- .../kotlin/io/zenoh/jni/JNISession.kt | 2 +- .../{DeleteConfig.kt => DeleteOptions.kt} | 18 ++---------------- .../java/io/zenoh/UserAttachmentTest.java | 6 ++++-- 4 files changed, 11 insertions(+), 23 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/{DeleteConfig.kt => DeleteOptions.kt} (54%) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 8fc5fdb7..3500a995 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -301,13 +301,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO */ fun delete(keyExpr: KeyExpr) { - resolveDelete(keyExpr, DeleteConfig()) + resolveDelete(keyExpr, DeleteOptions()) } /** * TODO */ - fun delete(keyExpr: KeyExpr, config: DeleteConfig) { + fun delete(keyExpr: KeyExpr, config: DeleteOptions) { resolveDelete(keyExpr, config) } @@ -415,8 +415,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolveDelete(keyExpr: KeyExpr, deleteConfig: DeleteConfig) { - jniSession?.run { performDelete(keyExpr, deleteConfig) } + internal fun resolveDelete(keyExpr: KeyExpr, deleteOptions: DeleteOptions) { + jniSession?.run { performDelete(keyExpr, deleteOptions) } } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 0d0eb670..7b3e6def 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -364,7 +364,7 @@ internal class JNISession { @Throws(ZError::class) fun performDelete( keyExpr: KeyExpr, - config: DeleteConfig, + config: DeleteOptions, ) { deleteViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt similarity index 54% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteConfig.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt index f713bef1..0ee1898f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteConfig.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt @@ -15,28 +15,14 @@ package io.zenoh.pubsub import io.zenoh.bytes.IntoZBytes -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.qos.Reliability /** * TODO */ -data class DeleteConfig( +data class DeleteOptions( var qos: QoS = QoS.defaultQoS(), var reliability: Reliability = Reliability.RELIABLE, var attachment: IntoZBytes? = null -) { - fun qos(qos: QoS) = apply { this.qos = qos } - - fun reliability(reliability: Reliability) = apply { this.reliability = reliability } - - fun attachment(attachment: IntoZBytes?) = apply { this.attachment = attachment } - - fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } - - fun express(express: Boolean) = apply { this.qos.express = express } - - fun priority(priority: Priority) = apply { this.qos.priority = priority } -} +) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 6e0ea776..11a49cdf 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.ZBytes; -import io.zenoh.pubsub.DeleteConfig; +import io.zenoh.pubsub.DeleteOptions; import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; import io.zenoh.query.GetConfig; @@ -115,7 +115,9 @@ public void publisherDeleteWithAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - publisher.delete(new DeleteConfig().attachment(attachment)); + var deleteOptions = new DeleteOptions(); + deleteOptions.setAttachment(attachment); + publisher.delete(deleteOptions); publisher.close(); subscriber.close(); From 3b916ed65d916596c3667ba278aa4b9565d5010a Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 4 Dec 2024 15:02:11 -0300 Subject: [PATCH 69/83] Alignment: renaming GetConfig to GetOptions and removing 'builder' functions in it. --- examples/src/main/java/io/zenoh/ZGet.java | 14 +++--- .../src/commonMain/kotlin/io/zenoh/Session.kt | 16 +++---- .../kotlin/io/zenoh/jni/JNISession.kt | 8 ++-- .../kotlin/io/zenoh/pubsub/Publisher.kt | 2 +- .../commonMain/kotlin/io/zenoh/query/Get.kt | 45 ++----------------- .../jvmTest/java/io/zenoh/EncodingTest.java | 8 +++- .../src/jvmTest/java/io/zenoh/GetTest.java | 14 ++++-- .../jvmTest/java/io/zenoh/QueryableTest.java | 30 +++++-------- .../java/io/zenoh/UserAttachmentTest.java | 15 +++++-- 9 files changed, 62 insertions(+), 90 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index c0365670..f8491cf1 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -17,7 +17,7 @@ import io.zenoh.bytes.Encoding; import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; -import io.zenoh.query.GetConfig; +import io.zenoh.query.GetOptions; import io.zenoh.query.Selector; import io.zenoh.query.Reply; import io.zenoh.sample.SampleKind; @@ -100,20 +100,20 @@ private void getExampleWithHandler(Config config, Selector selector) throws ZErr /** * The purpose of this example is to show how to provide configuration parameters * to the get query. For this, you can optionally provide a GetConfig parameter. - * @see GetConfig + * @see GetOptions */ private void getExampleProvidingConfig(Config config, Selector selector) throws ZError { try (Session session = Zenoh.open(config)) { System.out.println("Performing Get on '" + selector + "'..."); // Build the config - GetConfig getConfig = new GetConfig(); - getConfig.setTimeout(Duration.ofMillis(1000)); - getConfig.setEncoding(Encoding.ZENOH_STRING); - getConfig.setPayload(ZBytes.from("Example payload")); + GetOptions getOptions = new GetOptions(); + getOptions.setTimeout(Duration.ofMillis(1000)); + getOptions.setEncoding(Encoding.ZENOH_STRING); + getOptions.setPayload(ZBytes.from("Example payload")); // Apply the config - session.get(selector, this::handleReply, getConfig); + session.get(selector, this::handleReply, getOptions); } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 3500a995..e87e6da1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -235,7 +235,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ fun get(selector: IntoSelector): BlockingQueue> { val handler = BlockingQueueHandler(LinkedBlockingDeque()) - val config = GetConfig() + val config = GetOptions() return resolveGetWithHandler( selector, handler, @@ -246,7 +246,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * TODO */ - fun get(selector: IntoSelector, config: GetConfig): BlockingQueue> { + fun get(selector: IntoSelector, config: GetOptions): BlockingQueue> { val handler = BlockingQueueHandler(LinkedBlockingDeque()) return resolveGetWithHandler( selector, @@ -259,13 +259,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO */ fun get(selector: IntoSelector, handler: Handler): R { - return resolveGetWithHandler(selector, handler, GetConfig()) + return resolveGetWithHandler(selector, handler, GetOptions()) } /** * TODO */ - fun get(selector: IntoSelector, handler: Handler, config: GetConfig): R { + fun get(selector: IntoSelector, handler: Handler, config: GetOptions): R { return resolveGetWithHandler(selector, handler, config) } @@ -273,13 +273,13 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO */ fun get(selector: IntoSelector, callback: Callback) { - return resolveGetWithCallback(selector, callback, GetConfig()) + return resolveGetWithCallback(selector, callback, GetOptions()) } /** * TODO */ - fun get(selector: IntoSelector, callback: Callback, config: GetConfig) { + fun get(selector: IntoSelector, callback: Callback, config: GetOptions) { return resolveGetWithCallback(selector, callback, config) } @@ -387,7 +387,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { internal fun resolveGetWithHandler( selector: IntoSelector, handler: Handler, - config: GetConfig + config: GetOptions ): R { return jniSession?.performGetWithHandler( selector, @@ -400,7 +400,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { internal fun resolveGetWithCallback( selector: IntoSelector, callback: Callback, - config: GetConfig + config: GetOptions ) { return jniSession?.performGetWithCallback( selector, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 7b3e6def..45eeef61 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -203,7 +203,7 @@ internal class JNISession { fun performGetWithCallback( intoSelector: IntoSelector, callback: Callback, - config: GetConfig + config: GetOptions ) { val getCallback = JNIGetCallback { replierId: ByteArray?, @@ -250,7 +250,7 @@ internal class JNISession { selector.parameters.toString(), sessionPtr.get(), getCallback, - fun() { config.onClose?.run() }, + fun() {}, config.timeout.toMillis(), config.target.ordinal, config.consolidation.ordinal, @@ -265,7 +265,7 @@ internal class JNISession { fun performGetWithHandler( intoSelector: IntoSelector, handler: Handler, - config: GetConfig + config: GetOptions ): R { val getCallback = JNIGetCallback { replierId: ByteArray?, @@ -312,7 +312,7 @@ internal class JNISession { selector.parameters.toString(), sessionPtr.get(), getCallback, - fun() { config.onClose?.run() }, + handler::onClose, config.timeout.toMillis(), config.target.ordinal, config.consolidation.ordinal, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 4529916f..fc311f06 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -97,7 +97,7 @@ class Publisher internal constructor( */ @JvmOverloads @Throws(ZError::class) - fun delete(config: DeleteConfig = DeleteConfig()) { + fun delete(config: DeleteOptions = DeleteOptions()) { jniPublisher?.delete(config.attachment) ?: throw(publisherNotValid) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index 850e8154..a970e39e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -23,50 +23,11 @@ import java.time.Duration * * TODO */ -data class GetConfig( +data class GetOptions( var timeout: Duration = Duration.ofMillis(10000), var target: QueryTarget = QueryTarget.BEST_MATCHING, var consolidation: ConsolidationMode = ConsolidationMode.AUTO, var payload: IntoZBytes? = null, var encoding: Encoding? = null, - var attachment: IntoZBytes? = null, - var onClose: Runnable? = null, -) { - - /** Specify the [QueryTarget]. */ - fun target(target: QueryTarget) = apply { - this.target = target - } - - /** Specify the [ConsolidationMode]. */ - fun consolidation(consolidation: ConsolidationMode) = apply { - this.consolidation = consolidation - } - - /** Specify the timeout. */ - fun timeout(timeout: Duration) = apply { - this.timeout = timeout - } - - fun payload(payload: IntoZBytes) = apply { - this.payload = payload.into() - } - - fun encoding(encoding: Encoding) = apply { - this.encoding = encoding - } - - /** Specify an attachment. */ - fun attachment(attachment: IntoZBytes) = apply { - this.attachment = attachment.into() - } - - /** - * Specify an action to be invoked when the Get operation is over. - * - * Zenoh will trigger ths specified action once no more replies are to be expected. - */ - fun onClose(action: Runnable) = apply { - this.onClose = action - } -} + var attachment: IntoZBytes? = null +) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index c8b004ba..a5290e46 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -184,7 +184,10 @@ public void encoding_queryTest() throws ZError, InterruptedException { }); // Testing with null schema - session.get(selector, new GetConfig().payload(payload).encoding(without_schema)); + var getOptions = new GetOptions(); + getOptions.setPayload(payload); + getOptions.setEncoding(without_schema); + session.get(selector, getOptions); Thread.sleep(200); assertEquals(receivedEncoding[0], without_schema); @@ -193,7 +196,8 @@ public void encoding_queryTest() throws ZError, InterruptedException { // Testing non-null schema receivedEncoding[0] = null; - session.get(selector, new GetConfig().payload(payload).encoding(with_schema)); + getOptions.setEncoding(with_schema); + session.get(selector, getOptions); Thread.sleep(200); assertEquals(receivedEncoding[0], with_schema); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index b5c323ec..77727e9c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -56,7 +56,9 @@ public void tearDown() throws ZError { public void get_runsWithCallbackTest() { Reply[] reply = new Reply[1]; - session.get(selector, reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); + var getOptions = new GetOptions(); + getOptions.setTimeout(Duration.ofMillis(1000)); + session.get(selector, reply1 -> reply[0] = reply1, getOptions); assertNotNull(reply[0]); Sample sample = ((Reply.Success) reply[0]).getSample(); @@ -67,8 +69,10 @@ public void get_runsWithCallbackTest() { } @Test - public void get_runsWithHandlerTest() throws ZError { - ArrayList receiver = session.get(selector, new TestHandler(), new GetConfig().timeout(Duration.ofMillis(1000))); + public void get_runsWithHandlerTest() { + var getOptions = new GetOptions(); + getOptions.setTimeout(Duration.ofMillis(1000)); + ArrayList receiver = session.get(selector, new TestHandler(), getOptions); for (Reply reply : receiver) { Sample sample = ((Reply.Success) reply).getSample(); assertEquals(payload, sample.getPayload()); @@ -86,7 +90,9 @@ public void getWithSelectorParamsTest() throws ZError { Parameters params = Parameters.from("arg1=val1&arg2=val2&arg3"); Selector selectorWithParams = new Selector(selector.getKeyExpr(), params); - session.get(selectorWithParams, new GetConfig().timeout(Duration.ofMillis(1000))); + var getOptions = new GetOptions(); + getOptions.setTimeout(Duration.ofMillis(1000)); + session.get(selectorWithParams, getOptions); queryable.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index d56e2301..59a21a4b 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -18,11 +18,9 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Date; -import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; @@ -73,7 +71,7 @@ public void queryableRunsWithCallback() throws ZError { }); Reply[] reply = new Reply[1]; - session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); + session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1); assertNotNull(reply[0]); Sample receivedSample = ((Reply.Success) reply[0]).getSample(); @@ -88,7 +86,7 @@ public void queryableRunsWithHandler() throws ZError, InterruptedException { Thread.sleep(500); Reply[] reply = new Reply[1]; - session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1, new GetConfig()); + session.get(testKeyExpr.into(), reply1 -> reply[0] = reply1, new GetOptions()); Thread.sleep(500); @@ -114,7 +112,13 @@ public void queryTest() throws ZError, InterruptedException { receivedQuery[0] = null; var payload = ZBytes.from("Test value"); var attachment = ZBytes.from("Attachment"); - session.get(testKeyExpr, new GetConfig().payload(payload).encoding(Encoding.ZENOH_STRING).attachment(attachment)); + + var getOptions = new GetOptions(); + getOptions.setAttachment(attachment); + getOptions.setPayload(payload); + getOptions.setEncoding(Encoding.ZENOH_STRING); + getOptions.setAttachment(attachment); + session.get(testKeyExpr, getOptions); Thread.sleep(100); @@ -145,7 +149,7 @@ public void queryReplySuccessTest() throws ZError { }); Reply[] receivedReply = new Reply[1]; - session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); + session.get(testKeyExpr, reply -> receivedReply[0] = reply); queryable.close(); @@ -175,7 +179,7 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { ); Reply[] receivedReply = new Reply[1]; - session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); + session.get(testKeyExpr, reply -> receivedReply[0] = reply); Thread.sleep(1000); queryable.close(); @@ -202,7 +206,7 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { }); Reply[] receivedReply = new Reply[1]; - session.get(testKeyExpr, reply -> receivedReply[0] = reply, new GetConfig().timeout(Duration.ofMillis(10))); + session.get(testKeyExpr, reply -> receivedReply[0] = reply); Thread.sleep(1000); queryable.close(); @@ -214,16 +218,6 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { assertEquals(SampleKind.DELETE, sample.getKind()); assertEquals(timestamp, sample.getTimestamp()); } - - @Test - public void onCloseTest() throws InterruptedException, ZError { - AtomicReference onCloseWasCalled = new AtomicReference<>(false); - var queryable = session.declareQueryable(testKeyExpr, new QueryableConfig().onClose(() -> onCloseWasCalled.set(true))); - queryable.undeclare(); - - Thread.sleep(1000); - assertTrue(onCloseWasCalled.get()); - } } class QueryHandler implements Handler { diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 11a49cdf..018e4c04 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -20,7 +20,7 @@ import io.zenoh.pubsub.DeleteOptions; import io.zenoh.pubsub.PutConfig; import io.zenoh.pubsub.Subscriber; -import io.zenoh.query.GetConfig; +import io.zenoh.query.GetOptions; import io.zenoh.query.Reply; import io.zenoh.query.ReplyConfig; import io.zenoh.sample.Sample; @@ -155,7 +155,10 @@ public void queryWithAttachmentTest() throws ZError { } }); - session.get(keyExpr, new GetConfig().attachment(attachment).timeout(Duration.ofMillis(1000))); + var getOptions = new GetOptions(); + getOptions.setTimeout(Duration.ofMillis(1000)); + getOptions.setAttachment(attachment); + session.get(keyExpr, getOptions); queryable.close(); @@ -174,7 +177,11 @@ public void queryReplyWithAttachmentTest() throws ZError { } }); - session.get(keyExpr, reply1 -> reply[0] = reply1, new GetConfig().attachment(attachment).timeout(Duration.ofMillis(1000))); + + var getOptions = new GetOptions(); + getOptions.setTimeout(Duration.ofMillis(1000)); + getOptions.setAttachment(attachment); + session.get(keyExpr, reply1 -> reply[0] = reply1, getOptions); queryable.close(); @@ -194,7 +201,7 @@ public void queryReplyWithoutAttachmentTest() throws ZError { throw new RuntimeException(e); } }); - session.get(keyExpr, reply1 -> reply[0] = reply1, new GetConfig().timeout(Duration.ofMillis(1000))); + session.get(keyExpr, reply1 -> reply[0] = reply1); queryable.close(); From 4d9dfe8c26294c05e8215ac93087cabe010e0f6b Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 4 Dec 2024 18:26:14 -0300 Subject: [PATCH 70/83] Alignment: renaming PutConfig to PutOptions and removing 'builder' functions in it. --- examples/src/main/java/io/zenoh/ZPub.java | 8 ++--- examples/src/main/java/io/zenoh/ZPut.java | 6 ++-- .../src/commonMain/kotlin/io/zenoh/Session.kt | 8 ++--- .../kotlin/io/zenoh/jni/JNISession.kt | 2 +- .../kotlin/io/zenoh/pubsub/Publisher.kt | 2 +- .../pubsub/{PutConfig.kt => PutOptions.kt} | 29 ++++++++++++------- .../jvmTest/java/io/zenoh/EncodingTest.java | 9 ++++-- .../jvmTest/java/io/zenoh/PublisherTest.java | 6 ++-- .../src/jvmTest/java/io/zenoh/PutTest.java | 6 ++-- .../jvmTest/java/io/zenoh/SubscriberTest.java | 21 ++++++++------ .../java/io/zenoh/UserAttachmentTest.java | 10 +++++-- 11 files changed, 66 insertions(+), 41 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/{PutConfig.kt => PutOptions.kt} (59%) diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index 796be4ea..c4de913b 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -20,7 +20,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.pubsub.Publisher; import io.zenoh.pubsub.PublisherOptions; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Reliability; import picocli.CommandLine; @@ -64,9 +64,9 @@ public Integer call() throws ZError { String payload = String.format("[%4d] %s", idx, value); System.out.println("Putting Data ('" + keyExpr + "': '" + payload + "')..."); if (attachmentBytes != null) { - PutConfig putConfig = new PutConfig(); - putConfig.setAttachment(attachmentBytes); - publisher.put(ZBytes.from(payload), putConfig); + PutOptions putOptions = new PutOptions(); + putOptions.setAttachment(attachmentBytes); + publisher.put(ZBytes.from(payload), putOptions); } else { publisher.put(ZBytes.from(payload)); } diff --git a/examples/src/main/java/io/zenoh/ZPut.java b/examples/src/main/java/io/zenoh/ZPut.java index 989e337f..11172062 100644 --- a/examples/src/main/java/io/zenoh/ZPut.java +++ b/examples/src/main/java/io/zenoh/ZPut.java @@ -17,7 +17,7 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import picocli.CommandLine; import java.util.List; @@ -43,7 +43,9 @@ public Integer call() throws Exception { KeyExpr keyExpr = KeyExpr.tryFrom(key); System.out.println("Putting Data ('" + keyExpr + "': '" + value + "')..."); if (attachment != null) { - session.put(keyExpr, ZBytes.from(value), new PutConfig().attachment(ZBytes.from(attachment))); + var putOptions = new PutOptions(); + putOptions.setAttachment(ZBytes.from(attachment)); + session.put(keyExpr, ZBytes.from(value), putOptions); } else { session.put(keyExpr, ZBytes.from(value)); } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index e87e6da1..213cdfe3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -289,11 +289,11 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun put(keyExpr: KeyExpr, payload: IntoZBytes) { - resolvePut(keyExpr, payload, PutConfig()) + resolvePut(keyExpr, payload, PutOptions()) } @Throws(ZError::class) - fun put(keyExpr: KeyExpr, payload: IntoZBytes, config: PutConfig) { + fun put(keyExpr: KeyExpr, payload: IntoZBytes, config: PutOptions) { resolvePut(keyExpr, payload, config) } @@ -410,8 +410,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolvePut(keyExpr: KeyExpr, payload: IntoZBytes, putConfig: PutConfig) { - jniSession?.run { performPut(keyExpr, payload, putConfig) } + internal fun resolvePut(keyExpr: KeyExpr, payload: IntoZBytes, putOptions: PutOptions) { + jniSession?.run { performPut(keyExpr, payload, putOptions) } } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 45eeef61..ae915d4f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -343,7 +343,7 @@ internal class JNISession { fun performPut( keyExpr: KeyExpr, payload: IntoZBytes, - config: PutConfig, + config: PutOptions, ) { val encoding = config.encoding ?: Encoding.defaultEncoding() putViaJNI( diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index fc311f06..f5fc35f9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -86,7 +86,7 @@ class Publisher internal constructor( /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ @Throws(ZError::class) - fun put(payload: IntoZBytes, config: PutConfig) { + fun put(payload: IntoZBytes, config: PutOptions) { jniPublisher?.put(payload, config.encoding ?: this.encoding, config.attachment) ?: throw publisherNotValid } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt similarity index 59% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutConfig.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt index 1d8c1703..7c2bb8f4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutConfig.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt @@ -24,24 +24,33 @@ import io.zenoh.qos.Reliability /** * TODO */ -data class PutConfig( +data class PutOptions( var encoding: Encoding? = null, var qos: QoS = QoS.defaultQoS(), var reliability: Reliability = Reliability.RELIABLE, var attachment: IntoZBytes? = null ) { - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + fun getCongestionControl(): CongestionControl { + return this.qos.congestionControl + } - fun qos(qos: QoS) = apply { this.qos = qos } + fun getExpress(): Boolean { + return this.qos.express + } - fun reliability(reliability: Reliability) = apply { this.reliability = reliability } + fun getPriority(): Priority { + return this.qos.priority + } - fun attachment(attachment: IntoZBytes?) = apply { this.attachment = attachment } + fun setCongestionControl(congestionControl: CongestionControl) { + this.qos.congestionControl = congestionControl + } - fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } - - fun express(express: Boolean) = apply { this.qos.express = express } - - fun priority(priority: Priority) = apply { this.qos.priority = priority } + fun setExpress(express: Boolean) { + this.qos.express = express + } + fun setPriority(priority: Priority) { + this.qos.priority = priority + } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index a5290e46..fc75207a 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -18,7 +18,7 @@ import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import io.zenoh.pubsub.Subscriber; import io.zenoh.query.*; import io.zenoh.sample.Sample; @@ -46,7 +46,9 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - session.put(keyExpr, payload, new PutConfig().encoding(with_schema)); + var putOptions = new PutOptions(); + putOptions.setEncoding(with_schema); + session.put(keyExpr, payload, putOptions); Thread.sleep(200); assertNotNull(receivedSample[0]); @@ -54,7 +56,8 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { // Testing null schema receivedSample[0] = null; - session.put(keyExpr, payload, new PutConfig().encoding(without_schema)); + putOptions.setEncoding(without_schema); + session.put(keyExpr, payload, putOptions); Thread.sleep(200); assertEquals(receivedSample[0].getEncoding(), without_schema); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 24520b5d..227e28ad 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -5,7 +5,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.Encoding; import io.zenoh.pubsub.PublisherOptions; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import io.zenoh.qos.QoS; import io.zenoh.qos.Reliability; import io.zenoh.sample.SampleKind; @@ -65,7 +65,9 @@ public void putTest() { testPayloads.forEach(value -> { try { - publisher.put(value.getFirst(), new PutConfig().encoding(value.getSecond())); + var putOptions = new PutOptions(); + putOptions.setEncoding(value.getSecond()); + publisher.put(value.getFirst(), putOptions); } catch (ZError e) { throw new RuntimeException(e); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java index 624b4e38..a4f560e2 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -18,7 +18,7 @@ import io.zenoh.bytes.Encoding; import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import io.zenoh.pubsub.Subscriber; import io.zenoh.sample.Sample; import org.junit.Test; @@ -43,7 +43,9 @@ public void putTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - session.put(keyExpr, TEST_PAYLOAD, new PutConfig().encoding(Encoding.TEXT_PLAIN)); + var putOptions = new PutOptions(); + putOptions.setEncoding(Encoding.TEXT_PLAIN); + session.put(keyExpr, TEST_PAYLOAD, putOptions); subscriber.close(); session.close(); assertNotNull(receivedSample[0]); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java index 94ee94b3..809c4bc0 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SubscriberTest.java @@ -19,7 +19,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import io.zenoh.qos.CongestionControl; import io.zenoh.qos.Priority; import io.zenoh.sample.Sample; @@ -75,10 +75,11 @@ public void subscriber_runsWithCallback() throws ZError { TEST_VALUES.forEach(value -> { try { - session.put(testKeyExpr, value.getFirst(), new PutConfig() - .encoding(value.getSecond()) - .priority(TEST_PRIORITY) - .congestionControl(TEST_CONGESTION_CONTROL)); + var putOptions = new PutOptions(); + putOptions.setEncoding(value.getSecond()); + putOptions.setCongestionControl(TEST_CONGESTION_CONTROL); + putOptions.setPriority(TEST_PRIORITY); + session.put(testKeyExpr, value.getFirst(), putOptions); } catch (ZError e) { throw new RuntimeException(e); } @@ -107,10 +108,12 @@ public void subscriber_runsWithHandler() throws ZError { TEST_VALUES.forEach(value -> { try { - session.put(testKeyExpr, value.getFirst(), new PutConfig() - .encoding(value.getSecond()) - .priority(TEST_PRIORITY) - .congestionControl(TEST_CONGESTION_CONTROL)); + var putOptions = new PutOptions(); + putOptions.setEncoding(value.getSecond()); + putOptions.setCongestionControl(TEST_CONGESTION_CONTROL); + putOptions.setPriority(TEST_PRIORITY); + + session.put(testKeyExpr, value.getFirst(), putOptions); } catch (ZError e) { throw new RuntimeException(e); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index 018e4c04..f8dcd4ba 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -18,7 +18,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.bytes.ZBytes; import io.zenoh.pubsub.DeleteOptions; -import io.zenoh.pubsub.PutConfig; +import io.zenoh.pubsub.PutOptions; import io.zenoh.pubsub.Subscriber; import io.zenoh.query.GetOptions; import io.zenoh.query.Reply; @@ -66,7 +66,9 @@ public void putWithAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - session.put(keyExpr, payload, new PutConfig().attachment(attachment)); + var putOptions = new PutOptions(); + putOptions.setAttachment(attachment); + session.put(keyExpr, payload, putOptions); subscriber.close(); @@ -82,7 +84,9 @@ public void publisherPutWithAttachmentTest() throws ZError { Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); - publisher.put(payload, new PutConfig().attachment(attachment)); + var putOptions = new PutOptions(); + putOptions.setAttachment(attachment); + publisher.put(payload, putOptions); publisher.close(); subscriber.close(); From 569438f6a8d1690545530de0c1f74ae8a39507f1 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 12:26:28 -0300 Subject: [PATCH 71/83] Alignment: renaming ReplyConfig to ReplyOptions and removing 'builder' functions in it. --- .../src/main/java/io/zenoh/ZQueryable.java | 6 +++-- .../commonMain/kotlin/io/zenoh/query/Query.kt | 4 +-- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 27 +++++++++++-------- .../jvmTest/java/io/zenoh/EncodingTest.java | 7 +++-- .../src/jvmTest/java/io/zenoh/GetTest.java | 4 ++- .../jvmTest/java/io/zenoh/QueryableTest.java | 21 +++++++-------- .../java/io/zenoh/UserAttachmentTest.java | 6 +++-- 7 files changed, 44 insertions(+), 31 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index e0e3f488..eb333fad 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -20,7 +20,7 @@ import io.zenoh.query.Query; import io.zenoh.query.Queryable; import io.zenoh.query.QueryableConfig; -import io.zenoh.query.ReplyConfig; +import io.zenoh.query.ReplyOptions; import org.apache.commons.net.ntp.TimeStamp; import picocli.CommandLine; @@ -102,7 +102,9 @@ private void handleQuery(Query query) { try { String valueInfo = query.getPayload() != null ? " with value '" + query.getPayload() + "'" : ""; System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); - query.reply(query.getKeyExpr(), ZBytes.from(value), new ReplyConfig().timestamp(TimeStamp.getCurrentTime())); + var options = new ReplyOptions(); + options.setTimeStamp(TimeStamp.getCurrentTime()); + query.reply(query.getKeyExpr(), ZBytes.from(value), options); } catch (Exception e) { System.err.println(">> [Queryable] Error sending reply: " + e.getMessage()); } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 12f1fc59..865fe796 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -51,7 +51,7 @@ class Query internal constructor( val parameters = selector.parameters @Throws(ZError::class) - fun reply(keyExpr: KeyExpr, payload: IntoZBytes) = reply(keyExpr, payload, ReplyConfig()) + fun reply(keyExpr: KeyExpr, payload: IntoZBytes) = reply(keyExpr, payload, ReplyOptions()) /** * Reply to the specified key expression. @@ -60,7 +60,7 @@ class Query internal constructor( * as the key expression from the Query, however it must intersect with the query key. */ @Throws(ZError::class) - fun reply(keyExpr: KeyExpr, payload: IntoZBytes, config: ReplyConfig) { + fun reply(keyExpr: KeyExpr, payload: IntoZBytes, config: ReplyOptions) { val sample = Sample( keyExpr, payload.into(), diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index ebb9e657..9166dbf9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -85,7 +85,7 @@ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { /** * TODO */ -data class ReplyConfig( +data class ReplyOptions( var encoding: Encoding = Encoding.defaultEncoding(), var timeStamp: TimeStamp? = null, var attachment: ZBytes? = null, @@ -93,37 +93,42 @@ data class ReplyConfig( ) { /** - * Sets the [Encoding] of the reply. + * Get the QoS express value. */ - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + fun getExpress(): Boolean { + return qos.express + } /** - * Sets the [TimeStamp] of the replied [Sample]. + * Get the QoS Priority value. */ - fun timestamp(timeStamp: TimeStamp) = apply { this.timeStamp = timeStamp } + fun getPriority(): Priority { + return qos.priority + } /** - * Appends an attachment to the reply. + * Get the congestion control value. */ - fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment.into() } + fun getCongestionControl(): CongestionControl { + return qos.congestionControl + } /** * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. */ - fun express(express: Boolean) = apply { qos.express(express) } + fun setExpress(express: Boolean) { qos.express(express) } /** * Sets the [Priority] of the reply. */ - fun priority(priority: Priority) = apply { qos.priority(priority) } + fun setPriority(priority: Priority) { qos.priority(priority) } /** * Sets the [CongestionControl] of the reply. * * @param congestionControl */ - fun congestionControl(congestionControl: CongestionControl) = - apply { qos.congestionControl(congestionControl) } + fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl(congestionControl) } } /** diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index fc75207a..2aa0b092 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -77,10 +77,13 @@ public void encoding_replySuccessTest() throws ZError, InterruptedException { { try { KeyExpr queryKeyExpr = query.getKeyExpr(); + var options = new ReplyOptions(); if (queryKeyExpr.equals(test1.getKeyExpr())) { - query.reply(queryKeyExpr, payload, new ReplyConfig().encoding(without_schema)); + options.setEncoding(without_schema); + query.reply(queryKeyExpr, payload, options); } else if (queryKeyExpr.equals(test2.getKeyExpr())) { - query.reply(queryKeyExpr, payload, new ReplyConfig().encoding(with_schema)); + options.setEncoding(with_schema); + query.reply(queryKeyExpr, payload, options); } } catch (Exception e) { throw new RuntimeException(e); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index 77727e9c..9f582a39 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -37,7 +37,9 @@ public void setUp() throws ZError { queryable = session.declareQueryable(selector.getKeyExpr(), query -> { try { - query.reply(query.getKeyExpr(), payload, new ReplyConfig().timestamp(timestamp)); + var options = new ReplyOptions(); + options.setTimeStamp(timestamp); + query.reply(query.getKeyExpr(), payload, options); } catch (ZError e) { throw new RuntimeException(e); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index 59a21a4b..3fefc94c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -60,11 +60,9 @@ public void queryableRunsWithCallback() throws ZError { var queryable = session.declareQueryable(testKeyExpr, query -> { try { - query.reply(testKeyExpr, testPayload, new ReplyConfig() - .timestamp(timestamp) - .congestionControl(QoS.defaultQoS().getCongestionControl()) - .priority(QoS.defaultQoS().getPriority()) - .express(QoS.defaultQoS().getExpress())); + var options = new ReplyOptions(); + options.setTimeStamp(timestamp); + query.reply(testKeyExpr, testPayload, options); } catch (ZError e) { throw new RuntimeException(e); } @@ -137,12 +135,13 @@ public void queryReplySuccessTest() throws ZError { var timestamp = TimeStamp.getCurrentTime(); Queryable queryable = session.declareQueryable(testKeyExpr, query -> { + var options = new ReplyOptions(); + options.setTimeStamp(timestamp); + options.setPriority(Priority.DATA_HIGH); + options.setCongestionControl(CongestionControl.DROP); + options.setExpress(true); try { - query.reply(testKeyExpr, message, new ReplyConfig() - .timestamp(timestamp) - .priority(Priority.DATA_HIGH) - .express(true) - .congestionControl(CongestionControl.DROP)); + query.reply(testKeyExpr, message, options); } catch (ZError e) { throw new RuntimeException(e); } @@ -261,7 +260,7 @@ public void reply(Query query) throws ZError { null ); performedReplies.add(sample); - var config = new ReplyConfig(); + var config = new ReplyOptions(); config.setTimeStamp(sample.getTimestamp()); query.reply(query.getKeyExpr(), payload, config); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index f8dcd4ba..e8695da0 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -22,7 +22,7 @@ import io.zenoh.pubsub.Subscriber; import io.zenoh.query.GetOptions; import io.zenoh.query.Reply; -import io.zenoh.query.ReplyConfig; +import io.zenoh.query.ReplyOptions; import io.zenoh.sample.Sample; import org.junit.After; import org.junit.Before; @@ -175,7 +175,9 @@ public void queryReplyWithAttachmentTest() throws ZError { Reply[] reply = new Reply[1]; var queryable = session.declareQueryable(keyExpr, query -> { try { - query.reply(keyExpr, payload, new ReplyConfig().attachment(attachment)); + var options = new ReplyOptions(); + options.setAttachment(attachment); + query.reply(keyExpr, payload, options); } catch (ZError e) { throw new RuntimeException(e); } From 94bbab4de4c2647416cd2f83680e67403d7350c0 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 14:28:00 -0300 Subject: [PATCH 72/83] Alignment: renaming ReplyDelConfig to ReplyDelOptions and removing 'builder' functions in it. --- .../commonMain/kotlin/io/zenoh/query/Query.kt | 4 +-- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 29 ++++++++++++------- .../jvmTest/java/io/zenoh/QueryableTest.java | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 865fe796..e602df69 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -80,13 +80,13 @@ class Query internal constructor( * TODO */ @Throws(ZError::class) - fun replyDel(keyExpr: KeyExpr) = replyDel(keyExpr, ReplyDelConfig()) + fun replyDel(keyExpr: KeyExpr) = replyDel(keyExpr, ReplyDelOptions()) /** * TODO */ @Throws(ZError::class) - fun replyDel(keyExpr: KeyExpr, config: ReplyDelConfig) { + fun replyDel(keyExpr: KeyExpr, config: ReplyDelOptions) { jniQuery?.apply { replyDelete( keyExpr, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index 9166dbf9..350dac05 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -16,7 +16,6 @@ package io.zenoh.query import io.zenoh.ZenohType import io.zenoh.bytes.Encoding -import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.config.ZenohId import io.zenoh.sample.Sample @@ -134,38 +133,48 @@ data class ReplyOptions( /** * TODO */ -data class ReplyDelConfig( +data class ReplyDelOptions( var timeStamp: TimeStamp? = null, var attachment: ZBytes? = null, var qos: QoS = QoS.defaultQoS() ) { /** - * Sets the [TimeStamp] of the replied [Sample]. + * Get the QoS express value. */ - fun timestamp(timeStamp: TimeStamp) = apply { this.timeStamp = timeStamp } + fun getExpress(): Boolean { + return qos.express + } + + /** + * Get the QoS Priority value. + */ + fun getPriority(): Priority { + return qos.priority + } /** - * Appends an attachment to the reply. + * Get the congestion control value. */ - fun attachment(attachment: IntoZBytes) = apply { this.attachment = attachment.into() } + fun getCongestionControl(): CongestionControl { + return qos.congestionControl + } /** * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. */ - fun express(express: Boolean) = apply { qos.express(express) } + fun setExpress(express: Boolean) { qos.express(express) } /** * Sets the [Priority] of the reply. */ - fun priority(priority: Priority) = apply { qos.priority(priority) } + fun setPriority(priority: Priority) { qos.priority(priority) } /** * Sets the [CongestionControl] of the reply. * * @param congestionControl */ - fun congestionControl(congestionControl: CongestionControl) = - apply { qos.congestionControl(congestionControl) } + fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl(congestionControl) } } /** diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index 3fefc94c..2101de90 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -196,7 +196,7 @@ public void queryReplyDeleteTest() throws ZError, InterruptedException { var queryable = session.declareQueryable(testKeyExpr, query -> { try { - var config = new ReplyDelConfig(); + var config = new ReplyDelOptions(); config.setTimeStamp(timestamp); query.replyDel(testKeyExpr, config); } catch (ZError e) { From 07f22dcd4c8b39388f9965271c83879bf14607dc Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 14:43:12 -0300 Subject: [PATCH 73/83] Alignment: renaming ReplyErrConfig to ReplyErrOptions and removing 'builder' functions in it. --- zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt | 4 ++-- zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt | 9 +-------- zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java | 7 +++++-- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index e602df69..8fe6793e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -102,13 +102,13 @@ class Query internal constructor( * TODO */ @Throws(ZError::class) - fun replyErr(payload: IntoZBytes) = replyErr(payload, ReplyErrConfig()) + fun replyErr(payload: IntoZBytes) = replyErr(payload, ReplyErrOptions()) /** * TODO */ @Throws(ZError::class) - fun replyErr(payload: IntoZBytes, config: ReplyErrConfig) { + fun replyErr(payload: IntoZBytes, config: ReplyErrOptions) { jniQuery?.apply { replyError(payload.into(), config.encoding) jniQuery = null diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index 350dac05..a06a2a8d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -180,11 +180,4 @@ data class ReplyDelOptions( /** * TODO */ -data class ReplyErrConfig internal constructor(var encoding: Encoding = Encoding.defaultEncoding()) { - - /** - * Sets the [Encoding] of the reply. - */ - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } - -} +data class ReplyErrOptions(var encoding: Encoding = Encoding.defaultEncoding()) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index 2aa0b092..f40d4399 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -128,11 +128,14 @@ public void encoding_replyErrorTest() throws ZError, InterruptedException { var queryable = session.declareQueryable(keyExpr, query -> { KeyExpr keyExpr1 = query.getKeyExpr(); + var options = new ReplyErrOptions(); try { if (keyExpr1.equals(test1.getKeyExpr())) { - query.replyErr(replyPayload, new ReplyErrConfig().encoding(without_schema)); + options.setEncoding(without_schema); + query.replyErr(replyPayload, options); } else if (keyExpr1.equals(test2.getKeyExpr())) { - query.replyErr(replyPayload, new ReplyErrConfig().encoding(with_schema)); + options.setEncoding(with_schema); + query.replyErr(replyPayload, options); } } catch (Exception e) { throw new RuntimeException(e); From c5d92dd37176d89b1c2292c31e79d7c3a583af0f Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 14:56:46 -0300 Subject: [PATCH 74/83] Alignment: renaming QueryableConfig to QueryableOptions and removing 'builder' functions in it. --- examples/src/main/java/io/zenoh/ZQueryable.java | 12 ++++++------ .../src/commonMain/kotlin/io/zenoh/Session.kt | 16 ++++++++-------- .../commonMain/kotlin/io/zenoh/jni/JNISession.kt | 4 ++-- .../kotlin/io/zenoh/query/Queryable.kt | 6 +----- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index eb333fad..240c84fe 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -19,7 +19,7 @@ import io.zenoh.keyexpr.KeyExpr; import io.zenoh.query.Query; import io.zenoh.query.Queryable; -import io.zenoh.query.QueryableConfig; +import io.zenoh.query.QueryableOptions; import io.zenoh.query.ReplyOptions; import org.apache.commons.net.ntp.TimeStamp; import picocli.CommandLine; @@ -86,15 +86,15 @@ private void declareQueryableWithCallback(Config config, KeyExpr keyExpr) throws /** * Example demonstrating the use of QueryableConfig to declare a Queryable. * - * @see QueryableConfig + * @see QueryableOptions */ private void declareQueryableProvidingConfig(Config config, KeyExpr keyExpr) throws ZError { try (Session session = Zenoh.open(config)) { - QueryableConfig queryableConfig = new QueryableConfig(); - queryableConfig.setComplete(true); - queryableConfig.setOnClose(() -> System.out.println("Queryable closed...")); + QueryableOptions queryableOptions = new QueryableOptions(); + queryableOptions.setComplete(true); +// queryableConfig.setOnClose(() -> System.out.println("Queryable closed...")); - session.declareQueryable(keyExpr, this::handleQuery, queryableConfig); + session.declareQueryable(keyExpr, this::handleQuery, queryableOptions); } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 213cdfe3..125d7fde 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -154,9 +154,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { @JvmOverloads fun declareQueryable( keyExpr: KeyExpr, - config: QueryableConfig = QueryableConfig() + options: QueryableOptions = QueryableOptions() ): Queryable>> { - return resolveQueryableWithHandler(keyExpr, BlockingQueueHandler(LinkedBlockingDeque()), config) + return resolveQueryableWithHandler(keyExpr, BlockingQueueHandler(LinkedBlockingDeque()), options) } /** @@ -166,8 +166,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) @JvmOverloads - fun declareQueryable(keyExpr: KeyExpr, handler: Handler, config: QueryableConfig = QueryableConfig()): Queryable { - return resolveQueryableWithHandler(keyExpr, handler, config) + fun declareQueryable(keyExpr: KeyExpr, handler: Handler, options: QueryableOptions = QueryableOptions()): Queryable { + return resolveQueryableWithHandler(keyExpr, handler, options) } /** @@ -177,8 +177,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) @JvmOverloads - fun declareQueryable(keyExpr: KeyExpr, callback: Callback, config: QueryableConfig = QueryableConfig()): Queryable { - return resolveQueryableWithCallback(keyExpr, callback, config) + fun declareQueryable(keyExpr: KeyExpr, callback: Callback, options: QueryableOptions = QueryableOptions()): Queryable { + return resolveQueryableWithCallback(keyExpr, callback, options) } /** @@ -363,7 +363,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithHandler( - keyExpr: KeyExpr, handler: Handler, config: QueryableConfig + keyExpr: KeyExpr, handler: Handler, config: QueryableOptions ): Queryable { return jniSession?.run { val queryable = declareQueryableWithHandler(keyExpr, handler, config) @@ -374,7 +374,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithCallback( - keyExpr: KeyExpr, callback: Callback, config: QueryableConfig + keyExpr: KeyExpr, callback: Callback, config: QueryableOptions ): Queryable { return jniSession?.run { val queryable = declareQueryableWithCallback(keyExpr, callback, config) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index ae915d4f..48c8c60a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -133,7 +133,7 @@ internal class JNISession { @Throws(ZError::class) fun declareQueryableWithCallback( - keyExpr: KeyExpr, callback: Callback, config: QueryableConfig + keyExpr: KeyExpr, callback: Callback, config: QueryableOptions ): Queryable { val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> @@ -167,7 +167,7 @@ internal class JNISession { @Throws(ZError::class) fun declareQueryableWithHandler( - keyExpr: KeyExpr, handler: Handler, config: QueryableConfig + keyExpr: KeyExpr, handler: Handler, config: QueryableOptions ): Queryable { val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index 1f9696cd..395b6dad 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -15,16 +15,12 @@ package io.zenoh.query import io.zenoh.* -import io.zenoh.exceptions.ZError -import io.zenoh.handlers.Callback import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler import io.zenoh.jni.JNIQueryable import io.zenoh.keyexpr.KeyExpr import io.zenoh.session.SessionDeclaration import java.util.* -import java.util.concurrent.BlockingQueue -import java.util.concurrent.LinkedBlockingDeque /** * A queryable that allows to perform multiple queries on the specified [KeyExpr]. @@ -93,7 +89,7 @@ class Queryable internal constructor( /** * TODO: add doc */ -data class QueryableConfig( +data class QueryableOptions( var complete: Boolean = false, var onClose: Runnable? = null ) { From 752c45327bb299552d69d591ba31d808e33e35e2 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 15:11:04 -0300 Subject: [PATCH 75/83] Alignment: renaming ScoutConfig to ScoutOptions and removing 'builder' functions in it. --- examples/src/main/java/io/zenoh/ZScout.java | 6 ++-- .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 34 +++++++++---------- .../{ScoutConfig.kt => ScoutOptions.kt} | 9 ++--- .../src/jvmTest/java/io/zenoh/ScoutTest.java | 6 ++-- 4 files changed, 27 insertions(+), 28 deletions(-) rename zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/{ScoutConfig.kt => ScoutOptions.kt} (79%) diff --git a/examples/src/main/java/io/zenoh/ZScout.java b/examples/src/main/java/io/zenoh/ZScout.java index 45999e1f..515c4f0f 100644 --- a/examples/src/main/java/io/zenoh/ZScout.java +++ b/examples/src/main/java/io/zenoh/ZScout.java @@ -17,7 +17,7 @@ import io.zenoh.config.WhatAmI; import io.zenoh.scouting.Hello; import io.zenoh.scouting.Scout; -import io.zenoh.scouting.ScoutConfig; +import io.zenoh.scouting.ScoutOptions; import picocli.CommandLine; import java.util.Optional; @@ -38,7 +38,9 @@ public Integer call() throws Exception { System.out.println("Scouting..."); - Scout>> scout = Zenoh.scout(new ScoutConfig().whatAmI(Set.of(WhatAmI.Peer, WhatAmI.Router))); + var scoutOptions = new ScoutOptions(); + scoutOptions.setWhatAmI(Set.of(WhatAmI.Peer, WhatAmI.Router)); + Scout>> scout = Zenoh.scout(scoutOptions); BlockingQueue> receiver = scout.getReceiver(); assert receiver != null; diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index 8d242670..dfd8c942 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -22,7 +22,7 @@ import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler import io.zenoh.jni.JNIScout -import io.zenoh.scouting.ScoutConfig +import io.zenoh.scouting.ScoutOptions import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque @@ -49,52 +49,52 @@ object Zenoh { */ @JvmStatic fun scout(): Scout>> { - val scoutConfig = ScoutConfig() + val scoutOptions = ScoutOptions() val handler = BlockingQueueHandler(LinkedBlockingDeque>()) return JNIScout.scoutWithHandler( - scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, - receiver = handler.receiver(), config = scoutConfig.config + scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutOptions.config ) } @JvmStatic - fun scout(scoutConfig: ScoutConfig): Scout>> { + fun scout(scoutOptions: ScoutOptions): Scout>> { val handler = BlockingQueueHandler(LinkedBlockingDeque>()) return JNIScout.scoutWithHandler( - scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, - receiver = handler.receiver(), config = scoutConfig.config + scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutOptions.config ) } @JvmStatic fun scout(handler: Handler): Scout { - val scoutConfig = ScoutConfig() + val scoutOptions = ScoutOptions() return JNIScout.scoutWithHandler( - scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, - receiver = handler.receiver(), config = scoutConfig.config + scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutOptions.config ) } @JvmStatic - fun scout(handler: Handler, scoutConfig: ScoutConfig): Scout { + fun scout(handler: Handler, scoutOptions: ScoutOptions): Scout { return JNIScout.scoutWithHandler( - scoutConfig.whatAmI, handler::handle, fun() { handler.onClose() }, - receiver = handler.receiver(), config = scoutConfig.config + scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, + receiver = handler.receiver(), config = scoutOptions.config ) } @JvmStatic fun scout(callback: Callback): Scout { - val scoutConfig = ScoutConfig() + val scoutOptions = ScoutOptions() return JNIScout.scoutWithCallback( - scoutConfig.whatAmI, callback, config = scoutConfig.config + scoutOptions.whatAmI, callback, config = scoutOptions.config ) } @JvmStatic - fun scout(callback: Callback, scoutConfig: ScoutConfig): Scout { + fun scout(callback: Callback, scoutOptions: ScoutOptions): Scout { return JNIScout.scoutWithCallback( - scoutConfig.whatAmI, callback, config = scoutConfig.config + scoutOptions.whatAmI, callback, config = scoutOptions.config ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt similarity index 79% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt rename to zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt index 8f3ce23e..94e8452f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutConfig.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt @@ -17,12 +17,7 @@ package io.zenoh.scouting import io.zenoh.Config import io.zenoh.config.WhatAmI -data class ScoutConfig( +data class ScoutOptions( var config: Config? = null, var whatAmI: Set = setOf(WhatAmI.Peer, WhatAmI.Router) -) { - - fun config(config: Config) = apply { this.config = config } - - fun whatAmI(whatAmI: Set) = apply { this.whatAmI = whatAmI } -} +) diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java index 93887d0d..18b5a751 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java @@ -18,7 +18,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.scouting.Hello; import io.zenoh.scouting.Scout; -import io.zenoh.scouting.ScoutConfig; +import io.zenoh.scouting.ScoutOptions; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -71,7 +71,9 @@ public void scouting_callbackTest() throws ZError, InterruptedException { @Test public void scouting_whatAmITest() { - var scout = Zenoh.scout(new ScoutConfig().whatAmI(Set.of(WhatAmI.Client, WhatAmI.Peer))); + var scoutOptions = new ScoutOptions(); + scoutOptions.setWhatAmI(Set.of(WhatAmI.Client, WhatAmI.Peer)); + var scout = Zenoh.scout(scoutOptions); scout.close(); } From 0577e5bf7a89f4218e2ea9ca2296ebe2f7968bef Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 16:18:41 -0300 Subject: [PATCH 76/83] Alignment: renaming Liveliness.SubscriberConfig + renaming variables --- .../main/java/io/zenoh/ZSubLiveliness.java | 9 +- .../src/commonMain/kotlin/io/zenoh/Session.kt | 101 ++++++------------ .../kotlin/io/zenoh/jni/JNISession.kt | 58 +++++----- .../kotlin/io/zenoh/liveliness/Liveliness.kt | 35 +++--- .../kotlin/io/zenoh/pubsub/Publisher.kt | 8 +- .../commonMain/kotlin/io/zenoh/query/Query.kt | 40 +++---- .../src/jvmTest/java/io/zenoh/GetTest.java | 4 +- 7 files changed, 103 insertions(+), 152 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZSubLiveliness.java b/examples/src/main/java/io/zenoh/ZSubLiveliness.java index d3b6fc86..a6c61481 100644 --- a/examples/src/main/java/io/zenoh/ZSubLiveliness.java +++ b/examples/src/main/java/io/zenoh/ZSubLiveliness.java @@ -57,8 +57,9 @@ public Integer call() throws Exception { */ private void subscribeToLivelinessWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { try (Session session = Zenoh.open(config)) { + var options = new Liveliness.SubscriberOptions(history); Subscriber>> subscriber = - session.liveliness().declareSubscriber(keyExpr, new Liveliness.SubscriberConfig().history(history)); + session.liveliness().declareSubscriber(keyExpr, options); BlockingQueue> receiver = subscriber.getReceiver(); System.out.println("Listening for liveliness tokens..."); @@ -79,10 +80,11 @@ private void subscribeToLivelinessWithBlockingQueue(Config config, KeyExpr keyEx */ private void subscribeToLivelinessWithCallback(Config config, KeyExpr keyExpr) throws ZError { try (Session session = Zenoh.open(config)) { + var options = new Liveliness.SubscriberOptions(history); session.liveliness().declareSubscriber( keyExpr, this::handleLivelinessSample, - new Liveliness.SubscriberConfig().history(history) + options ); } } @@ -96,10 +98,11 @@ private void subscribeToLivelinessWithCallback(Config config, KeyExpr keyExpr) t private void subscribeToLivelinessWithHandler(Config config, KeyExpr keyExpr) throws ZError { try (Session session = Zenoh.open(config)) { QueueHandler queueHandler = new QueueHandler<>(); + var options = new Liveliness.SubscriberOptions(history); session.liveliness().declareSubscriber( keyExpr, queueHandler, - new Liveliness.SubscriberConfig().history(history) + options ); } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 125d7fde..fd213ff3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -101,14 +101,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { * * TODO */ - fun declarePublisher(keyExpr: KeyExpr): Publisher = declarePublisher(keyExpr, PublisherOptions()) - - /** - * Declare a [Publisher] on the session. - * - * TODO - */ - fun declarePublisher(keyExpr: KeyExpr, publisherOptions: PublisherOptions): Publisher { + @JvmOverloads + @Throws(ZError::class) + fun declarePublisher(keyExpr: KeyExpr, publisherOptions: PublisherOptions = PublisherOptions()): Publisher { return resolvePublisher(keyExpr, publisherOptions) } @@ -203,7 +198,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { * @param keyExpr The intended Key expression. * @return A resolvable returning an optimized representation of the passed `keyExpr`. */ - fun declareKeyExpr(keyExpr: String): Resolvable = Resolvable { + fun declareKeyExpr(keyExpr: String): Resolvable = Resolvable { // TODO: remove resolvable return@Resolvable jniSession?.run { val keyexpr = declareKeyExpr(keyExpr) declarations.add(keyexpr) @@ -233,82 +228,52 @@ class Session private constructor(private val config: Config) : AutoCloseable { * TODO: provide example * ``` */ - fun get(selector: IntoSelector): BlockingQueue> { - val handler = BlockingQueueHandler(LinkedBlockingDeque()) - val config = GetOptions() - return resolveGetWithHandler( - selector, - handler, - config - ) - } - - /** - * TODO - */ - fun get(selector: IntoSelector, config: GetOptions): BlockingQueue> { + @JvmOverloads + @Throws(ZError::class) + fun get(selector: IntoSelector, options: GetOptions = GetOptions()): BlockingQueue> { val handler = BlockingQueueHandler(LinkedBlockingDeque()) return resolveGetWithHandler( selector, handler, - config + options ) } /** * TODO */ - fun get(selector: IntoSelector, handler: Handler): R { - return resolveGetWithHandler(selector, handler, GetOptions()) - } - - /** - * TODO - */ - fun get(selector: IntoSelector, handler: Handler, config: GetOptions): R { - return resolveGetWithHandler(selector, handler, config) - } - - /** - * TODO - */ - fun get(selector: IntoSelector, callback: Callback) { - return resolveGetWithCallback(selector, callback, GetOptions()) + @JvmOverloads + @Throws(ZError::class) + fun get(selector: IntoSelector, handler: Handler, options: GetOptions = GetOptions()): R { + return resolveGetWithHandler(selector, handler, options) } /** * TODO */ - fun get(selector: IntoSelector, callback: Callback, config: GetOptions) { - return resolveGetWithCallback(selector, callback, config) + @JvmOverloads + @Throws(ZError::class) + fun get(selector: IntoSelector, callback: Callback, options: GetOptions = GetOptions()) { + return resolveGetWithCallback(selector, callback, options) } /** * Declare a [Put] with the provided value on the specified key expression. * //TODO update */ + @JvmOverloads @Throws(ZError::class) - fun put(keyExpr: KeyExpr, payload: IntoZBytes) { - resolvePut(keyExpr, payload, PutOptions()) - } - - @Throws(ZError::class) - fun put(keyExpr: KeyExpr, payload: IntoZBytes, config: PutOptions) { - resolvePut(keyExpr, payload, config) + fun put(keyExpr: KeyExpr, payload: IntoZBytes, options: PutOptions = PutOptions()) { + resolvePut(keyExpr, payload, options) } /** * TODO */ - fun delete(keyExpr: KeyExpr) { - resolveDelete(keyExpr, DeleteOptions()) - } - - /** - * TODO - */ - fun delete(keyExpr: KeyExpr, config: DeleteOptions) { - resolveDelete(keyExpr, config) + @JvmOverloads + @Throws(ZError::class) + fun delete(keyExpr: KeyExpr, options: DeleteOptions = DeleteOptions()) { + resolveDelete(keyExpr, options) } /** Returns if session is open or has been closed. */ @@ -331,9 +296,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { } @Throws(ZError::class) - internal fun resolvePublisher(keyExpr: KeyExpr, config: PublisherOptions): Publisher { + internal fun resolvePublisher(keyExpr: KeyExpr, options: PublisherOptions): Publisher { return jniSession?.run { - val publisher = declarePublisher(keyExpr, config) + val publisher = declarePublisher(keyExpr, options) declarations.add(publisher) publisher } ?: throw (sessionClosedException) @@ -363,10 +328,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithHandler( - keyExpr: KeyExpr, handler: Handler, config: QueryableOptions + keyExpr: KeyExpr, handler: Handler, options: QueryableOptions ): Queryable { return jniSession?.run { - val queryable = declareQueryableWithHandler(keyExpr, handler, config) + val queryable = declareQueryableWithHandler(keyExpr, handler, options) declarations.add(queryable) queryable } ?: throw (sessionClosedException) @@ -374,10 +339,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithCallback( - keyExpr: KeyExpr, callback: Callback, config: QueryableOptions + keyExpr: KeyExpr, callback: Callback, options: QueryableOptions ): Queryable { return jniSession?.run { - val queryable = declareQueryableWithCallback(keyExpr, callback, config) + val queryable = declareQueryableWithCallback(keyExpr, callback, options) declarations.add(queryable) queryable } ?: throw (sessionClosedException) @@ -387,12 +352,12 @@ class Session private constructor(private val config: Config) : AutoCloseable { internal fun resolveGetWithHandler( selector: IntoSelector, handler: Handler, - config: GetOptions + options: GetOptions ): R { return jniSession?.performGetWithHandler( selector, handler, - config + options ) ?: throw sessionClosedException } @@ -400,12 +365,12 @@ class Session private constructor(private val config: Config) : AutoCloseable { internal fun resolveGetWithCallback( selector: IntoSelector, callback: Callback, - config: GetOptions + options: GetOptions ) { return jniSession?.performGetWithCallback( selector, callback, - config + options ) ?: throw sessionClosedException } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index 48c8c60a..eaa131f1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -203,7 +203,7 @@ internal class JNISession { fun performGetWithCallback( intoSelector: IntoSelector, callback: Callback, - config: GetOptions + options: GetOptions ) { val getCallback = JNIGetCallback { replierId: ByteArray?, @@ -251,13 +251,13 @@ internal class JNISession { sessionPtr.get(), getCallback, fun() {}, - config.timeout.toMillis(), - config.target.ordinal, - config.consolidation.ordinal, - config.attachment?.into()?.bytes, - config.payload?.into()?.bytes, - config.encoding?.id ?: Encoding.defaultEncoding().id, - config.encoding?.schema + options.timeout.toMillis(), + options.target.ordinal, + options.consolidation.ordinal, + options.attachment?.into()?.bytes, + options.payload?.into()?.bytes, + options.encoding?.id ?: Encoding.defaultEncoding().id, + options.encoding?.schema ) } @@ -265,7 +265,7 @@ internal class JNISession { fun performGetWithHandler( intoSelector: IntoSelector, handler: Handler, - config: GetOptions + options: GetOptions ): R { val getCallback = JNIGetCallback { replierId: ByteArray?, @@ -313,13 +313,13 @@ internal class JNISession { sessionPtr.get(), getCallback, handler::onClose, - config.timeout.toMillis(), - config.target.ordinal, - config.consolidation.ordinal, - config.attachment?.into()?.bytes, - config.payload?.into()?.bytes, - config.encoding?.id ?: Encoding.defaultEncoding().id, - config.encoding?.schema + options.timeout.toMillis(), + options.target.ordinal, + options.consolidation.ordinal, + options.attachment?.into()?.bytes, + options.payload?.into()?.bytes, + options.encoding?.id ?: Encoding.defaultEncoding().id, + options.encoding?.schema ) return handler.receiver() } @@ -343,9 +343,9 @@ internal class JNISession { fun performPut( keyExpr: KeyExpr, payload: IntoZBytes, - config: PutOptions, + options: PutOptions, ) { - val encoding = config.encoding ?: Encoding.defaultEncoding() + val encoding = options.encoding ?: Encoding.defaultEncoding() putViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, @@ -353,28 +353,28 @@ internal class JNISession { payload.into().bytes, encoding.id, encoding.schema, - config.qos.congestionControl.value, - config.qos.priority.value, - config.qos.express, - config.attachment?.into()?.bytes, - config.reliability.ordinal + options.qos.congestionControl.value, + options.qos.priority.value, + options.qos.express, + options.attachment?.into()?.bytes, + options.reliability.ordinal ) } @Throws(ZError::class) fun performDelete( keyExpr: KeyExpr, - config: DeleteOptions, + options: DeleteOptions, ) { deleteViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - config.qos.congestionControl.value, - config.qos.priority.value, - config.qos.express, - config.attachment?.into()?.bytes, - config.reliability.ordinal + options.qos.congestionControl.value, + options.qos.priority.value, + options.qos.express, + options.attachment?.into()?.bytes, + options.reliability.ordinal ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt index d72669bb..e7fb1f1e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt @@ -61,7 +61,8 @@ class Liveliness internal constructor(private val session: Session) { ): BlockingQueue> { val jniSession = session.jniSession ?: throw Session.sessionClosedException val handler = BlockingQueueHandler(LinkedBlockingDeque()) - return JNILiveliness.get(jniSession, + return JNILiveliness.get( + jniSession, keyExpr, handler::handle, receiver = handler.receiver(), @@ -119,7 +120,7 @@ class Liveliness internal constructor(private val session: Session) { fun declareSubscriber( keyExpr: KeyExpr, callback: Callback, - config: SubscriberConfig = SubscriberConfig() + options: SubscriberOptions = SubscriberOptions() ): Subscriber { val jniSession = session.jniSession ?: throw Session.sessionClosedException return JNILiveliness.declareSubscriber( @@ -127,8 +128,9 @@ class Liveliness internal constructor(private val session: Session) { keyExpr, callback, null, - config.history, - fun() { config.onClose?.run() }) + options.history, + fun() {} + ) } /** @@ -142,7 +144,7 @@ class Liveliness internal constructor(private val session: Session) { fun declareSubscriber( keyExpr: KeyExpr, handler: Handler, - config: SubscriberConfig = SubscriberConfig() + options: SubscriberOptions = SubscriberOptions() ): Subscriber { val jniSession = session.jniSession ?: throw Session.sessionClosedException return JNILiveliness.declareSubscriber( @@ -150,17 +152,15 @@ class Liveliness internal constructor(private val session: Session) { keyExpr, handler::handle, handler.receiver(), - config.history, - fun() { - handler.onClose() - config.onClose?.run() - }) + options.history, + handler::onClose + ) } @JvmOverloads fun declareSubscriber( keyExpr: KeyExpr, - config: SubscriberConfig = SubscriberConfig() + options: SubscriberOptions = SubscriberOptions() ): Subscriber>> { val handler = BlockingQueueHandler(LinkedBlockingDeque()) val jniSession = session.jniSession ?: throw Session.sessionClosedException @@ -169,15 +169,10 @@ class Liveliness internal constructor(private val session: Session) { keyExpr, handler::handle, handler.receiver(), - config.history, - fun() { - handler.onClose() - config.onClose?.run() - }) + options.history, + handler::onClose + ) } - data class SubscriberConfig(var history: Boolean = false, var onClose: Runnable? = null) { - fun history(history: Boolean) = apply { this.history = history } - fun onClose(onClose: Runnable) = apply { this.onClose = onClose } - } + data class SubscriberOptions(var history: Boolean = false) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index f5fc35f9..7e9be214 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -86,8 +86,8 @@ class Publisher internal constructor( /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ @Throws(ZError::class) - fun put(payload: IntoZBytes, config: PutOptions) { - jniPublisher?.put(payload, config.encoding ?: this.encoding, config.attachment) ?: throw publisherNotValid + fun put(payload: IntoZBytes, options: PutOptions) { + jniPublisher?.put(payload, options.encoding ?: this.encoding, options.attachment) ?: throw publisherNotValid } /** @@ -97,8 +97,8 @@ class Publisher internal constructor( */ @JvmOverloads @Throws(ZError::class) - fun delete(config: DeleteOptions = DeleteOptions()) { - jniPublisher?.delete(config.attachment) ?: throw(publisherNotValid) + fun delete(options: DeleteOptions = DeleteOptions()) { + jniPublisher?.delete(options.attachment) ?: throw(publisherNotValid) } /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 8fe6793e..e8fb7dea 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -50,9 +50,6 @@ class Query internal constructor( /** Shortcut to the [selector]'s parameters. */ val parameters = selector.parameters - @Throws(ZError::class) - fun reply(keyExpr: KeyExpr, payload: IntoZBytes) = reply(keyExpr, payload, ReplyOptions()) - /** * Reply to the specified key expression. * @@ -60,15 +57,16 @@ class Query internal constructor( * as the key expression from the Query, however it must intersect with the query key. */ @Throws(ZError::class) - fun reply(keyExpr: KeyExpr, payload: IntoZBytes, config: ReplyOptions) { + @JvmOverloads + fun reply(keyExpr: KeyExpr, payload: IntoZBytes, options: ReplyOptions = ReplyOptions()) { val sample = Sample( keyExpr, payload.into(), - config.encoding, + options.encoding, SampleKind.PUT, - config.timeStamp, - config.qos, - config.attachment + options.timeStamp, + options.qos, + options.attachment ) jniQuery?.apply { replySuccess(sample) @@ -79,20 +77,15 @@ class Query internal constructor( /** * TODO */ + @JvmOverloads @Throws(ZError::class) - fun replyDel(keyExpr: KeyExpr) = replyDel(keyExpr, ReplyDelOptions()) - - /** - * TODO - */ - @Throws(ZError::class) - fun replyDel(keyExpr: KeyExpr, config: ReplyDelOptions) { + fun replyDel(keyExpr: KeyExpr, options: ReplyDelOptions = ReplyDelOptions()) { jniQuery?.apply { replyDelete( keyExpr, - config.timeStamp, - config.attachment, - config.qos + options.timeStamp, + options.attachment, + options.qos ) jniQuery = null } ?: throw (ZError("Query is invalid")) @@ -101,16 +94,11 @@ class Query internal constructor( /** * TODO */ + @JvmOverloads @Throws(ZError::class) - fun replyErr(payload: IntoZBytes) = replyErr(payload, ReplyErrOptions()) - - /** - * TODO - */ - @Throws(ZError::class) - fun replyErr(payload: IntoZBytes, config: ReplyErrOptions) { + fun replyErr(payload: IntoZBytes, options: ReplyErrOptions = ReplyErrOptions()) { jniQuery?.apply { - replyError(payload.into(), config.encoding) + replyError(payload.into(), options.encoding) jniQuery = null } ?: throw (ZError("Query is invalid")) } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index 9f582a39..c706548f 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -55,7 +55,7 @@ public void tearDown() throws ZError { } @Test - public void get_runsWithCallbackTest() { + public void get_runsWithCallbackTest() throws ZError { Reply[] reply = new Reply[1]; var getOptions = new GetOptions(); @@ -71,7 +71,7 @@ public void get_runsWithCallbackTest() { } @Test - public void get_runsWithHandlerTest() { + public void get_runsWithHandlerTest() throws ZError { var getOptions = new GetOptions(); getOptions.setTimeout(Duration.ofMillis(1000)); ArrayList receiver = session.get(selector, new TestHandler(), getOptions); From 1e72dd6464120d2c94363dda9066dd2fd6cea1f2 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 16:26:38 -0300 Subject: [PATCH 77/83] Alignment: queryable options refactor --- examples/src/main/java/io/zenoh/ZQueryable.java | 2 -- .../src/commonMain/kotlin/io/zenoh/query/Queryable.kt | 8 +------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index 240c84fe..64312b73 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -92,8 +92,6 @@ private void declareQueryableProvidingConfig(Config config, KeyExpr keyExpr) thr try (Session session = Zenoh.open(config)) { QueryableOptions queryableOptions = new QueryableOptions(); queryableOptions.setComplete(true); -// queryableConfig.setOnClose(() -> System.out.println("Queryable closed...")); - session.declareQueryable(keyExpr, this::handleQuery, queryableOptions); } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index 395b6dad..b8c3b51a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -89,10 +89,4 @@ class Queryable internal constructor( /** * TODO: add doc */ -data class QueryableOptions( - var complete: Boolean = false, - var onClose: Runnable? = null -) { - fun complete(complete: Boolean) = apply { this.complete = complete } - fun onClose(onClose: Runnable) = apply { this.onClose = onClose } -} +data class QueryableOptions(var complete: Boolean = false) From 1dffad8458ec87e02bdf40283203a1a9b9592d95 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Thu, 5 Dec 2024 16:33:44 -0300 Subject: [PATCH 78/83] Alignment: removing Resolvable --- .../commonMain/kotlin/io/zenoh/Resolvable.kt | 23 ------------------- .../src/commonMain/kotlin/io/zenoh/Session.kt | 10 ++++---- .../kotlin/io/zenoh/pubsub/Publisher.kt | 2 -- 3 files changed, 6 insertions(+), 29 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/Resolvable.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Resolvable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Resolvable.kt deleted file mode 100644 index bc0012fe..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Resolvable.kt +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh - -/** - * A resolvable function interface meant to be used by Zenoh builders. - */ -fun interface Resolvable { - - fun res(): R -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index fd213ff3..14f67542 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -198,8 +198,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { * @param keyExpr The intended Key expression. * @return A resolvable returning an optimized representation of the passed `keyExpr`. */ - fun declareKeyExpr(keyExpr: String): Resolvable = Resolvable { // TODO: remove resolvable - return@Resolvable jniSession?.run { + @Throws(ZError::class) + fun declareKeyExpr(keyExpr: String): KeyExpr { + return jniSession?.run { val keyexpr = declareKeyExpr(keyExpr) declarations.add(keyexpr) keyexpr @@ -215,8 +216,9 @@ class Session private constructor(private val config: Config) : AutoCloseable { * @param keyExpr The key expression to undeclare. * @return A resolvable returning the status of the undeclare operation. */ - fun undeclare(keyExpr: KeyExpr): Resolvable = Resolvable { - return@Resolvable jniSession?.run { + @Throws(ZError::class) + fun undeclare(keyExpr: KeyExpr) { + return jniSession?.run { undeclareKeyExpr(keyExpr) } ?: throw (sessionClosedException) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 7e9be214..1a80a66e 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -92,8 +92,6 @@ class Publisher internal constructor( /** * Performs a DELETE operation on the specified [keyExpr] - * - * @return A [Resolvable] operation. */ @JvmOverloads @Throws(ZError::class) From e3cdd1181c97b5ed6164e366c8faeb88148d47c9 Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Tue, 10 Dec 2024 14:21:05 -0300 Subject: [PATCH 79/83] Alignment: splitting Queryable, Subscriber and Get into Handler and Callback subclasses + tidying up documentation. --- examples/src/main/java/io/zenoh/ZPing.java | 7 +- examples/src/main/java/io/zenoh/ZPong.java | 9 +- examples/src/main/java/io/zenoh/ZPub.java | 8 +- examples/src/main/java/io/zenoh/ZPubThr.java | 8 +- .../src/main/java/io/zenoh/ZQueryable.java | 4 +- examples/src/main/java/io/zenoh/ZScout.java | 3 +- examples/src/main/java/io/zenoh/ZSub.java | 9 +- .../main/java/io/zenoh/ZSubLiveliness.java | 12 +- examples/src/main/java/io/zenoh/ZSubThr.java | 2 +- .../src/commonMain/kotlin/io/zenoh/Config.kt | 165 +--------- .../src/commonMain/kotlin/io/zenoh/Session.kt | 288 +++++++++++++++--- .../src/commonMain/kotlin/io/zenoh/Zenoh.kt | 67 ++-- .../commonMain/kotlin/io/zenoh/ZenohType.kt | 3 +- .../kotlin/io/zenoh/bytes/IntoZBytes.kt | 30 +- .../kotlin/io/zenoh/bytes/ZBytes.kt | 1 - .../io/zenoh/handlers/BlockingQueueHandler.kt | 4 +- .../kotlin/io/zenoh/handlers/Handler.kt | 9 +- .../kotlin/io/zenoh/jni/JNIKeyExpr.kt | 7 + .../kotlin/io/zenoh/jni/JNILiveliness.kt | 41 ++- .../kotlin/io/zenoh/jni/JNIPublisher.kt | 2 +- .../kotlin/io/zenoh/jni/JNIQueryable.kt | 2 +- .../kotlin/io/zenoh/jni/JNIScout.kt | 11 +- .../kotlin/io/zenoh/jni/JNISession.kt | 16 +- .../kotlin/io/zenoh/jni/JNISubscriber.kt | 2 +- .../kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt | 25 -- .../kotlin/io/zenoh/keyexpr/KeyExpr.kt | 8 +- .../kotlin/io/zenoh/liveliness/Liveliness.kt | 64 ++-- .../io/zenoh/liveliness/LivelinessToken.kt | 4 +- .../kotlin/io/zenoh/pubsub/DeleteOptions.kt | 6 +- .../kotlin/io/zenoh/pubsub/Publisher.kt | 14 +- .../io/zenoh/pubsub/PublisherOptions.kt | 43 ++- .../kotlin/io/zenoh/pubsub/PutOptions.kt | 30 +- .../kotlin/io/zenoh/pubsub/Subscriber.kt | 77 ++++- .../src/commonMain/kotlin/io/zenoh/qos/QoS.kt | 6 - .../commonMain/kotlin/io/zenoh/query/Get.kt | 7 +- .../kotlin/io/zenoh/query/Parameters.kt | 6 +- .../commonMain/kotlin/io/zenoh/query/Query.kt | 19 +- .../kotlin/io/zenoh/query/Queryable.kt | 99 ++++-- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 52 ++-- .../kotlin/io/zenoh/query/Selector.kt | 6 +- .../kotlin/io/zenoh/sample/Sample.kt | 3 + .../kotlin/io/zenoh/scouting/Scout.kt | 67 +++- .../kotlin/io/zenoh/scouting/ScoutOptions.kt | 6 + .../io/zenoh/session/SessionDeclaration.kt | 4 +- .../src/jvmTest/java/io/zenoh/ConfigTest.java | 2 +- .../src/jvmTest/java/io/zenoh/DeleteTest.java | 2 +- .../jvmTest/java/io/zenoh/EncodingTest.java | 2 +- .../src/jvmTest/java/io/zenoh/GetTest.java | 4 +- .../jvmTest/java/io/zenoh/KeyExprTest.java | 10 +- .../jvmTest/java/io/zenoh/PublisherTest.java | 6 +- .../src/jvmTest/java/io/zenoh/PutTest.java | 2 +- .../jvmTest/java/io/zenoh/QueryableTest.java | 2 +- .../src/jvmTest/java/io/zenoh/ScoutTest.java | 8 +- .../jvmTest/java/io/zenoh/SelectorTest.java | 9 + .../java/io/zenoh/UserAttachmentTest.java | 10 +- 55 files changed, 824 insertions(+), 489 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt diff --git a/examples/src/main/java/io/zenoh/ZPing.java b/examples/src/main/java/io/zenoh/ZPing.java index 8cacb161..76b3017c 100644 --- a/examples/src/main/java/io/zenoh/ZPing.java +++ b/examples/src/main/java/io/zenoh/ZPing.java @@ -52,8 +52,11 @@ public Integer call() throws Exception { BlockingQueue> receiverQueue = session.declareSubscriber(keyExprPong).getReceiver(); - Publisher publisher = - session.declarePublisher(keyExprPing, new PublisherOptions().congestionControl(CongestionControl.BLOCK).express(!noExpress)); + + var publisherOptions = new PublisherOptions(); + publisherOptions.setCongestionControl(CongestionControl.BLOCK); + publisherOptions.setExpress(!noExpress); + Publisher publisher = session.declarePublisher(keyExprPing, publisherOptions); byte[] data = new byte[payloadSize]; for (int i = 0; i < payloadSize; i++) { diff --git a/examples/src/main/java/io/zenoh/ZPong.java b/examples/src/main/java/io/zenoh/ZPong.java index 0a24c3dc..580bd998 100644 --- a/examples/src/main/java/io/zenoh/ZPong.java +++ b/examples/src/main/java/io/zenoh/ZPong.java @@ -45,10 +45,11 @@ public Integer call() throws Exception { KeyExpr keyExprPing = KeyExpr.tryFrom("test/ping"); KeyExpr keyExprPong = KeyExpr.tryFrom("test/pong"); - Publisher publisher = session.declarePublisher( - keyExprPong, - new PublisherOptions().congestionControl(CongestionControl.BLOCK).express(!noExpress) - ); + var publisherOptions = new PublisherOptions(); + publisherOptions.setCongestionControl(CongestionControl.BLOCK); + publisherOptions.setExpress(!noExpress); + + Publisher publisher = session.declarePublisher(keyExprPong, publisherOptions); session.declareSubscriber(keyExprPing, sample -> { try { diff --git a/examples/src/main/java/io/zenoh/ZPub.java b/examples/src/main/java/io/zenoh/ZPub.java index c4de913b..319772a9 100644 --- a/examples/src/main/java/io/zenoh/ZPub.java +++ b/examples/src/main/java/io/zenoh/ZPub.java @@ -48,10 +48,10 @@ public Integer call() throws ZError { System.out.println("Declaring publisher on '" + keyExpr + "'..."); // A publisher config can optionally be provided. - PublisherOptions publisherOptions = new PublisherOptions() // PublisherOpts - .encoding(Encoding.ZENOH_STRING) - .congestionControl(CongestionControl.BLOCK) - .reliability(Reliability.RELIABLE); + PublisherOptions publisherOptions = new PublisherOptions(); + publisherOptions.setEncoding(Encoding.ZENOH_STRING); + publisherOptions.setCongestionControl(CongestionControl.BLOCK); + publisherOptions.setReliability(Reliability.RELIABLE); // Declare the publisher Publisher publisher = session.declarePublisher(keyExpr, publisherOptions); diff --git a/examples/src/main/java/io/zenoh/ZPubThr.java b/examples/src/main/java/io/zenoh/ZPubThr.java index f70f2fde..8482f2b5 100644 --- a/examples/src/main/java/io/zenoh/ZPubThr.java +++ b/examples/src/main/java/io/zenoh/ZPubThr.java @@ -48,10 +48,10 @@ public Integer call() throws Exception { try (Session session = Zenoh.open(config)) { KeyExpr keyExpr = KeyExpr.tryFrom("test/thr"); - var publisherConfig = new PublisherOptions() - .congestionControl(CongestionControl.BLOCK) - .priority(priorityInput != null ? Priority.getEntries().get(priorityInput) : Priority.DATA); - try (Publisher publisher = session.declarePublisher(keyExpr, publisherConfig)) { + var publisherOptions = new PublisherOptions(); + publisherOptions.setCongestionControl(CongestionControl.BLOCK); + publisherOptions.setPriority(priorityInput != null ? Priority.getEntries().get(priorityInput) : Priority.DATA); + try (Publisher publisher = session.declarePublisher(keyExpr, publisherOptions)) { System.out.println("Publisher declared on test/thr."); long count = 0; long start = System.currentTimeMillis(); diff --git a/examples/src/main/java/io/zenoh/ZQueryable.java b/examples/src/main/java/io/zenoh/ZQueryable.java index 64312b73..6cb68e00 100644 --- a/examples/src/main/java/io/zenoh/ZQueryable.java +++ b/examples/src/main/java/io/zenoh/ZQueryable.java @@ -18,7 +18,6 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; import io.zenoh.query.Query; -import io.zenoh.query.Queryable; import io.zenoh.query.QueryableOptions; import io.zenoh.query.ReplyOptions; import org.apache.commons.net.ntp.TimeStamp; @@ -58,9 +57,8 @@ public Integer call() throws Exception { */ private void declareQueryableWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { try (Session session = Zenoh.open(config)) { - Queryable>> queryable = session.declareQueryable(keyExpr); + var queryable = session.declareQueryable(keyExpr); BlockingQueue> receiver = queryable.getReceiver(); - assert receiver != null; while (true) { Optional wrapper = receiver.take(); if (wrapper.isEmpty()) { diff --git a/examples/src/main/java/io/zenoh/ZScout.java b/examples/src/main/java/io/zenoh/ZScout.java index 515c4f0f..89f2be1b 100644 --- a/examples/src/main/java/io/zenoh/ZScout.java +++ b/examples/src/main/java/io/zenoh/ZScout.java @@ -16,7 +16,6 @@ import io.zenoh.config.WhatAmI; import io.zenoh.scouting.Hello; -import io.zenoh.scouting.Scout; import io.zenoh.scouting.ScoutOptions; import picocli.CommandLine; @@ -40,7 +39,7 @@ public Integer call() throws Exception { var scoutOptions = new ScoutOptions(); scoutOptions.setWhatAmI(Set.of(WhatAmI.Peer, WhatAmI.Router)); - Scout>> scout = Zenoh.scout(scoutOptions); + var scout = Zenoh.scout(scoutOptions); BlockingQueue> receiver = scout.getReceiver(); assert receiver != null; diff --git a/examples/src/main/java/io/zenoh/ZSub.java b/examples/src/main/java/io/zenoh/ZSub.java index a7c4c274..2379e70f 100644 --- a/examples/src/main/java/io/zenoh/ZSub.java +++ b/examples/src/main/java/io/zenoh/ZSub.java @@ -17,7 +17,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.handlers.Handler; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.pubsub.Subscriber; +import io.zenoh.pubsub.HandlerSubscriber; import io.zenoh.sample.Sample; import picocli.CommandLine; @@ -56,7 +56,7 @@ public Integer call() throws Exception { */ private void subscribeWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { try (Session session = Zenoh.open(config)) { - try (Subscriber>> subscriber = session.declareSubscriber(keyExpr)) { + try (HandlerSubscriber>> subscriber = session.declareSubscriber(keyExpr)) { BlockingQueue> receiver = subscriber.getReceiver(); assert receiver != null; while (true) { @@ -88,7 +88,10 @@ private void subscribeWithCallback(Config config, KeyExpr keyExpr) throws ZError private void subscribeWithHandler(Config config, KeyExpr keyExpr) throws ZError { try (Session session = Zenoh.open(config)) { QueueHandler queueHandler = new QueueHandler<>(); - session.declareSubscriber(keyExpr, queueHandler); + var subscriber = session.declareSubscriber(keyExpr, queueHandler); + for (Sample sample : subscriber.getReceiver()) { + System.out.println(sample); + } } } diff --git a/examples/src/main/java/io/zenoh/ZSubLiveliness.java b/examples/src/main/java/io/zenoh/ZSubLiveliness.java index a6c61481..cf76c9e2 100644 --- a/examples/src/main/java/io/zenoh/ZSubLiveliness.java +++ b/examples/src/main/java/io/zenoh/ZSubLiveliness.java @@ -16,8 +16,7 @@ import io.zenoh.exceptions.ZError; import io.zenoh.keyexpr.KeyExpr; -import io.zenoh.liveliness.Liveliness; -import io.zenoh.pubsub.Subscriber; +import io.zenoh.liveliness.LivelinessSubscriberOptions; import io.zenoh.sample.Sample; import io.zenoh.sample.SampleKind; import picocli.CommandLine; @@ -57,9 +56,8 @@ public Integer call() throws Exception { */ private void subscribeToLivelinessWithBlockingQueue(Config config, KeyExpr keyExpr) throws ZError, InterruptedException { try (Session session = Zenoh.open(config)) { - var options = new Liveliness.SubscriberOptions(history); - Subscriber>> subscriber = - session.liveliness().declareSubscriber(keyExpr, options); + var options = new LivelinessSubscriberOptions(history); + var subscriber = session.liveliness().declareSubscriber(keyExpr, options); BlockingQueue> receiver = subscriber.getReceiver(); System.out.println("Listening for liveliness tokens..."); @@ -80,7 +78,7 @@ private void subscribeToLivelinessWithBlockingQueue(Config config, KeyExpr keyEx */ private void subscribeToLivelinessWithCallback(Config config, KeyExpr keyExpr) throws ZError { try (Session session = Zenoh.open(config)) { - var options = new Liveliness.SubscriberOptions(history); + var options = new LivelinessSubscriberOptions(history); session.liveliness().declareSubscriber( keyExpr, this::handleLivelinessSample, @@ -98,7 +96,7 @@ private void subscribeToLivelinessWithCallback(Config config, KeyExpr keyExpr) t private void subscribeToLivelinessWithHandler(Config config, KeyExpr keyExpr) throws ZError { try (Session session = Zenoh.open(config)) { QueueHandler queueHandler = new QueueHandler<>(); - var options = new Liveliness.SubscriberOptions(history); + var options = new LivelinessSubscriberOptions(history); session.liveliness().declareSubscriber( keyExpr, queueHandler, diff --git a/examples/src/main/java/io/zenoh/ZSubThr.java b/examples/src/main/java/io/zenoh/ZSubThr.java index ebd74c8c..670967ee 100644 --- a/examples/src/main/java/io/zenoh/ZSubThr.java +++ b/examples/src/main/java/io/zenoh/ZSubThr.java @@ -168,7 +168,7 @@ private void closeSubscriber() { ) private boolean noMulticastScouting; - private Subscriber subscriber; + private Subscriber subscriber; public static void main(String[] args) { int exitCode = new CommandLine(new ZSubThr(args.length == 0)).execute(args); diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt index 9abddf27..d826e04f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt @@ -31,94 +31,7 @@ import kotlinx.serialization.json.JsonElement * * Either way, the supported formats are `yaml`, `json` and `json5`. * - * A default configuration can be loaded using [Config.default]. - * - * ## Examples: - * - * ### Loading default config: - * - * ```kotlin - * val config = Config.default() - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * ### Loading from file - * - * Using [Path]: - * ```kotlin - * val config = Config.fromFile(Path("example/path/config.json5")).getOrThrow() - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * - * or alternatively, using [File] - * ```kotlin - * val config = Config.fromFile(File("example/path/config.json5")).getOrThrow() - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * ### Embedded string configuration - * - Json5 - * ```kotlin - * val json5config = """ - * { - * mode: "peer", - * connect: { - * endpoints: ["tcp/localhost:7450"], - * }, - * scouting: { - * multicast: { - * enabled: false, - * } - * } - * } - * """.trimIndent() - * val config = Config.fromJson5(json5config).getOrThrow() - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * - * - Json - * ```kotlin - * val jsonConfig = """ - * { - * mode: "peer", - * listen: { - * endpoints: ["tcp/localhost:7450"], - * }, - * scouting: { - * multicast: { - * enabled: false, - * } - * } - * } - * """.trimIndent() - * val config = Config.fromJson(jsonConfig).getOrThrow() - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * - * - Yaml - * ```kotlin - * val yamlConfig = """ - * mode: peer - * connect: - * endpoints: - * - tcp/localhost:7450 - * scouting: - * multicast: - * enabled: false - * """.trimIndent() - * val config = Config.fromYaml(yamlConfig).getOrThrow() - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` + * A default configuration can be loaded using [Config.loadDefault]. * * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more * information on the Zenoh config parameters. @@ -166,29 +79,6 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { /** * Loads the configuration from json-formatted string. * - * Example: - * ```kotlin - * val config = Config.fromJson( - * config = """ - * { - * "mode": "peer", - * "connect": { - * "endpoints": ["tcp/localhost:7450"] - * }, - * "scouting": { - * "multicast": { - * "enabled": false - * } - * } - * } - * """.trimIndent() - * ).getOrThrow() - * - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more * information on the Zenoh config parameters. * @@ -204,29 +94,6 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { /** * Loads the configuration from json5-formatted string. * - * Example: - * ```kotlin - * val config = Config.fromJson5( - * config = """ - * { - * mode: "peer", - * connect: { - * endpoints: ["tcp/localhost:7450"], - * }, - * scouting: { - * multicast: { - * enabled: false, - * } - * } - * } - * """.trimIndent() - * ).getOrThrow() - * - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more * information on the Zenoh config parameters. * @@ -242,25 +109,6 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { /** * Loads the configuration from yaml-formatted string. * - * Example: - * ```kotlin - * val config = Config.fromYaml( - * config = """ - * mode: peer - * connect: - * endpoints: - * - tcp/localhost:7450 - * scouting: - * multicast: - * enabled: false - * """.trimIndent() - * ).getOrThrow() - * - * Zenoh.open(config).onSuccess { - * // ... - * } - * ``` - * * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more * information on the Zenoh config parameters. * @@ -273,17 +121,6 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { return JNIConfig.loadYamlConfig(config) } -// /** TODO -// * Loads the configuration from the [jsonElement] specified. -// * -// * @param jsonElement The zenoh config as a [JsonElement]. -// */ -// @JvmStatic -// @Throws(ZError::class) -// fun fromJsonElement(jsonElement: JsonElement): Config { -// return JNIConfig.loadJsonConfig(jsonElement.toString()) -// } - /** * Loads the configuration from the env variable [CONFIG_ENV]. * diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index 14f67542..c944e83c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -40,7 +40,6 @@ import java.util.concurrent.LinkedBlockingDeque * A session is typically associated with declarations such as [Publisher]s, [Subscriber]s, or [Queryable]s, which are * declared using [declarePublisher], [declareSubscriber], and [declareQueryable], respectively. * Other operations such as simple Put, Get or Delete can be performed from a session using [put], [get] and [delete]. - * Finally, it's possible to declare key expressions ([KeyExpr]) as well. * * Sessions are open upon creation and can be closed manually by calling [close]. Alternatively, the session will be * automatically closed when used with Java's try-with-resources statement or its Kotlin counterpart, [use]. @@ -91,7 +90,6 @@ class Session private constructor(private val config: Config) : AutoCloseable { jniSession = null } - @Suppress("removal") protected fun finalize() { close() } @@ -99,7 +97,32 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Publisher] on the session. * - * TODO + * Example: + * ```java + * try (Session session = Zenoh.open(config)) { + * // A publisher config can optionally be provided. + * PublisherOptions publisherOptions = new PublisherOptions(); + * publisherOptions.setEncoding(Encoding.ZENOH_STRING); + * publisherOptions.setCongestionControl(CongestionControl.BLOCK); + * publisherOptions.setReliability(Reliability.RELIABLE); + * + * // Declare the publisher + * Publisher publisher = session.declarePublisher(keyExpr, publisherOptions); + * + * int idx = 0; + * while (true) { + * Thread.sleep(1000); + * String payload = String.format("[%4d] %s", idx, value); + * System.out.println("Putting Data ('" + keyExpr + "': '" + payload + "')..."); + * publisher.put(ZBytes.from(payload)); + * idx++; + * } + * } + * ``` + * + * @param keyExpr The [KeyExpr] the publisher will be associated to. + * @param publisherOptions Optional [PublisherOptions] to configure the publisher. + * @return The declared [Publisher]. */ @JvmOverloads @Throws(ZError::class) @@ -110,10 +133,29 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** * Declare a [Subscriber] on the session. * - * TODO + * Example with blocking queue (default receiver): + * ```java + * try (Session session = Zenoh.open(config)) { + * try (HandlerSubscriber>> subscriber = session.declareSubscriber(keyExpr)) { + * BlockingQueue> receiver = subscriber.getReceiver(); + * assert receiver != null; + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * System.out.println(wrapper.get()); + * handleSample(wrapper.get()); + * } + * } + * } + * ``` + * + * @param keyExpr The [KeyExpr] the subscriber will be associated to. + * @return [HandlerSubscriber] with a [BlockingQueue] as a receiver. */ @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr): Subscriber>> { + fun declareSubscriber(keyExpr: KeyExpr): HandlerSubscriber>> { return resolveSubscriberWithHandler( keyExpr, BlockingQueueHandler(LinkedBlockingDeque()) @@ -121,58 +163,161 @@ class Session private constructor(private val config: Config) : AutoCloseable { } /** - * Declare a [Subscriber] on the session. + * Declare a [Subscriber] on the session using a handler. + * + * Example with a custom handler: + * ```java + * // Example handler that stores the received samples into a queue. + * class QueueHandler implements Handler> { + * + * final ArrayDeque queue = new ArrayDeque<>(); * - * TODO + * @Override + * public void handle(Sample t) { + * queue.add(t); + * } + * + * @Override + * public ArrayDeque receiver() { + * return queue; + * } + * + * @Override + * public void onClose() {} + * } + * + * // ... + * + * try (Session session = Zenoh.open(config)) { + * QueueHandler queueHandler = new QueueHandler(); + * var subscriber = session.declareSubscriber(keyExpr, queueHandler); + * // ... + * } + * ``` + * + * @param R the [handler]'s receiver type. + * @param keyExpr The [KeyExpr] the subscriber will be associated to. + * @param handler The [Handler] to process the incoming [Sample]s received by the subscriber. + * @return A [HandlerSubscriber] with the [handler]'s receiver. */ @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, handler: Handler): Subscriber { + fun declareSubscriber(keyExpr: KeyExpr, handler: Handler): HandlerSubscriber { return resolveSubscriberWithHandler(keyExpr, handler) } /** - * Declare a [Subscriber] on the session. + * Declare a [Subscriber] on the session using a callback. * - * TODO + * Example with a callback: + * ```java + * try (Session session = Zenoh.open(config)) { + * var subscriber = session.declareSubscriber(keyExpr, sample -> System.out.println(sample)); + * // ... + * } + * ``` + * + * @param keyExpr The [KeyExpr] the subscriber will be associated to. + * @param callback [Callback] for handling the incoming samples. + * @return A [CallbackSubscriber]. */ @Throws(ZError::class) - fun declareSubscriber(keyExpr: KeyExpr, callback: Callback): Subscriber { + fun declareSubscriber(keyExpr: KeyExpr, callback: Callback): CallbackSubscriber { return resolveSubscriberWithCallback(keyExpr, callback) } /** * Declare a [Queryable] on the session. * - * TODO + * Example using a blocking queue (default receiver): + * ```java + * try (Session session = Zenoh.open(config)) { + * var queryable = session.declareQueryable(keyExpr); + * var receiver = queryable.getReceiver(); + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * Query query = wrapper.get(); + * query.reply(query.getKeyExpr(), ZBytes.from("Example reply)); + * } + * } + * ``` + * + * @param keyExpr The [KeyExpr] the queryable will be associated to. + * @param options Optional [QueryableOptions] for configuring the queryable. + * @return A [HandlerQueryable] with a [BlockingQueue] receiver. */ @Throws(ZError::class) @JvmOverloads fun declareQueryable( keyExpr: KeyExpr, options: QueryableOptions = QueryableOptions() - ): Queryable>> { + ): HandlerQueryable>> { return resolveQueryableWithHandler(keyExpr, BlockingQueueHandler(LinkedBlockingDeque()), options) } /** * Declare a [Queryable] on the session. * - * TODO + * Example using a custom [Handler]: + * ```java + * // Example handler that replies with the amount of queries received. + * class QueryHandler implements Handler { + * + * private Int counter = 0; + * + * @Override + * public void handle(Query query) { + * var keyExpr = query.getKeyExpr(); + * query.reply(keyExpr, ZBytes.from("Reply #" + counter + "!")); + * counter++; + * } + * + * @Override + * public Void receiver() {} + * + * @Override + * public void onClose() {} + * } + * + * // ... + * try (Session session = Zenoh.open(config)) { + * var queryable = session.declareQueryable(keyExpr, new QueryHandler()); + * //... + * } + * ``` + * + * @param R The type of the [handler]'s receiver. + * @param keyExpr The [KeyExpr] the queryable will be associated to. + * @param handler The [Handler] to handle the incoming queries. + * @param options Optional [QueryableOptions] for configuring the queryable. + * @return A [HandlerQueryable] with the handler's receiver. */ @Throws(ZError::class) @JvmOverloads - fun declareQueryable(keyExpr: KeyExpr, handler: Handler, options: QueryableOptions = QueryableOptions()): Queryable { + fun declareQueryable(keyExpr: KeyExpr, handler: Handler, options: QueryableOptions = QueryableOptions()): HandlerQueryable { return resolveQueryableWithHandler(keyExpr, handler, options) } /** * Declare a [Queryable] on the session. * - * TODO + * ```java + * try (Session session = Zenoh.open(config)) { + * var queryable = session.declareQueryable(keyExpr, query -> query.reply(keyExpr, ZBytes.from("Example reply"))); + * //... + * } + * ``` + * + * @param keyExpr The [KeyExpr] the queryable will be associated to. + * @param callback The [Callback] to handle the incoming queries. + * @param options Optional [QueryableOptions] for configuring the queryable. + * @return A [CallbackQueryable]. */ @Throws(ZError::class) @JvmOverloads - fun declareQueryable(keyExpr: KeyExpr, callback: Callback, options: QueryableOptions = QueryableOptions()): Queryable { + fun declareQueryable(keyExpr: KeyExpr, callback: Callback, options: QueryableOptions = QueryableOptions()): CallbackQueryable { return resolveQueryableWithCallback(keyExpr, callback, options) } @@ -185,18 +330,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { * a queryable, or a publisher will also inform Zenoh of your intent to use their * key expressions repeatedly. * - * Example: - * ```java - * try (Session session = session.open()) { - * try (KeyExpr keyExpr = session.declareKeyExpr("demo/java/example").res()) { - * Publisher publisher = session.declarePublisher(keyExpr).res(); - * // ... - * } - * } - * ``` - * * @param keyExpr The intended Key expression. - * @return A resolvable returning an optimized representation of the passed `keyExpr`. + * @return The declared [KeyExpr]. */ @Throws(ZError::class) fun declareKeyExpr(keyExpr: String): KeyExpr { @@ -224,11 +359,28 @@ class Session private constructor(private val config: Config) : AutoCloseable { } /** - * Declare a [Get] with a [BlockingQueue] receiver. + * Perform a get query handling the replies through a [BlockingQueue]. * + * Example using the default blocking queue receiver: * ```java - * TODO: provide example + * try (Session session = Zenoh.open(config)) { + * System.out.println("Performing Get on '" + selector + "'..."); + * BlockingQueue> receiver = session.get(Selector.from("a/b/c")); + * + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * Reply reply = wrapper.get(); + * System.out.println(reply); + * } + * } * ``` + * + * @param selector The [Selector] for the get query. + * @param options Optional [GetOptions] to configure the get query. + * @return A [BlockingQueue] with the received replies. */ @JvmOverloads @Throws(ZError::class) @@ -242,7 +394,41 @@ class Session private constructor(private val config: Config) : AutoCloseable { } /** - * TODO + * Perform a get query handling the replies through a [Handler]. + * + * Example using a custom handler: + * ```java + * // Example handler that prints the replies along with a counter: + * class GetHandler implements Handler { + * + * private Int counter = 0; + * + * @Override + * public void handle(Reply reply) { + * System.out.println("Reply #" + counter + ": " + reply); + * counter++; + * } + * + * @Override + * public Void receiver() {} + * + * @Override + * public void onClose() {} + * } + * + * //... + * try (Session session = Zenoh.open(config)) { + * System.out.println("Performing Get on '" + selector + "'..."); + * session.get(Selector.from("a/b/c"), new GetHandler()); + * //... + * } + * ``` + * + * @param R The type of the [handler]'s receiver. + * @param selector The [Selector] for the get query. + * @param handler The [Handler] to handle the incoming replies. + * @param options Optional [GetOptions] to configure the query. + * @return The handler's receiver. */ @JvmOverloads @Throws(ZError::class) @@ -251,7 +437,19 @@ class Session private constructor(private val config: Config) : AutoCloseable { } /** - * TODO + * Perform a get query, handling the replies with a [Callback]. + * + * Example: + * ```java + * try (Session session = Zenoh.open(config)) { + * session.get(Selector.from("a/b/c"), reply -> System.out.println(reply)); + * //... + * } + * ``` + * + * @param selector The [Selector] for the get query. + * @param callback The [Callback] to handle the incoming replies. + * @param options Optional [GetOptions] to configure the query. */ @JvmOverloads @Throws(ZError::class) @@ -260,8 +458,17 @@ class Session private constructor(private val config: Config) : AutoCloseable { } /** - * Declare a [Put] with the provided value on the specified key expression. - * //TODO update + * Perform a put with the provided [payload] to the specified [keyExpr]. + * + * Example: + * ```java + * session.put(KeyExpr.from("a/b/c"), ZBytes.from("Example payload")); + * //... + * ``` + * + * @param keyExpr The [KeyExpr] for performing the put. + * @param payload The payload to put. + * @param options Optional [PutOptions] to configure the put. */ @JvmOverloads @Throws(ZError::class) @@ -270,7 +477,10 @@ class Session private constructor(private val config: Config) : AutoCloseable { } /** - * TODO + * Perform a delete operation to the specified [keyExpr]. + * + * @param keyExpr The [KeyExpr] for performing the delete operation. + * @param options Optional [DeleteOptions] to configure the delete operation. */ @JvmOverloads @Throws(ZError::class) @@ -309,7 +519,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriberWithHandler( keyExpr: KeyExpr, handler: Handler - ): Subscriber { + ): HandlerSubscriber { return jniSession?.run { val subscriber = declareSubscriberWithHandler(keyExpr, handler) declarations.add(subscriber) @@ -320,7 +530,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveSubscriberWithCallback( keyExpr: KeyExpr, callback: Callback - ): Subscriber { + ): CallbackSubscriber { return jniSession?.run { val subscriber = declareSubscriberWithCallback(keyExpr, callback) declarations.add(subscriber) @@ -331,7 +541,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithHandler( keyExpr: KeyExpr, handler: Handler, options: QueryableOptions - ): Queryable { + ): HandlerQueryable { return jniSession?.run { val queryable = declareQueryableWithHandler(keyExpr, handler, options) declarations.add(queryable) @@ -342,7 +552,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolveQueryableWithCallback( keyExpr: KeyExpr, callback: Callback, options: QueryableOptions - ): Queryable { + ): CallbackQueryable { return jniSession?.run { val queryable = declareQueryableWithCallback(keyExpr, callback, options) declarations.add(queryable) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index dfd8c942..7a5931f8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -15,14 +15,12 @@ package io.zenoh import io.zenoh.Logger.Companion.LOG_ENV -import io.zenoh.scouting.Hello -import io.zenoh.scouting.Scout import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler import io.zenoh.jni.JNIScout -import io.zenoh.scouting.ScoutOptions +import io.zenoh.scouting.* import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque @@ -46,19 +44,14 @@ object Zenoh { * * Scout spawns a task that periodically sends scout messages and waits for Hello replies. * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + * + * @param scoutOptions Optional [ScoutOptions] to configure the scouting. + * @return A [HandlerScout] with a [BlockingQueue] receiver. */ + @JvmOverloads @JvmStatic - fun scout(): Scout>> { - val scoutOptions = ScoutOptions() - val handler = BlockingQueueHandler(LinkedBlockingDeque>()) - return JNIScout.scoutWithHandler( - scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, - receiver = handler.receiver(), config = scoutOptions.config - ) - } - - @JvmStatic - fun scout(scoutOptions: ScoutOptions): Scout>> { + @Throws(ZError::class) + fun scout(scoutOptions: ScoutOptions = ScoutOptions()): HandlerScout>> { val handler = BlockingQueueHandler(LinkedBlockingDeque>()) return JNIScout.scoutWithHandler( scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, @@ -66,33 +59,41 @@ object Zenoh { ) } + /** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + * + * @param R The [handler]'s receiver type. + * @param handler [Handler] to handle the incoming [Hello] messages. + * @param scoutOptions Optional [ScoutOptions] to configure the scouting. + * @return A [HandlerScout] with the handler's receiver. + */ + @JvmOverloads @JvmStatic - fun scout(handler: Handler): Scout { - val scoutOptions = ScoutOptions() - return JNIScout.scoutWithHandler( - scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, - receiver = handler.receiver(), config = scoutOptions.config - ) - } - - @JvmStatic - fun scout(handler: Handler, scoutOptions: ScoutOptions): Scout { + @Throws(ZError::class) + fun scout(handler: Handler, scoutOptions: ScoutOptions = ScoutOptions()): HandlerScout { return JNIScout.scoutWithHandler( scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, receiver = handler.receiver(), config = scoutOptions.config ) } + /** + * Scout for routers and/or peers. + * + * Scout spawns a task that periodically sends scout messages and waits for Hello replies. + * Drop the returned Scout to stop the scouting task or explicitly call [Scout.stop] or [Scout.close]. + * + * @param callback [Callback] to handle the incoming [Hello] messages. + * @param scoutOptions Optional [ScoutOptions] to configure the scouting. + * @return A [CallbackScout] with the handler's receiver. + */ + @JvmOverloads @JvmStatic - fun scout(callback: Callback): Scout { - val scoutOptions = ScoutOptions() - return JNIScout.scoutWithCallback( - scoutOptions.whatAmI, callback, config = scoutOptions.config - ) - } - - @JvmStatic - fun scout(callback: Callback, scoutOptions: ScoutOptions): Scout { + @Throws(ZError::class) + fun scout(callback: Callback, scoutOptions: ScoutOptions = ScoutOptions()): CallbackScout { return JNIScout.scoutWithCallback( scoutOptions.whatAmI, callback, config = scoutOptions.config ) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ZenohType.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ZenohType.kt index 3089ea3c..b8940500 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ZenohType.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/ZenohType.kt @@ -1,8 +1,7 @@ package io.zenoh /** - * Zenoh type. An empty interface to regroup elements of type [io.zenoh.sample.Sample], - * [io.zenoh.query.Reply] and [io.zenoh.queryable.Query]. + * Zenoh type. * * This kind of elements have in common that they can be received through the Zenoh network. */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt index 41f6f86c..a988c34f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/IntoZBytes.kt @@ -1,3 +1,17 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + package io.zenoh.bytes /** @@ -6,10 +20,20 @@ package io.zenoh.bytes * Classes implementing this interface can be serialized into a ZBytes object. * * Example: - * ```kotlin - * class Foo(val content: String) : IntoZBytes { + * ```java + * class Foo implements IntoZBytes { + * + * private final String content; + * + * Foo(String content) { + * this.content = content; + * } * - * override fun into(): ZBytes = content.into() + * @NotNull + * @Override + * public ZBytes into() { + * return ZBytes.from(content); + * } * } * ``` */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt index a4462396..1fd22d7c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt @@ -29,7 +29,6 @@ package io.zenoh.bytes * encouraged to use any data format of their choice like JSON, protobuf, * flatbuffers, etc. * - * See also: [ZBytes examples](https://github.com/eclipse-zenoh/zenoh-kotlin/blob/main/examples/src/main/kotlin/io.zenoh/ZBytes.kt) */ class ZBytes internal constructor(internal val bytes: ByteArray) : IntoZBytes { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt index b6ffe3ac..93a64182 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/BlockingQueueHandler.kt @@ -21,9 +21,7 @@ import java.util.concurrent.BlockingQueue /** * Blocking queue handler * - * Implementation of a [Handler] with a [BlockingQueue] receiver. This handler is intended to be used - * as the default handler by the [io.zenoh.queryable.Queryable], [io.zenoh.subscriber.Subscriber] and [io.zenoh.query.Get], - * allowing us to send the incoming elements through a [BlockingQueue]. + * Implementation of a [Handler] with a [BlockingQueue] receiver. * * The way to tell no more elements of type [T] will be received is when an empty element is put (see [onClose]). * diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/Handler.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/Handler.kt index 0647e852..422d6d95 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/Handler.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/handlers/Handler.kt @@ -21,6 +21,9 @@ import io.zenoh.ZenohType * incoming [T] elements. * * **Example**: + * In this example we implement a handler that stores the received elements into an ArrayDeque, + * which can then be retrieved: + * * ```java * public class QueueHandler implements Handler> { * @@ -46,12 +49,12 @@ import io.zenoh.ZenohType * * That `QueueHandler` could then be used as follows, for instance for a subscriber: * ```java - * QueueHandler handler = new QueueHandler(); - * session.declareSubscriber(keyExpr).with(handler).res(); + * var queue = session.declareSubscriber(keyExpr, new QueueHandler()); * ... * ``` + * where the `queue` returned is the receiver from the handler. * - * @param T A receiving [ZenohType], either a [io.zenoh.sample.Sample], a [io.zenoh.query.Reply] or a [io.zenoh.queryable.Query]. + * @param T A receiving [ZenohType]. * @param R An arbitrary receiver. */ interface Handler { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt index 4b7fc8cf..29e419e3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt @@ -26,14 +26,17 @@ internal class JNIKeyExpr(internal val ptr: Long) { ZenohLoad } + @Throws(ZError::class) fun tryFrom(keyExpr: String): KeyExpr { return KeyExpr(tryFromViaJNI(keyExpr)) } + @Throws(ZError::class) fun autocanonize(keyExpr: String): KeyExpr { return KeyExpr(autocanonizeViaJNI(keyExpr)) } + @Throws(ZError::class) fun intersects(keyExprA: KeyExpr, keyExprB: KeyExpr): Boolean = intersectsViaJNI( keyExprA.jniKeyExpr?.ptr ?: 0, keyExprA.keyExpr, @@ -41,6 +44,7 @@ internal class JNIKeyExpr(internal val ptr: Long) { keyExprB.keyExpr ) + @Throws(ZError::class) fun includes(keyExprA: KeyExpr, keyExprB: KeyExpr): Boolean = includesViaJNI( keyExprA.jniKeyExpr?.ptr ?: 0, keyExprA.keyExpr, @@ -48,6 +52,7 @@ internal class JNIKeyExpr(internal val ptr: Long) { keyExprB.keyExpr ) + @Throws(ZError::class) fun relationTo(keyExpr: KeyExpr, other: KeyExpr): SetIntersectionLevel { val intersection = relationToViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, @@ -58,10 +63,12 @@ internal class JNIKeyExpr(internal val ptr: Long) { return SetIntersectionLevel.fromInt(intersection) } + @Throws(ZError::class) fun joinViaJNI(keyExpr: KeyExpr, other: String): KeyExpr { return KeyExpr(joinViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other)) } + @Throws(ZError::class) fun concatViaJNI(keyExpr: KeyExpr, other: String): KeyExpr { return KeyExpr(concatViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other)) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt index 47d522e5..6d6a5aef 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt @@ -24,7 +24,8 @@ import io.zenoh.jni.callbacks.JNIOnCloseCallback import io.zenoh.jni.callbacks.JNISubscriberCallback import io.zenoh.keyexpr.KeyExpr import io.zenoh.liveliness.LivelinessToken -import io.zenoh.pubsub.Subscriber +import io.zenoh.pubsub.CallbackSubscriber +import io.zenoh.pubsub.HandlerSubscriber import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority import io.zenoh.qos.QoS @@ -98,14 +99,46 @@ internal object JNILiveliness { return LivelinessToken(JNILivelinessToken(ptr)) } + fun declareSubscriber( + jniSession: JNISession, + keyExpr: KeyExpr, + callback: Callback, + history: Boolean, + onClose: () -> Unit + ): CallbackSubscriber { + val subCallback = + JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> + val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null + val sample = Sample( + KeyExpr(keyExpr2, null), + payload.into(), + Encoding(encodingId, schema = encodingSchema), + SampleKind.fromInt(kind), + timestamp, + QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), + attachmentBytes?.into() + ) + callback.run(sample) + } + val ptr = declareSubscriberViaJNI( + jniSession.sessionPtr.get(), + keyExpr.jniKeyExpr?.ptr ?: 0, + keyExpr.keyExpr, + subCallback, + history, + onClose + ) + return CallbackSubscriber(keyExpr, JNISubscriber(ptr)) + } + fun declareSubscriber( jniSession: JNISession, keyExpr: KeyExpr, callback: Callback, - receiver: R?, + receiver: R, history: Boolean, onClose: () -> Unit - ): Subscriber { + ): HandlerSubscriber { val subCallback = JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null @@ -128,7 +161,7 @@ internal object JNILiveliness { history, onClose ) - return Subscriber(keyExpr, receiver, JNISubscriber(ptr)) + return HandlerSubscriber(keyExpr, JNISubscriber(ptr), receiver) } private external fun getViaJNI( diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt index 2ee414bc..6e694271 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt @@ -19,7 +19,7 @@ import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes /** - * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.publication.Publisher]. + * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.pubsub.Publisher]. * * @property ptr: raw pointer to the underlying native Publisher. */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt index f17df868..e5f7d3ce 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt @@ -15,7 +15,7 @@ package io.zenoh.jni /** - * Adapter class to handle the interactions with Zenoh through JNI for a [Queryable] + * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.query.Queryable] * * @property ptr: raw pointer to the underlying native Queryable. */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt index c326e3f2..f2e1c49c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt @@ -21,9 +21,10 @@ import io.zenoh.handlers.Callback import io.zenoh.jni.callbacks.JNIScoutCallback import io.zenoh.config.ZenohId import io.zenoh.scouting.Hello -import io.zenoh.scouting.Scout import io.zenoh.config.WhatAmI import io.zenoh.jni.callbacks.JNIOnCloseCallback +import io.zenoh.scouting.CallbackScout +import io.zenoh.scouting.HandlerScout /** * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.scouting.Scout] @@ -45,13 +46,13 @@ internal class JNIScout(private val ptr: Long) { onClose: () -> Unit, config: Config?, receiver: R - ): Scout { + ): HandlerScout { val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List -> callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) } val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, onClose,config?.jniConfig?.ptr ?: 0) - return Scout(receiver, JNIScout(ptr)) + return HandlerScout(JNIScout(ptr), receiver) } @Throws(ZError::class) @@ -59,13 +60,13 @@ internal class JNIScout(private val ptr: Long) { whatAmI: Set, callback: Callback, config: Config?, - ): Scout { + ): CallbackScout { val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List -> callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) } val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, fun() {},config?.jniConfig?.ptr ?: 0) - return Scout(null, JNIScout(ptr)) + return CallbackScout(JNIScout(ptr)) } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index eaa131f1..f67f9889 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -82,7 +82,7 @@ internal class JNISession { @Throws(ZError::class) fun declareSubscriberWithHandler( keyExpr: KeyExpr, handler: Handler - ): Subscriber { + ): HandlerSubscriber { val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null @@ -100,13 +100,13 @@ internal class JNISession { val subscriberRawPtr = declareSubscriberViaJNI( keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), subCallback, handler::onClose ) - return Subscriber(keyExpr, handler.receiver(), JNISubscriber(subscriberRawPtr)) + return HandlerSubscriber(keyExpr, JNISubscriber(subscriberRawPtr), handler.receiver()) } @Throws(ZError::class) fun declareSubscriberWithCallback( keyExpr: KeyExpr, callback: Callback - ): Subscriber { + ): CallbackSubscriber { val subCallback = JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null @@ -128,13 +128,13 @@ internal class JNISession { subCallback, fun() {} ) - return Subscriber(keyExpr, null, JNISubscriber(subscriberRawPtr)) + return CallbackSubscriber(keyExpr, JNISubscriber(subscriberRawPtr)) } @Throws(ZError::class) fun declareQueryableWithCallback( keyExpr: KeyExpr, callback: Callback, config: QueryableOptions - ): Queryable { + ): CallbackQueryable { val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> val jniQuery = JNIQuery(queryPtr) @@ -162,13 +162,13 @@ internal class JNISession { fun() {}, config.complete ) - return Queryable(keyExpr, null, JNIQueryable(queryableRawPtr)) + return CallbackQueryable(keyExpr, JNIQueryable(queryableRawPtr)) } @Throws(ZError::class) fun declareQueryableWithHandler( keyExpr: KeyExpr, handler: Handler, config: QueryableOptions - ): Queryable { + ): HandlerQueryable { val queryCallback = JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long -> val jniQuery = JNIQuery(queryPtr) @@ -196,7 +196,7 @@ internal class JNISession { handler::onClose, config.complete ) - return Queryable(keyExpr, handler.receiver(), JNIQueryable(queryableRawPtr)) + return HandlerQueryable(keyExpr, JNIQueryable(queryableRawPtr), handler.receiver()) } @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt index 73bd2dad..1bb80543 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt @@ -15,7 +15,7 @@ package io.zenoh.jni /** - * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.subscriber.Subscriber] + * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.pubsub.Subscriber] * * @property ptr: raw pointer to the underlying native Subscriber. */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt deleted file mode 100644 index f9ace4d8..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/IntoKeyExpr.kt +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.keyexpr - -import io.zenoh.exceptions.ZError - -@Throws(ZError::class) -fun String.intoKeyExpr(): KeyExpr { - if (this.isEmpty()) { - throw(ZError("Attempting to create a KeyExpr from an empty string.")) - } - return KeyExpr.autocanonize(this) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt index 24ea7cd6..b5fe6110 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt @@ -58,9 +58,6 @@ import io.zenoh.query.Selector * As an alternative, employing a try-with-resources pattern using Kotlin's `use` block is recommended. This approach * ensures that [close] is automatically called, safely managing the lifecycle of the [KeyExpr] instance. * - * @param keyExpr The string representation of the key expression. - * @param jniKeyExpr An optional [JNIKeyExpr] instance, present when the key expression was declared through [Session.declareKeyExpr], - * it represents the native instance of the key expression. */ class KeyExpr internal constructor(internal val keyExpr: String, internal var jniKeyExpr: JNIKeyExpr? = null): AutoCloseable, IntoSelector, SessionDeclaration { @@ -107,6 +104,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * defined by `this` and `other`. * Will return false as well if the key expression is not valid anymore. */ + @Throws(ZError::class) fun intersects(other: KeyExpr): Boolean { return JNIKeyExpr.intersects(this, other) } @@ -116,15 +114,17 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * defined by `this`. * Will return false as well if the key expression is not valid anymore. */ + @Throws(ZError::class) fun includes(other: KeyExpr): Boolean { return JNIKeyExpr.includes(this, other) } /** - * Returns the relation between 'this' and other from 'this''s point of view (SetIntersectionLevel::Includes + * Returns the relation between 'this' and other from 'this''s point of view ([SetIntersectionLevel.INCLUDES] * signifies that self includes other). Note that this is slower than [intersects] and [includes], * so you should favor these methods for most applications. */ + @Throws(ZError::class) fun relationTo(other: KeyExpr): SetIntersectionLevel { return JNIKeyExpr.relationTo(this, other) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt index e7fb1f1e..96711557 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt @@ -15,11 +15,14 @@ package io.zenoh.liveliness import io.zenoh.Session +import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler import io.zenoh.jni.JNILiveliness import io.zenoh.keyexpr.KeyExpr +import io.zenoh.pubsub.CallbackSubscriber +import io.zenoh.pubsub.HandlerSubscriber import io.zenoh.pubsub.Subscriber import io.zenoh.query.Reply import io.zenoh.sample.Sample @@ -43,6 +46,7 @@ class Liveliness internal constructor(private val session: Session) { /** * Create a LivelinessToken for the given key expression. */ + @Throws(ZError::class) fun declareToken(keyExpr: KeyExpr): LivelinessToken { val jniSession = session.jniSession ?: throw Session.sessionClosedException return JNILiveliness.declareToken(jniSession, keyExpr) @@ -55,6 +59,7 @@ class Liveliness internal constructor(private val session: Session) { * @param timeout Optional timeout of the query, defaults to 10 secs. */ @JvmOverloads + @Throws(ZError::class) fun get( keyExpr: KeyExpr, timeout: Duration = Duration.ofMillis(10000), @@ -79,6 +84,7 @@ class Liveliness internal constructor(private val session: Session) { * @param timeout Optional timeout of the query, defaults to 10 secs. */ @JvmOverloads + @Throws(ZError::class) fun get( keyExpr: KeyExpr, callback: Callback, timeout: Duration = Duration.ofMillis(10000) ) { @@ -95,6 +101,7 @@ class Liveliness internal constructor(private val session: Session) { * @param timeout Optional timeout of the query, defaults to 10 secs. */ @JvmOverloads + @Throws(ZError::class) fun get( keyExpr: KeyExpr, handler: Handler, timeout: Duration = Duration.ofMillis(10000) ): R { @@ -114,55 +121,65 @@ class Liveliness internal constructor(private val session: Session) { * Create a [Subscriber] for liveliness changes matching the given key expression. * * @param keyExpr The [KeyExpr] the subscriber will be listening to. - * @param callback The [Callback] to be run when a liveliness change is received. + * @param options Optional [LivelinessSubscriberOptions] parameter for subscriber configuration. */ @JvmOverloads + @Throws(ZError::class) fun declareSubscriber( keyExpr: KeyExpr, - callback: Callback, - options: SubscriberOptions = SubscriberOptions() - ): Subscriber { + options: LivelinessSubscriberOptions = LivelinessSubscriberOptions() + ): HandlerSubscriber>> { + val handler = BlockingQueueHandler(LinkedBlockingDeque()) val jniSession = session.jniSession ?: throw Session.sessionClosedException return JNILiveliness.declareSubscriber( jniSession, keyExpr, - callback, - null, + handler::handle, + handler.receiver(), options.history, - fun() {} + handler::onClose ) } /** * Create a [Subscriber] for liveliness changes matching the given key expression. * - * @param R The [Handler.receiver] type. * @param keyExpr The [KeyExpr] the subscriber will be listening to. - * @param handler [Handler] to handle liveliness changes events. + * @param callback The [Callback] to be run when a liveliness change is received. + * @param options Optional [LivelinessSubscriberOptions] parameter for subscriber configuration. */ @JvmOverloads - fun declareSubscriber( + @Throws(ZError::class) + fun declareSubscriber( keyExpr: KeyExpr, - handler: Handler, - options: SubscriberOptions = SubscriberOptions() - ): Subscriber { + callback: Callback, + options: LivelinessSubscriberOptions = LivelinessSubscriberOptions() + ): CallbackSubscriber { val jniSession = session.jniSession ?: throw Session.sessionClosedException return JNILiveliness.declareSubscriber( jniSession, keyExpr, - handler::handle, - handler.receiver(), + callback, options.history, - handler::onClose + fun() {} ) } + /** + * Create a [Subscriber] for liveliness changes matching the given key expression. + * + * @param R The [Handler.receiver] type. + * @param keyExpr The [KeyExpr] the subscriber will be listening to. + * @param handler [Handler] to handle liveliness changes events. + * @param options Optional [LivelinessSubscriberOptions] parameter for subscriber configuration. + */ @JvmOverloads - fun declareSubscriber( + @Throws(ZError::class) + fun declareSubscriber( keyExpr: KeyExpr, - options: SubscriberOptions = SubscriberOptions() - ): Subscriber>> { - val handler = BlockingQueueHandler(LinkedBlockingDeque()) + handler: Handler, + options: LivelinessSubscriberOptions = LivelinessSubscriberOptions() + ): HandlerSubscriber { val jniSession = session.jniSession ?: throw Session.sessionClosedException return JNILiveliness.declareSubscriber( jniSession, @@ -173,6 +190,9 @@ class Liveliness internal constructor(private val session: Session) { handler::onClose ) } - - data class SubscriberOptions(var history: Boolean = false) } + +/** + * Options for the [Liveliness] subscriber. + */ +data class LivelinessSubscriberOptions(var history: Boolean = false) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt index 386b84e0..5d95b8fa 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt @@ -18,7 +18,7 @@ import io.zenoh.jni.JNILivelinessToken import io.zenoh.session.SessionDeclaration /** - * A token whose liveliness is tied to the Zenoh [Session]. + * A token whose liveliness is tied to the Zenoh [io.zenoh.Session]. * * A declared liveliness token will be seen as alive by any other Zenoh * application in the system that monitors it while the liveliness token @@ -28,8 +28,6 @@ import io.zenoh.session.SessionDeclaration * that monitors it. * * Liveliness tokens are automatically undeclared when dropped. - * - * TODO: provide example */ class LivelinessToken internal constructor(private var jniLivelinessToken: JNILivelinessToken?): SessionDeclaration, AutoCloseable { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt index 0ee1898f..cc488ce9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt @@ -19,7 +19,11 @@ import io.zenoh.qos.QoS import io.zenoh.qos.Reliability /** - * TODO + * Options for delete operations. + * + * @param qos The [QoS] (Quality of Service) desired. + * @param reliability The [Reliability] desired. + * @param attachment Optional attachment for the delete operation. */ data class DeleteOptions( var qos: QoS = QoS.defaultQoS(), diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 1a80a66e..00b4d0b5 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -20,8 +20,6 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIPublisher import io.zenoh.keyexpr.KeyExpr -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.session.SessionDeclaration import kotlin.Throws @@ -32,18 +30,18 @@ import kotlin.Throws * A publisher is automatically dropped when using it with the 'try-with-resources' statement (i.e. 'use' in Kotlin). * The session from which it was declared will also keep a reference to it and undeclare it once the session is closed. * - * In order to declare a publisher, [Session.declarePublisher] must be called, which returns a [Publisher.Builder] from - * which we can specify the [Priority], and the [CongestionControl]. + * In order to declare a publisher, [Session.declarePublisher] must be called. * * Example: * ```java * try (Session session = Session.open()) { * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/java/greeting")) { * System.out.println("Declaring publisher on '" + keyExpr + "'..."); - * try (Publisher publisher = session.declarePublisher(keyExpr).res()) { + * try (Publisher publisher = session.declarePublisher(keyExpr)) { * int i = 0; * while (true) { - * publisher.put("Hello for the " + i + "th time!").res(); + * var payload = ZBytes.from("Hello for the " + i + "th time!"); + * publisher.put(payload); * Thread.sleep(1000); * i++; * } @@ -57,9 +55,7 @@ import kotlin.Throws * The publisher configuration parameters can be later changed using the setter functions. * * @property keyExpr The key expression the publisher will be associated to. - * @property qos [QoS] configuration of the publisher. - * @property jniPublisher Delegate class handling the communication with the native code. - * @constructor Create empty Publisher with the default configuration. + * @property encoding The encoding user by the publisher. */ class Publisher internal constructor( val keyExpr: KeyExpr, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt index 36ad4651..a0461699 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt @@ -15,27 +15,48 @@ package io.zenoh.pubsub import io.zenoh.bytes.Encoding -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority -import io.zenoh.qos.QoS -import io.zenoh.qos.Reliability +import io.zenoh.qos.* /** - * TODO + * Options for the publisher. + * + * @param encoding The encoding of the payload. + * @param reliability The desired reliability. + * @param qos The quality of service desired. */ data class PublisherOptions(var reliability: Reliability = Reliability.RELIABLE, var qos: QoS = QoS.defaultQoS(), var encoding: Encoding = Encoding.defaultEncoding()) { - fun reliability(reliability: Reliability) = apply { this.reliability = reliability } + fun getQoS(): QoS { + return qos + } - fun encoding(encoding: Encoding) = apply { this.encoding = encoding } + fun getCongestionControl(): CongestionControl { + return this.qos.congestionControl + } - fun qos(qos: QoS) = apply { this.qos = qos } + fun getExpress(): Boolean { + return this.qos.express + } - fun congestionControl(congestionControl: CongestionControl) = apply { this.qos.congestionControl = congestionControl } + fun getPriority(): Priority { + return this.qos.priority + } - fun express(express: Boolean) = apply { this.qos.express = express } + fun setQoS(qos: QoS) { + this.qos = qos + } - fun priority(priority: Priority) = apply { this.qos.priority = priority } + fun setCongestionControl(congestionControl: CongestionControl) { + this.qos.congestionControl = congestionControl + } + + fun setExpress(express: Boolean) { + this.qos.express = express + } + + fun setPriority(priority: Priority) { + this.qos.priority = priority + } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt index 7c2bb8f4..c2b747f3 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt @@ -16,13 +16,15 @@ package io.zenoh.pubsub import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority -import io.zenoh.qos.QoS -import io.zenoh.qos.Reliability +import io.zenoh.qos.* /** - * TODO + * Options for the PUT operations. + * + * @param encoding The encoding of the payload. + * @param reliability The desired reliability. + * @param attachment Optional attachment. + * @param qos The quality of service desired. */ data class PutOptions( var encoding: Encoding? = null, @@ -30,26 +32,44 @@ data class PutOptions( var reliability: Reliability = Reliability.RELIABLE, var attachment: IntoZBytes? = null ) { + /** + * Get the congestion control. + */ fun getCongestionControl(): CongestionControl { return this.qos.congestionControl } + /** + * Get the express value of the QoS. + */ fun getExpress(): Boolean { return this.qos.express } + /** + * Get the priority. + */ fun getPriority(): Priority { return this.qos.priority } + /** + * Set the QoS congestion control. + */ fun setCongestionControl(congestionControl: CongestionControl) { this.qos.congestionControl = congestionControl } + /** + * Set the QoS express value. + */ fun setExpress(express: Boolean) { this.qos.express = express } + /** + * Set the priority desired. + */ fun setPriority(priority: Priority) { this.qos.priority = priority } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index 6363fd70..a3688303 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -26,10 +26,44 @@ import io.zenoh.session.SessionDeclaration * * Example using the default [BlockingQueueHandler] handler: * - * TODO + * ```java + * var queue = session.declareSubscriber("a/b/c"); + * try (Session session = Zenoh.open(config)) { + * try (var subscriber = session.declareSubscriber(keyExpr)) { + * var receiver = subscriber.getReceiver(); + * assert receiver != null; + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * System.out.println(wrapper.get()); + * } + * } + * } + * ``` + * + * Example using a callback: + * ```java + * try (Session session = Zenoh.open(config)) { + * session.declareSubscriber(keyExpr, System.out::println); + * } + * ``` + * + * Example using a handler: + * ```java + * class MyHandler implements Handler> {...} + * + * //... + * try (Session session = Zenoh.open(config)) { + * var handler = new MyHandler(); + * var arraylist = session.declareSubscriber(keyExpr, handler); + * // ... + * } + * ``` */ -class Subscriber internal constructor( - val keyExpr: KeyExpr, val receiver: R?, private var jniSubscriber: JNISubscriber? +sealed class Subscriber( + val keyExpr: KeyExpr, private var jniSubscriber: JNISubscriber? ) : AutoCloseable, SessionDeclaration { fun isValid(): Boolean { @@ -49,3 +83,40 @@ class Subscriber internal constructor( jniSubscriber?.close() } } + +/** + * Subscriber using a callback to handle incoming samples. + * + * Example: + * ```java + * try (Session session = Zenoh.open(config)) { + * session.declareSubscriber(keyExpr, System.out::println); + * } + * ``` + */ +class CallbackSubscriber internal constructor(keyExpr: KeyExpr, jniSubscriber: JNISubscriber?): Subscriber(keyExpr, jniSubscriber) + +/** + * Subscriber using a [io.zenoh.handlers.Handler] for handling incoming samples. + * + * Example using the default handler: + * ```java + * try (Session session = Zenoh.open(config)) { + * try (HandlerSubscriber>> subscriber = session.declareSubscriber(keyExpr)) { + * BlockingQueue> receiver = subscriber.getReceiver(); + * assert receiver != null; + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * System.out.println(wrapper.get()); + * } + * } + * } + * ``` + * + * @param R The type of the receiver. + * @param receiver The receiver of the subscriber's handler. + */ +class HandlerSubscriber internal constructor(keyExpr: KeyExpr, jniSubscriber: JNISubscriber?, val receiver: R): Subscriber(keyExpr, jniSubscriber) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt index 28b8c114..56a0ad7c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt @@ -27,12 +27,6 @@ data class QoS ( var express: Boolean = false ) { - fun congestionControl(congestionControl: CongestionControl) = apply { this.congestionControl = congestionControl } - - fun priority(priority: Priority) = apply { this.priority = priority } - - fun express(express: Boolean) = apply { this.express = express } - companion object { private val defaultQoS = QoS() diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt index a970e39e..08d7a506 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Get.kt @@ -21,7 +21,12 @@ import java.time.Duration /** * Get to query data from the matching queryables in the system. * - * TODO + * @param timeout Timeout of the query. + * @param target The [QueryTarget] of the query. + * @param consolidation The [ConsolidationMode] of the query. + * @param payload Optional payload. + * @param encoding Encoding of the payload. + * @param attachment Optional attachment. */ data class GetOptions( var timeout: Duration = Duration.ofMillis(10000), diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt index 33573314..241ade35 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Parameters.kt @@ -103,9 +103,9 @@ data class Parameters internal constructor(private val params: MutableMap? = params[key]?.split(VALUE_SEPARATOR) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index e8fb7dea..0d4de0af 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -34,9 +34,6 @@ import io.zenoh.sample.SampleKind * @property payload Optional payload in case the received query was declared using "with query". * @property encoding Encoding of the [payload]. * @property attachment Optional attachment. - * @property jniQuery Delegate object in charge of communicating with the underlying native code. - * @constructor Instances of Query objects are only meant to be created through the JNI upon receiving - * a query request. Therefore, the constructor is private. */ class Query internal constructor( val keyExpr: KeyExpr, @@ -55,6 +52,7 @@ class Query internal constructor( * * @param keyExpr Key expression to reply to. This parameter must not be necessarily the same * as the key expression from the Query, however it must intersect with the query key. + * @param options Optional options for configuring the reply. */ @Throws(ZError::class) @JvmOverloads @@ -75,7 +73,11 @@ class Query internal constructor( } /** - * TODO + * Reply "delete" to the specified key expression. + * + * @param keyExpr Key expression to reply to. This parameter must not be necessarily the same + * as the key expression from the Query, however it must intersect with the query key. + * @param options Optional options for configuring the reply. */ @JvmOverloads @Throws(ZError::class) @@ -92,13 +94,16 @@ class Query internal constructor( } /** - * TODO + * Reply "error" to the specified key expression. + * + * @param message The error message. + * @param options Optional options for configuring the reply. */ @JvmOverloads @Throws(ZError::class) - fun replyErr(payload: IntoZBytes, options: ReplyErrOptions = ReplyErrOptions()) { + fun replyErr(message: IntoZBytes, options: ReplyErrOptions = ReplyErrOptions()) { jniQuery?.apply { - replyError(payload.into(), options.encoding) + replyError(message.into(), options.encoding) jniQuery = null } ?: throw (ZError("Query is invalid")) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index b8c3b51a..eab11c56 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -14,13 +14,11 @@ package io.zenoh.query -import io.zenoh.* import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler import io.zenoh.jni.JNIQueryable import io.zenoh.keyexpr.KeyExpr import io.zenoh.session.SessionDeclaration -import java.util.* /** * A queryable that allows to perform multiple queries on the specified [KeyExpr]. @@ -29,54 +27,53 @@ import java.util.* * * Example using the default [BlockingQueueHandler] handler: * ```java - * try (Session session = Session.open()) { - * try (KeyExpr keyExpr = KeyExpr.tryFrom("demo/example/zenoh-java-queryable")) { - * System.out.println("Declaring Queryable"); - * try (Queryable>> queryable = session.declareQueryable(keyExpr).res()) { - * BlockingQueue> receiver = queryable.getReceiver(); - * while (true) { - * Optional wrapper = receiver.take(); - * if (wrapper.isEmpty()) { - * break; - * } - * Query query = wrapper.get(); - * String valueInfo = query.getValue() != null ? " with value '" + query.getValue() + "'" : ""; - * System.out.println(">> [Queryable] Received Query '" + query.getSelector() + "'" + valueInfo); - * try { - * query.reply(keyExpr) - * .success("Queryable from Java!") - * .withKind(SampleKind.PUT) - * .withTimeStamp(TimeStamp.getCurrentTime()) - * .res(); - * } catch (Exception e) { - * System.out.println(">> [Queryable] Error sending reply: " + e); - * } - * } + * try (Session session = Zenoh.open(config)) { + * var queryable = session.declareQueryable(keyExpr); + * BlockingQueue> receiver = queryable.getReceiver(); + * assert receiver != null; + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; * } + * Query query = wrapper.get(); + * query.reply(query.getKeyExpr(), ZBytes.from("Example reply"); * } * } * ``` * - * @param R Receiver type of the [Handler] implementation. If no handler is provided to the builder, [R] will be [Unit]. + * Example using a [io.zenoh.handlers.Callback]: + * ```java + * try (Session session = Zenoh.open(config)) { + * var queryable = session.declareQueryable(keyExpr, query -> query.reply(query.getKeyExpr(), ZBytes.from("Example reply")); + * } + * ``` + * * @property keyExpr The [KeyExpr] to which the subscriber is associated. - * @property receiver Optional [R] that is provided when specifying a [Handler] for the subscriber. * @property jniQueryable Delegate object in charge of communicating with the underlying native code. - * @constructor Internal constructor. Instances of Queryable must be created through the [Builder] obtained after - * calling [Session.declareQueryable] or alternatively through [newBuilder]. + * @see CallbackQueryable + * @see HandlerQueryable */ -class Queryable internal constructor( - val keyExpr: KeyExpr, val receiver: R?, private var jniQueryable: JNIQueryable? +sealed class Queryable( + val keyExpr: KeyExpr, private var jniQueryable: JNIQueryable? ) : AutoCloseable, SessionDeclaration { fun isValid(): Boolean { return jniQueryable != null } + /** + * Undeclares the queryable. + */ override fun undeclare() { jniQueryable?.close() jniQueryable = null } + /** + * Closes the queryable, equivalent to [undeclare]. This function is automatically called + * when using try with resources. + */ override fun close() { undeclare() } @@ -87,6 +84,44 @@ class Queryable internal constructor( } /** - * TODO: add doc + * [Queryable] receiving replies through a callback. + * + * Example + * ```java + * try (Session session = Zenoh.open(config)) { + * CallbackQueryable queryable = session.declareQueryable(keyExpr, query -> query.reply(query.getKeyExpr(), ZBytes.from("Example reply")); + * } + * ``` + */ +class CallbackQueryable internal constructor(keyExpr: KeyExpr, jniQueryable: JNIQueryable?): Queryable(keyExpr, jniQueryable) + +/** + * [Queryable] receiving replies through a [Handler]. + * + * Example using the default receiver: + * ```java + * try (Session session = Zenoh.open(config)) { + * Queryable>> queryable = session.declareQueryable(keyExpr); + * BlockingQueue> receiver = queryable.getReceiver(); + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * Query query = wrapper.get(); + * query.reply(query.getKeyExpr(), ZBytes.from("Example reply"); + * } + * } + * ``` + * + * @param R The type of the handler's receiver. + * @param receiver The receiver of the queryable's handler. + */ +class HandlerQueryable internal constructor(keyExpr: KeyExpr, jniQueryable: JNIQueryable?, val receiver: R): Queryable(keyExpr, jniQueryable) + +/** + * Options for configuring a [Queryable]. + * + * @param complete The completeness of the information the queryable provides. */ data class QueryableOptions(var complete: Boolean = false) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index a06a2a8d..a5b48aef 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -25,24 +25,17 @@ import io.zenoh.qos.QoS import org.apache.commons.net.ntp.TimeStamp /** - * Class to represent a Zenoh Reply to a [Get] operation and to a remote [Query]. - * - * A reply can be either successful ([Success]) or an error ([Error]), both having different information. For instance, - * the successful reply will contain a [Sample] while the error reply will only contain a [Value] with the error information. - * - * Replies can either be automatically created when receiving a remote reply after performing a [Get] (in which case the - * [replierId] shows the id of the replier) or created through the builders while answering to a remote [Query] (in that - * case the replier ID is automatically added by Zenoh). - * - * Generating a reply only makes sense within the context of a [Query], therefore builders below are meant to only - * be accessible from [Query.reply]. - * - * TODO: provide example + * Class to represent a Zenoh Reply to a remote query. * * @property replierId: unique ID identifying the replier. + * @see Success + * @see Error */ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { + /** + * A Success reply. + */ class Success internal constructor(replierId: ZenohId?, val sample: Sample) : Reply(replierId) { override fun toString(): String { @@ -61,6 +54,9 @@ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { } + /** + * An Error reply. + */ class Error internal constructor(replierId: ZenohId?, val error: ZBytes, val encoding: Encoding) : Reply(replierId) { @@ -82,7 +78,12 @@ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { } /** - * TODO + * Options for performing a [Reply] to a [Query]. + * + * @param encoding [Encoding] of the payload of the reply. + * @param timeStamp Optional timestamp. + * @param attachment Optional attachment. + * @param qos The [QoS] for the reply. */ data class ReplyOptions( var encoding: Encoding = Encoding.defaultEncoding(), @@ -115,23 +116,27 @@ data class ReplyOptions( /** * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. */ - fun setExpress(express: Boolean) { qos.express(express) } + fun setExpress(express: Boolean) { qos.express = express } /** * Sets the [Priority] of the reply. */ - fun setPriority(priority: Priority) { qos.priority(priority) } + fun setPriority(priority: Priority) { qos.priority = priority } /** * Sets the [CongestionControl] of the reply. * * @param congestionControl */ - fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl(congestionControl) } + fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl = congestionControl } } /** - * TODO + * Options for performing a Reply Delete to a [Query]. + * + * @param timeStamp Optional timestamp. + * @param attachment Optional attachment. + * @param qos The [QoS] for the reply. */ data class ReplyDelOptions( var timeStamp: TimeStamp? = null, @@ -162,22 +167,25 @@ data class ReplyDelOptions( /** * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. */ - fun setExpress(express: Boolean) { qos.express(express) } + fun setExpress(express: Boolean) { qos.express = express } /** * Sets the [Priority] of the reply. */ - fun setPriority(priority: Priority) { qos.priority(priority) } + fun setPriority(priority: Priority) { qos.priority = priority } /** * Sets the [CongestionControl] of the reply. * * @param congestionControl */ - fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl(congestionControl) } + fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl = congestionControl } } + /** - * TODO + * Options for performing a Reply Err to a [Query]. + * + * @param encoding The encoding of the error message. */ data class ReplyErrOptions(var encoding: Encoding = Encoding.defaultEncoding()) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt index 6a9fb106..34e5cd4f 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Selector.kt @@ -69,7 +69,8 @@ data class Selector(val keyExpr: KeyExpr, val parameters: Parameters? = null) : * with the encouraged behaviour being to reject operations when a duplicate parameter is detected. * * @param selector The selector expression as a String. - * @return a Result with the constructed Selector. + * @return An instance [Selector]. + * @throws ZError in case of failure processing the selector. */ @Throws(ZError::class) @JvmStatic @@ -100,6 +101,3 @@ data class Selector(val keyExpr: KeyExpr, val parameters: Parameters? = null) : interface IntoSelector { fun into(): Selector } - -@Throws(ZError::class) -fun String.intoSelector(): Selector = Selector.tryFrom(this) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt index 98bbf282..adb99cd8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt @@ -31,6 +31,9 @@ import org.apache.commons.net.ntp.TimeStamp * @property timestamp Optional [TimeStamp]. * @property qos The Quality of Service settings used to deliver the sample. * @property attachment Optional attachment. + * @property express The express value in the [qos]. + * @property congestionControl The congestion control in the [qos]. + * @property priority The priority in the [qos]. */ data class Sample( val keyExpr: KeyExpr, diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt index 7e1de8c3..8034a851 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt @@ -23,17 +23,45 @@ import io.zenoh.jni.JNIScout * Drop the returned Scout to stop the scouting task. * * To launch a scout, use [io.zenoh.Zenoh.scout]: - * ```kotlin - * Zenoh.scout(callback = { hello -> - * println(hello) - * }).getOrThrow() + * + * Example using the default blocking queue handler: + * ```java + * + * var scoutOptions = new ScoutOptions(); + * scoutOptions.setWhatAmI(Set.of(WhatAmI.Peer, WhatAmI.Router)); + * + * var scout = Zenoh.scout(scoutOptions); + * BlockingQueue> receiver = scout.getReceiver(); + * + * try { + * while (true) { + * Optional wrapper = receiver.take(); + * if (wrapper.isEmpty()) { + * break; + * } + * + * Hello hello = wrapper.get(); + * System.out.println(hello); + * } + * } finally { + * scout.stop(); + * } * ``` * - * @param R The receiver type. - * @param receiver Receiver to handle incoming hello messages. + * Example using a callback: + * ```java + * var scoutOptions = new ScoutOptions(); + * scoutOptions.setWhatAmI(Set.of(WhatAmI.Peer, WhatAmI.Router)); + * Zenoh.scout(hello -> { + * //... + * System.out.println(hello); + * }, scoutOptions); + * ``` + * + * @see CallbackScout + * @see HandlerScout */ -class Scout internal constructor( - val receiver: R?, +sealed class Scout ( private var jniScout: JNIScout? ) : AutoCloseable { @@ -56,3 +84,26 @@ class Scout internal constructor( stop() } } + +/** + * Scout using a callback to handle incoming [Hello] messages. + * + * Example: + * ```java + * CallbackScout scout = Zenoh.scout(hello -> {...}); + * ``` + */ +class CallbackScout internal constructor(jniScout: JNIScout?) : Scout(jniScout) + +/** + * Scout using a handler to handle incoming [Hello] messages. + * + * Example + * ```java + * HandlerScout>> scout = Zenoh.scout(); + * ``` + * + * @param R The type of the receiver. + * @param receiver The receiver of the scout's handler. + */ +class HandlerScout internal constructor(jniScout: JNIScout?, val receiver: R) : Scout(jniScout) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt index 94e8452f..3f3f9f13 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/ScoutOptions.kt @@ -17,6 +17,12 @@ package io.zenoh.scouting import io.zenoh.Config import io.zenoh.config.WhatAmI +/** + * Options for scouting. + * + * @param config A [Config] for scouting. + * @param whatAmI [WhatAmI] parameters. + */ data class ScoutOptions( var config: Config? = null, var whatAmI: Set = setOf(WhatAmI.Peer, WhatAmI.Router) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt index 79041640..2c3a9224 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/session/SessionDeclaration.kt @@ -17,8 +17,8 @@ package io.zenoh.session /** * Session declaration. * - * A session declaration is either a [io.zenoh.publication.Publisher], - * a [io.zenoh.subscriber.Subscriber] or a [io.zenoh.queryable.Queryable] declared from a [Session]. + * A session declaration is either a [io.zenoh.pubsub.Publisher], + * a [io.zenoh.pubsub.Subscriber] or a [io.zenoh.query.Queryable] declared from a [io.zenoh.Session]. */ interface SessionDeclaration { diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java index 2fe40bac..990c5452 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ConfigTest.java @@ -131,7 +131,7 @@ private void runSessionTest(Config clientConfig, Config serverConfig) throws ZEr final Sample[] receivedSample = new Sample[1]; - Subscriber subscriber = + Subscriber subscriber = sessionClient.declareSubscriber(TEST_KEY_EXP, sample -> receivedSample[0] = sample); ZBytes payload = ZBytes.from("example message"); sessionClient.put(TEST_KEY_EXP, payload); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java index 285b14e7..6b31ae6f 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/DeleteTest.java @@ -34,7 +34,7 @@ public void deleteIsProperlyReceivedBySubscriberTest() throws ZError, Interrupte Session session = Zenoh.open(Config.loadDefault()); final Sample[] receivedSample = new Sample[1]; KeyExpr keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); session.delete(keyExpr); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java index f40d4399..a524672b 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/EncodingTest.java @@ -43,7 +43,7 @@ public void encoding_subscriberTest() throws ZError, InterruptedException { // Testing non null schema Sample[] receivedSample = new Sample[1]; - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); var putOptions = new PutOptions(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java index c706548f..b929bb92 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/GetTest.java @@ -28,7 +28,7 @@ public class GetTest { private Session session; private Selector selector; - private Queryable queryable; + private Queryable queryable; @Before public void setUp() throws ZError { @@ -86,7 +86,7 @@ public void get_runsWithHandlerTest() throws ZError { public void getWithSelectorParamsTest() throws ZError { Parameters[] receivedParams = new Parameters[1]; - Queryable queryable = session.declareQueryable(selector.getKeyExpr(), query -> + Queryable queryable = session.declareQueryable(selector.getKeyExpr(), query -> receivedParams[0] = query.getParameters() ); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java index a246b482..eca1aba4 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/KeyExprTest.java @@ -90,7 +90,7 @@ public void includesTest() throws ZError { @Test public void sessionDeclarationTest() throws ZError { Session session = Zenoh.open(Config.loadDefault()); - KeyExpr keyExpr = session.declareKeyExpr("a/b/c").res(); + KeyExpr keyExpr = session.declareKeyExpr("a/b/c"); assertEquals("a/b/c", keyExpr.toString()); session.close(); keyExpr.close(); @@ -99,17 +99,17 @@ public void sessionDeclarationTest() throws ZError { @Test public void sessionUnDeclarationTest() throws ZError { Session session = Zenoh.open(Config.loadDefault()); - KeyExpr keyExpr = session.declareKeyExpr("a/b/c").res(); + KeyExpr keyExpr = session.declareKeyExpr("a/b/c"); assertEquals("a/b/c", keyExpr.toString()); - session.undeclare(keyExpr).res(); + session.undeclare(keyExpr); // Undeclaring twice a key expression shall fail. - assertThrows(ZError.class, () -> session.undeclare(keyExpr).res()); + assertThrows(ZError.class, () -> session.undeclare(keyExpr)); // Undeclaring a key expr that was not declared through a session. KeyExpr keyExpr2 = KeyExpr.tryFrom("x/y/z"); - assertThrows(ZError.class, () -> session.undeclare(keyExpr2).res()); + assertThrows(ZError.class, () -> session.undeclare(keyExpr2)); session.close(); } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java index 227e28ad..d1e158f1 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PublisherTest.java @@ -30,7 +30,7 @@ public class PublisherTest { private Session session; private ArrayList receivedSamples; private Publisher publisher; - private Subscriber subscriber; + private Subscriber subscriber; private KeyExpr keyExpr; @Before @@ -38,7 +38,9 @@ public void setUp() throws ZError { session = Zenoh.open(Config.loadDefault()); keyExpr = KeyExpr.tryFrom("example/testing/keyexpr"); - var config = new PublisherOptions(Reliability.RELIABLE, QoS.defaultQoS(), Encoding.ZENOH_STRING); + var config = new PublisherOptions(); + config.setReliability(Reliability.RELIABLE); + config.setEncoding(Encoding.ZENOH_STRING); publisher = session.declarePublisher(keyExpr, config); receivedSamples = new ArrayList<>(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java index a4f560e2..71b8cb5c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/PutTest.java @@ -40,7 +40,7 @@ public void putTest() throws ZError { Sample[] receivedSample = new Sample[1]; var keyExpr = KeyExpr.tryFrom(TEST_KEY_EXP); - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); var putOptions = new PutOptions(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index 2101de90..d56501e6 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -134,7 +134,7 @@ public void queryReplySuccessTest() throws ZError { var message = ZBytes.from("Test message"); var timestamp = TimeStamp.getCurrentTime(); - Queryable queryable = session.declareQueryable(testKeyExpr, query -> { + Queryable queryable = session.declareQueryable(testKeyExpr, query -> { var options = new ReplyOptions(); options.setTimeStamp(timestamp); options.setPriority(Priority.DATA_HIGH); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java index 18b5a751..80530b1f 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/ScoutTest.java @@ -40,7 +40,7 @@ public void scouting_queueTest() throws ZError, InterruptedException { Thread.sleep(1000); - Scout>> scout = Zenoh.scout(); + var scout = Zenoh.scout(); Thread.sleep(1000); scout.close(); @@ -70,7 +70,7 @@ public void scouting_callbackTest() throws ZError, InterruptedException { } @Test - public void scouting_whatAmITest() { + public void scouting_whatAmITest() throws ZError { var scoutOptions = new ScoutOptions(); scoutOptions.setWhatAmI(Set.of(WhatAmI.Client, WhatAmI.Peer)); var scout = Zenoh.scout(scoutOptions); @@ -78,8 +78,8 @@ public void scouting_whatAmITest() { } @Test - public void scouting_onCloseTest() { - Scout>> scout = Zenoh.scout(); + public void scouting_onCloseTest() throws ZError { + var scout = Zenoh.scout(); var receiver = scout.getReceiver(); scout.close(); diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java index 8a7cc7d9..9252dd3f 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/SelectorTest.java @@ -15,11 +15,14 @@ package io.zenoh; import io.zenoh.exceptions.ZError; +import io.zenoh.query.Parameters; import io.zenoh.query.Selector; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.List; + import static org.junit.Assert.*; @RunWith(JUnit4.class) @@ -38,4 +41,10 @@ public void selector_fromStringTest() throws ZError { assertThrows(ZError.class, () -> Selector.tryFrom("")); } + + @Test + public void parametersTest() { + var parameters = Parameters.from("a=1;b=2;c=1|2|3"); + assertEquals(List.of("1", "2", "3"), parameters.values("c")); + } } diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java index e8695da0..1f0a4d2f 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/UserAttachmentTest.java @@ -63,7 +63,7 @@ public void tearDown() { @Test public void putWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); var putOptions = new PutOptions(); @@ -81,7 +81,7 @@ public void putWithAttachmentTest() throws ZError { public void publisherPutWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); var putOptions = new PutOptions(); @@ -100,7 +100,7 @@ public void publisherPutWithAttachmentTest() throws ZError { public void publisherPutWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); publisher.put(payload); @@ -116,7 +116,7 @@ public void publisherPutWithoutAttachmentTest() throws ZError { public void publisherDeleteWithAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); var deleteOptions = new DeleteOptions(); @@ -135,7 +135,7 @@ public void publisherDeleteWithAttachmentTest() throws ZError { public void publisherDeleteWithoutAttachmentTest() throws ZError { Sample[] receivedSample = new Sample[1]; var publisher = session.declarePublisher(keyExpr); - Subscriber subscriber = + Subscriber subscriber = session.declareSubscriber(keyExpr, sample -> receivedSample[0] = sample); publisher.delete(); From 795fbff8ecf242549abcf49e3b9b0c9368055bec Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 11 Dec 2024 00:25:39 -0300 Subject: [PATCH 80/83] Alignment: removing JNIZBytes --- .../kotlin/io/zenoh/jni/JNIZBytes.kt | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt deleted file mode 100644 index 8e9e94b2..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.ZenohLoad -import io.zenoh.bytes.ZBytes -import kotlin.reflect.KType - -@PublishedApi -internal object JNIZBytes { - - init { - ZenohLoad - } - - external fun serializeViaJNI(any: Any, kType: KType): ZBytes - - external fun deserializeViaJNI(zBytes: ZBytes, kType: KType): Any -} From 2f741207c34cfb1599d858684e8b3a2b27065baa Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 11 Dec 2024 01:47:25 -0300 Subject: [PATCH 81/83] Alignment: removing unused kotlin json dependency --- zenoh-java/build.gradle.kts | 2 +- .../src/commonMain/kotlin/io/zenoh/Config.kt | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/zenoh-java/build.gradle.kts b/zenoh-java/build.gradle.kts index 0b582541..c398631e 100644 --- a/zenoh-java/build.gradle.kts +++ b/zenoh-java/build.gradle.kts @@ -59,7 +59,7 @@ kotlin { val commonMain by getting { dependencies { implementation("commons-net:commons-net:3.9.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") +// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") } } val commonTest by getting { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt index d826e04f..91bc0e01 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt @@ -18,7 +18,6 @@ import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIConfig import java.io.File import java.nio.file.Path -import kotlinx.serialization.json.JsonElement /** * # Config @@ -148,21 +147,6 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { /** * Inserts a json5 value associated to the [key] into the Config. - * - * Example: - * ```kotlin - * val config = Config.default() - * - * // ... - * val scouting = """ - * { - * multicast: { - * enabled: true, - * } - * } - * """.trimIndent() - * config.insertJson5("scouting", scouting).getOrThrow() - * ``` */ @Throws(ZError::class) fun insertJson5(key: String, value: String) { From 1645dab9be8ce7cf6f8277d7234404826a528dbf Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 18 Dec 2024 18:10:14 -0300 Subject: [PATCH 82/83] Alignment: options refactor on QoS param --- examples/src/main/java/io/zenoh/ZGet.java | 50 ++++------ zenoh-java/build.gradle.kts | 1 - .../kotlin/io/zenoh/jni/JNISession.kt | 21 ++-- .../kotlin/io/zenoh/pubsub/DeleteOptions.kt | 12 ++- .../kotlin/io/zenoh/pubsub/Publisher.kt | 10 +- .../io/zenoh/pubsub/PublisherOptions.kt | 45 ++------- .../kotlin/io/zenoh/pubsub/PutOptions.kt | 54 ++--------- .../src/commonMain/kotlin/io/zenoh/qos/QoS.kt | 5 +- .../commonMain/kotlin/io/zenoh/query/Query.kt | 5 +- .../commonMain/kotlin/io/zenoh/query/Reply.kt | 97 +++---------------- .../kotlin/io/zenoh/sample/Sample.kt | 6 +- .../jvmTest/java/io/zenoh/QueryableTest.java | 6 +- 12 files changed, 85 insertions(+), 227 deletions(-) diff --git a/examples/src/main/java/io/zenoh/ZGet.java b/examples/src/main/java/io/zenoh/ZGet.java index f8491cf1..c840be96 100644 --- a/examples/src/main/java/io/zenoh/ZGet.java +++ b/examples/src/main/java/io/zenoh/ZGet.java @@ -14,10 +14,10 @@ package io.zenoh; -import io.zenoh.bytes.Encoding; import io.zenoh.bytes.ZBytes; import io.zenoh.exceptions.ZError; import io.zenoh.query.GetOptions; +import io.zenoh.query.QueryTarget; import io.zenoh.query.Selector; import io.zenoh.query.Reply; import io.zenoh.sample.SampleKind; @@ -46,21 +46,29 @@ public Integer call() throws ZError, InterruptedException { Config config = loadConfig(emptyArgs, configFile, connect, listen, noMulticastScouting, mode); Selector selector = Selector.tryFrom(this.selectorOpt); + // Load GET options + GetOptions options = new GetOptions(); + options.setPayload(ZBytes.from(this.payload)); + options.setTarget(QueryTarget.valueOf(this.target)); + options.setTimeout(Duration.ofMillis(this.timeout)); + options.setAttachment(ZBytes.from(this.attachment)); + + // A GET query can be performed in different ways, by default (using a blocking queue), using a callback // or providing a handler. Uncomment one of the function calls below to try out different implementations: // Implementation with a blocking queue - getExampleDefault(config, selector); - // getExampleWithCallback(config, selector); - // getExampleWithHandler(config, selector); - // getExampleProvidingConfig(config, selector); + getExampleDefault(config, selector, options); + // getExampleWithCallback(config, selector, options); + // getExampleWithHandler(config, selector, options); return 0; } - private void getExampleDefault(Config config, Selector selector) throws ZError, InterruptedException { + private void getExampleDefault(Config config, Selector selector, GetOptions options) throws ZError, InterruptedException { try (Session session = Zenoh.open(config)) { System.out.println("Performing Get on '" + selector + "'..."); - BlockingQueue> receiver = session.get(selector); + + BlockingQueue> receiver = session.get(selector, options); while (true) { Optional wrapper = receiver.take(); @@ -77,10 +85,10 @@ private void getExampleDefault(Config config, Selector selector) throws ZError, * Example using a simple callback for handling the replies. * @see io.zenoh.handlers.Callback */ - private void getExampleWithCallback(Config config, Selector selector) throws ZError { + private void getExampleWithCallback(Config config, Selector selector, GetOptions options) throws ZError { try (Session session = Zenoh.open(config)) { System.out.println("Performing Get on '" + selector + "'..."); - session.get(selector, this::handleReply); + session.get(selector, this::handleReply, options); } } @@ -89,31 +97,11 @@ private void getExampleWithCallback(Config config, Selector selector) throws ZEr * @see QueueHandler * @see io.zenoh.handlers.Handler */ - private void getExampleWithHandler(Config config, Selector selector) throws ZError { + private void getExampleWithHandler(Config config, Selector selector, GetOptions options) throws ZError { try (Session session = Zenoh.open(config)) { System.out.println("Performing Get on '" + selector + "'..."); QueueHandler queueHandler = new QueueHandler<>(); - session.get(selector, queueHandler); - } - } - - /** - * The purpose of this example is to show how to provide configuration parameters - * to the get query. For this, you can optionally provide a GetConfig parameter. - * @see GetOptions - */ - private void getExampleProvidingConfig(Config config, Selector selector) throws ZError { - try (Session session = Zenoh.open(config)) { - System.out.println("Performing Get on '" + selector + "'..."); - - // Build the config - GetOptions getOptions = new GetOptions(); - getOptions.setTimeout(Duration.ofMillis(1000)); - getOptions.setEncoding(Encoding.ZENOH_STRING); - getOptions.setPayload(ZBytes.from("Example payload")); - - // Apply the config - session.get(selector, this::handleReply, getOptions); + session.get(selector, queueHandler, options); } } diff --git a/zenoh-java/build.gradle.kts b/zenoh-java/build.gradle.kts index c398631e..d97ff9e2 100644 --- a/zenoh-java/build.gradle.kts +++ b/zenoh-java/build.gradle.kts @@ -59,7 +59,6 @@ kotlin { val commonMain by getting { dependencies { implementation("commons-net:commons-net:3.9.0") -// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") } } val commonTest by getting { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt index f67f9889..8604bc24 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt @@ -66,14 +66,15 @@ internal class JNISession { keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - publisherOptions.qos.congestionControl.value, - publisherOptions.qos.priority.value, - publisherOptions.qos.express, + publisherOptions.congestionControl.value, + publisherOptions.priority.value, + publisherOptions.express, publisherOptions.reliability.ordinal ) return Publisher( keyExpr, - publisherOptions.qos, + publisherOptions.congestionControl, + publisherOptions.priority, publisherOptions.encoding, JNIPublisher(publisherRawPtr), ) @@ -353,9 +354,9 @@ internal class JNISession { payload.into().bytes, encoding.id, encoding.schema, - options.qos.congestionControl.value, - options.qos.priority.value, - options.qos.express, + options.congestionControl.value, + options.priority.value, + options.express, options.attachment?.into()?.bytes, options.reliability.ordinal ) @@ -370,9 +371,9 @@ internal class JNISession { keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr.get(), - options.qos.congestionControl.value, - options.qos.priority.value, - options.qos.express, + options.congestionControl.value, + options.priority.value, + options.express, options.attachment?.into()?.bytes, options.reliability.ordinal ) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt index cc488ce9..50980816 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/DeleteOptions.kt @@ -15,18 +15,24 @@ package io.zenoh.pubsub import io.zenoh.bytes.IntoZBytes +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority import io.zenoh.qos.QoS import io.zenoh.qos.Reliability /** * Options for delete operations. * - * @param qos The [QoS] (Quality of Service) desired. * @param reliability The [Reliability] desired. * @param attachment Optional attachment for the delete operation. + * @property express [QoS] express value. + * @property congestionControl The congestion control policy. + * @property priority The priority policy. */ data class DeleteOptions( - var qos: QoS = QoS.defaultQoS(), var reliability: Reliability = Reliability.RELIABLE, - var attachment: IntoZBytes? = null + var attachment: IntoZBytes? = null, + var express: Boolean = QoS.defaultQoS.express, + var congestionControl: CongestionControl = QoS.defaultQoS.congestionControl, + var priority: Priority = QoS.defaultQoS.priority ) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index 00b4d0b5..07521583 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -20,7 +20,8 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIPublisher import io.zenoh.keyexpr.KeyExpr -import io.zenoh.qos.QoS +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority import io.zenoh.session.SessionDeclaration import kotlin.Throws @@ -59,7 +60,8 @@ import kotlin.Throws */ class Publisher internal constructor( val keyExpr: KeyExpr, - private var qos: QoS, + private var congestionControl: CongestionControl, + private var priority: Priority, val encoding: Encoding, private var jniPublisher: JNIPublisher?, ) : SessionDeclaration, AutoCloseable { @@ -69,10 +71,10 @@ class Publisher internal constructor( } /** Get the congestion control applied when routing the data. */ - fun congestionControl() = qos.congestionControl + fun congestionControl() = congestionControl /** Get the priority of the written data. */ - fun priority() = qos.priority + fun priority() = priority /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ @Throws(ZError::class) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt index a0461699..0759a5b4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PublisherOptions.kt @@ -20,43 +20,14 @@ import io.zenoh.qos.* /** * Options for the publisher. * - * @param encoding The encoding of the payload. * @param reliability The desired reliability. - * @param qos The quality of service desired. + * @param encoding The encoding of the payload. + * @property express [QoS] express value. + * @property congestionControl The congestion control policy. + * @property priority The priority policy. */ data class PublisherOptions(var reliability: Reliability = Reliability.RELIABLE, - var qos: QoS = QoS.defaultQoS(), - var encoding: Encoding = Encoding.defaultEncoding()) { - - fun getQoS(): QoS { - return qos - } - - fun getCongestionControl(): CongestionControl { - return this.qos.congestionControl - } - - fun getExpress(): Boolean { - return this.qos.express - } - - fun getPriority(): Priority { - return this.qos.priority - } - - fun setQoS(qos: QoS) { - this.qos = qos - } - - fun setCongestionControl(congestionControl: CongestionControl) { - this.qos.congestionControl = congestionControl - } - - fun setExpress(express: Boolean) { - this.qos.express = express - } - - fun setPriority(priority: Priority) { - this.qos.priority = priority - } -} + var encoding: Encoding = Encoding.defaultEncoding(), + var express: Boolean = QoS.defaultQoS.express, + var congestionControl: CongestionControl = QoS.defaultQoS.congestionControl, + var priority: Priority = QoS.defaultQoS.priority) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt index c2b747f3..e5930d61 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/PutOptions.kt @@ -24,53 +24,15 @@ import io.zenoh.qos.* * @param encoding The encoding of the payload. * @param reliability The desired reliability. * @param attachment Optional attachment. - * @param qos The quality of service desired. + * @property express [QoS] express value. + * @property congestionControl The congestion control policy. + * @property priority The priority policy. */ data class PutOptions( var encoding: Encoding? = null, - var qos: QoS = QoS.defaultQoS(), var reliability: Reliability = Reliability.RELIABLE, - var attachment: IntoZBytes? = null -) { - /** - * Get the congestion control. - */ - fun getCongestionControl(): CongestionControl { - return this.qos.congestionControl - } - - /** - * Get the express value of the QoS. - */ - fun getExpress(): Boolean { - return this.qos.express - } - - /** - * Get the priority. - */ - fun getPriority(): Priority { - return this.qos.priority - } - - /** - * Set the QoS congestion control. - */ - fun setCongestionControl(congestionControl: CongestionControl) { - this.qos.congestionControl = congestionControl - } - - /** - * Set the QoS express value. - */ - fun setExpress(express: Boolean) { - this.qos.express = express - } - - /** - * Set the priority desired. - */ - fun setPriority(priority: Priority) { - this.qos.priority = priority - } -} + var attachment: IntoZBytes? = null, + var express: Boolean = QoS.defaultQoS.express, + var congestionControl: CongestionControl = QoS.defaultQoS.congestionControl, + var priority: Priority = QoS.defaultQoS.priority +) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt index 56a0ad7c..7b18eedd 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/QoS.kt @@ -28,9 +28,6 @@ data class QoS ( ) { companion object { - private val defaultQoS = QoS() - - @JvmStatic - fun defaultQoS() = defaultQoS + internal val defaultQoS = QoS() } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 0d4de0af..7fb349d4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -21,6 +21,7 @@ import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.jni.JNIQuery import io.zenoh.keyexpr.KeyExpr +import io.zenoh.qos.QoS import io.zenoh.sample.Sample import io.zenoh.sample.SampleKind @@ -63,7 +64,7 @@ class Query internal constructor( options.encoding, SampleKind.PUT, options.timeStamp, - options.qos, + QoS(options.congestionControl, options.priority, options.express), options.attachment ) jniQuery?.apply { @@ -87,7 +88,7 @@ class Query internal constructor( keyExpr, options.timeStamp, options.attachment, - options.qos + QoS(options.congestionControl, options.priority, options.express), ) jniQuery = null } ?: throw (ZError("Query is invalid")) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index a5b48aef..15b33e47 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -83,104 +83,35 @@ sealed class Reply private constructor(val replierId: ZenohId?) : ZenohType { * @param encoding [Encoding] of the payload of the reply. * @param timeStamp Optional timestamp. * @param attachment Optional attachment. - * @param qos The [QoS] for the reply. + * @property express [QoS] express value. + * @property congestionControl The congestion control policy. + * @property priority The priority policy. */ data class ReplyOptions( var encoding: Encoding = Encoding.defaultEncoding(), var timeStamp: TimeStamp? = null, var attachment: ZBytes? = null, - var qos: QoS = QoS.defaultQoS() -) { - - /** - * Get the QoS express value. - */ - fun getExpress(): Boolean { - return qos.express - } - - /** - * Get the QoS Priority value. - */ - fun getPriority(): Priority { - return qos.priority - } - - /** - * Get the congestion control value. - */ - fun getCongestionControl(): CongestionControl { - return qos.congestionControl - } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun setExpress(express: Boolean) { qos.express = express } - - /** - * Sets the [Priority] of the reply. - */ - fun setPriority(priority: Priority) { qos.priority = priority } - - /** - * Sets the [CongestionControl] of the reply. - * - * @param congestionControl - */ - fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl = congestionControl } -} + var express: Boolean = QoS.defaultQoS.express, + var congestionControl: CongestionControl = QoS.defaultQoS.congestionControl, + var priority: Priority = QoS.defaultQoS.priority +) /** * Options for performing a Reply Delete to a [Query]. * * @param timeStamp Optional timestamp. * @param attachment Optional attachment. - * @param qos The [QoS] for the reply. + * @property express [QoS] express value. + * @property congestionControl The congestion control policy. + * @property priority The priority policy. */ data class ReplyDelOptions( var timeStamp: TimeStamp? = null, var attachment: ZBytes? = null, - var qos: QoS = QoS.defaultQoS() -) { - /** - * Get the QoS express value. - */ - fun getExpress(): Boolean { - return qos.express - } - - /** - * Get the QoS Priority value. - */ - fun getPriority(): Priority { - return qos.priority - } - - /** - * Get the congestion control value. - */ - fun getCongestionControl(): CongestionControl { - return qos.congestionControl - } - - /** - * Sets the express flag. If true, the reply won't be batched in order to reduce the latency. - */ - fun setExpress(express: Boolean) { qos.express = express } - - /** - * Sets the [Priority] of the reply. - */ - fun setPriority(priority: Priority) { qos.priority = priority } - - /** - * Sets the [CongestionControl] of the reply. - * - * @param congestionControl - */ - fun setCongestionControl(congestionControl: CongestionControl) { qos.congestionControl = congestionControl } -} + var express: Boolean = QoS.defaultQoS.express, + var congestionControl: CongestionControl = QoS.defaultQoS.congestionControl, + var priority: Priority = QoS.defaultQoS.priority +) /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt index adb99cd8..216d67e0 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt @@ -31,9 +31,9 @@ import org.apache.commons.net.ntp.TimeStamp * @property timestamp Optional [TimeStamp]. * @property qos The Quality of Service settings used to deliver the sample. * @property attachment Optional attachment. - * @property express The express value in the [qos]. - * @property congestionControl The congestion control in the [qos]. - * @property priority The priority in the [qos]. + * @property express [QoS] express value. + * @property congestionControl The congestion control policy. + * @property priority The priority policy. */ data class Sample( val keyExpr: KeyExpr, diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index d56501e6..b1e5918c 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -53,7 +53,7 @@ public void queryableRunsWithCallback() throws ZError { Encoding.defaultEncoding(), SampleKind.PUT, timestamp, - QoS.defaultQoS(), + new QoS(), null ); @@ -158,9 +158,9 @@ public void queryReplySuccessTest() throws ZError { var sample = ((Reply.Success) receivedReply[0]).getSample(); assertEquals(message, sample.getPayload()); assertEquals(timestamp, sample.getTimestamp()); - assertEquals(Priority.DATA_HIGH, sample.getQos().getPriority()); + assertEquals(Priority.DATA_HIGH, sample.getPriority()); assertTrue(sample.getQos().getExpress()); - assertEquals(CongestionControl.DROP, sample.getQos().getCongestionControl()); + assertEquals(CongestionControl.DROP, sample.getCongestionControl()); } @Test From 3f49774f498733ba26690db85bd7ee1d1eb428db Mon Sep 17 00:00:00 2001 From: Darius Maitia Date: Wed, 18 Dec 2024 19:49:51 -0300 Subject: [PATCH 83/83] Native loading refactor Aligning with zenoh-kotlin's native lib loading logic: - Adding extra checks for determining the platform on top of which zenoh-java is running - Defaulting javaClass's class loader in case the system class loader fails to find the native lib --- .../src/jvmMain/kotlin/io/zenoh/Target.kt | 2 +- .../src/jvmMain/kotlin/io/zenoh/Zenoh.kt | 38 +++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt index 4bb087ee..0e58c219 100644 --- a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt +++ b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt @@ -14,7 +14,7 @@ package io.zenoh -enum class Target { +internal enum class Target { WINDOWS_X86_64_MSVC, LINUX_X86_64, LINUX_AARCH64, diff --git a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt index 11ae638c..593e451d 100644 --- a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt @@ -27,7 +27,7 @@ import java.util.zip.ZipInputStream internal actual object ZenohLoad { private const val ZENOH_LIB_NAME = "zenoh_jni" - init { + init { // Try first to load the local native library for cases in which the module was built locally, // otherwise try to load from the JAR. if (tryLoadingLocalLibrary().isFailure) { @@ -45,24 +45,33 @@ internal actual object ZenohLoad { */ private fun determineTarget(): Result = runCatching { val osName = System.getProperty("os.name").lowercase() - val osArch = System.getProperty("os.arch") + val osArch = System.getProperty("os.arch").lowercase() val target = when { osName.contains("win") -> when { - osArch.contains("x86_64") || osArch.contains("amd64") -> Target.WINDOWS_X86_64_MSVC - else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") + osArch.contains("x86_64") || osArch.contains("amd64") || osArch.contains("x64") -> + Target.WINDOWS_X86_64_MSVC + else -> throw UnsupportedOperationException("Unsupported architecture on Windows: $osArch") } - osName.contains("mac") -> when { - osArch.contains("x86_64") || osArch.contains("amd64") -> Target.APPLE_X86_64 - osArch.contains("aarch64") -> Target.APPLE_AARCH64 - else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") + osName.contains("mac") || osName.contains("darwin") || osName.contains("os x") -> when { + osArch.contains("x86_64") || osArch.contains("amd64") || osArch.contains("x64") -> + Target.APPLE_X86_64 + + osArch.contains("aarch64") || osArch.contains("arm64") -> + Target.APPLE_AARCH64 + + else -> throw UnsupportedOperationException("Unsupported architecture on macOS: $osArch") } osName.contains("nix") || osName.contains("nux") || osName.contains("aix") -> when { - osArch.contains("x86_64") || osArch.contains("amd64") -> Target.LINUX_X86_64 - osArch.contains("aarch64") -> Target.LINUX_AARCH64 - else -> throw UnsupportedOperationException("Unsupported architecture: $osArch") + osArch.contains("x86_64") || osArch.contains("amd64") || osArch.contains("x64") -> + Target.LINUX_X86_64 + + osArch.contains("aarch64") || osArch.contains("arm64") -> + Target.LINUX_AARCH64 + + else -> throw UnsupportedOperationException("Unsupported architecture on Linux/Unix: $osArch") } else -> throw UnsupportedOperationException("Unsupported platform: $osName") @@ -108,7 +117,9 @@ internal actual object ZenohLoad { } private fun loadLibraryAsInputStream(target: Target): Result = runCatching { - val libUrl = ClassLoader.getSystemClassLoader().getResourceAsStream("$target/$target.zip")!! + val targetName = "$target/$target.zip" + val libUrl = ClassLoader.getSystemClassLoader().getResourceAsStream(targetName) + ?: javaClass.classLoader.getResourceAsStream(targetName)!! val uncompressedLibFile = unzipLibrary(libUrl) return Result.success(FileInputStream(uncompressedLibFile.getOrThrow())) } @@ -145,6 +156,9 @@ internal actual object ZenohLoad { */ private fun tryLoadingLocalLibrary(): Result = runCatching { val lib = ClassLoader.getSystemClassLoader().findLibraryStream(ZENOH_LIB_NAME) + ?: javaClass.classLoader.findLibraryStream( + ZENOH_LIB_NAME + ) if (lib != null) { loadZenohJNI(lib) } else {