diff --git a/.github/workflows/build-main.yml b/.github/workflows/build-main.yml index 8877b5f..318fb15 100644 --- a/.github/workflows/build-main.yml +++ b/.github/workflows/build-main.yml @@ -15,18 +15,25 @@ jobs: SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Setup java - uses: actions/setup-java@v4 + - name: Setup JDK + uses: actions/setup-java@v5 with: - distribution: 'temurin' java-version: '21' + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + gradle-version: current + - name: Check out code + uses: actions/checkout@v4 - name: Build and Test - run: chmod +x gradlew && ./gradlew clean test jacocoTestReport coveralls + run: chmod +x gradlew && ./gradlew clean test jacocoTestReport - name: Verify Javadoc run: ./gradlew javadoc + - name: Send coverage to Coveralls + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.COVERALLS_REPO_TOKEN }} - name: Publish Snapshot run: ./gradlew -i publishToSonatype diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 3b8ac45..3c25a38 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -9,16 +9,23 @@ jobs: runs-on: ubuntu-latest env: BUILD_EVENT: ${{ github.event_name }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Setup java - uses: actions/setup-java@v4 + - name: Setup JDK + uses: actions/setup-java@v5 with: - distribution: 'temurin' java-version: '21' + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + gradle-version: current + - name: Check out code + uses: actions/checkout@v4 - name: Build and Test - run: chmod +x gradlew && ./gradlew clean test jacocoTestReport coveralls + run: chmod +x gradlew && ./gradlew clean test jacocoTestReport - name: Verify Javadoc run: ./gradlew javadoc + - name: Send coverage to Coveralls + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.COVERALLS_REPO_TOKEN }} diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index e8a8b21..be90a0a 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,16 +17,20 @@ jobs: SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Setup java - uses: actions/setup-java@v4 + - name: Setup JDK + uses: actions/setup-java@v5 with: - distribution: 'temurin' java-version: '21' + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + gradle-version: current + - name: Check out code + uses: actions/checkout@v4 - name: Build and Test run: chmod +x gradlew && ./gradlew clean test - name: Verify Javadoc run: ./gradlew javadoc - name: Verify, Sign and Publish Release - run: ./gradlew -i signMavenJavaPublication publishToSonatype closeAndReleaseSonatypeStagingRepository + run: ./gradlew -i publishToSonatype closeAndReleaseSonatypeStagingRepository diff --git a/build.gradle b/build.gradle index e2a02dc..fbd8c18 100644 --- a/build.gradle +++ b/build.gradle @@ -1,43 +1,70 @@ -import org.gradle.internal.os.OperatingSystem +import aQute.bnd.gradle.Bundle plugins { - id 'java' - id 'java-library' - id 'maven-publish' - id 'jacoco' - id 'com.github.kt3k.coveralls' version '2.12.2' - id "org.gradle.test-retry" version "1.1.9" - id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' - id 'signing' + id("java") + id("java-library") + id("maven-publish") + id("jacoco") + id("biz.aQute.bnd.builder") version "7.2.1" + id("org.gradle.test-retry") version "1.6.4" + id("io.github.gradle-nexus.publish-plugin") version "2.0.0" + id("signing") } def jarVersion = "3.0.0" group = 'io.synadia' -def isMerge = System.getenv("BUILD_EVENT") == "push" def isRelease = System.getenv("BUILD_EVENT") == "release" +def tc = System.getenv("TARGET_COMPATIBILITY"); +def targetCompat = tc == "25" ? JavaVersion.VERSION_25 : JavaVersion.VERSION_21 +def jarEnd = tc == "25" ? "-jdk25" : "" +def jarAndArtifactName = "jnats-json" + jarEnd -// version is the variable the build actually uses. -version = isRelease ? jarVersion : jarVersion + "-SNAPSHOT" +version = isRelease ? jarVersion : jarVersion + "-SNAPSHOT" // version is the variable the build actually uses. java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = targetCompat } repositories { mavenCentral() - maven { url "https://oss.sonatype.org/content/repositories/releases/" } - maven { url "https://repo1.maven.org/maven2/" } + maven { url="https://repo1.maven.org/maven2/" } + maven { url="https://central.sonatype.com/repository/maven-snapshots/" } } dependencies { implementation 'org.jspecify:jspecify:1.0.0' - implementation 'commons-codec:commons-codec:1.18.0' + implementation 'commons-codec:commons-codec:1.20.0' + + testImplementation 'org.junit.jupiter:junit-jupiter:5.14.1' + + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.register('bundle', Bundle) { + from sourceSets.main.output +} + +java { + withSourcesJar() + withJavadocJar() +} + +jar { + bundle { + bnd("Bundle-Name": "io.synadia.jnats.json", + "Bundle-Vendor": "synadia.io", + "Bundle-Description": "JNats Json Utils", + "Bundle-DocURL": "https://github.com/synadia-io/jnats.json", + "Target-Compatibility": "Java " + targetCompat + ) + } +} - testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' - testImplementation 'nl.jqno.equalsverifier:equalsverifier:4.0' +java { + withSourcesJar() + withJavadocJar() } test { @@ -50,36 +77,11 @@ test { } javadoc { - options.addBooleanOption('html5', true) + failOnError = false options.overview = 'src/main/javadoc/overview.html' // relative to source root source = sourceSets.main.allJava title = "NATS.IO JNats JSON" classpath = sourceSets.main.runtimeClasspath - doLast { - if (!OperatingSystem.current().isWindows()) { - exec { - println "Updating favicon on all html files" - workingDir 'build/docs/javadoc' - // Only on linux, mac at this point - commandLine 'find', '.', '-name', '*.html', '-exec', 'sed', '-i', '-e', 's###', '{}', ';' - } - copy { - println "Copying images to javadoc folder" - from 'src/main/javadoc/images' - into 'build/docs/javadoc' - } - } - } -} - -tasks.register('javadocJar', Jar) { - archiveClassifier.set('javadoc') - from javadoc -} - -tasks.register('sourcesJar', Jar) { - archiveClassifier.set('sources') - from sourceSets.main.allSource } jacoco { @@ -93,19 +95,13 @@ jacocoTestReport { } } -artifacts { - archives javadocJar, sourcesJar -} - -if (isMerge || isRelease) { - nexusPublishing { - repositories { - sonatype { - nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) - snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) - username = System.getenv('OSSRH_USERNAME') - password = System.getenv('OSSRH_PASSWORD') - } +nexusPublishing { + repositories { + sonatype { + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) + username = System.getenv('OSSRH_USERNAME') + password = System.getenv('OSSRH_PASSWORD') } } } @@ -117,12 +113,12 @@ publishing { artifact sourcesJar artifact javadocJar pom { - name = rootProject.name + name = jarAndArtifactName packaging = 'jar' groupId = group - artifactId = archivesBaseName + artifactId = jarAndArtifactName description = 'JSON Parser built specifically for JNATS' - url = 'https://github.com/synadia-io/json.java21' + url = 'https://github.com/synadia-io/jnats.json' licenses { license { name = 'The Apache License, Version 2.0' @@ -138,7 +134,7 @@ publishing { } } scm { - url = 'https://github.com/synadia-io/json.java21' + url = 'https://github.com/synadia-io/jnats.json' } } } @@ -151,6 +147,7 @@ if (isRelease) { def signingKey = System.getenv('SIGNING_KEY') def signingPassword = System.getenv('SIGNING_PASSWORD') useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) + sign configurations.archives sign publishing.publications.mavenJava } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55..f8e1ee3 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ca025c8..23449a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9..adff685 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index db3a6ac..c4bdd3a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index a75bfef..a3061a8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html - */ - -rootProject.name = 'jnats-json-21' +rootProject.name = 'jnats-json' diff --git a/src/main/java/io/synadia/json/ArrayBuilder.java b/src/main/java/io/synadia/json/ArrayBuilder.java index a45ea93..054c426 100644 --- a/src/main/java/io/synadia/json/ArrayBuilder.java +++ b/src/main/java/io/synadia/json/ArrayBuilder.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/DateTimeUtils.java b/src/main/java/io/synadia/json/DateTimeUtils.java index 27ff9b2..4f89b75 100644 --- a/src/main/java/io/synadia/json/DateTimeUtils.java +++ b/src/main/java/io/synadia/json/DateTimeUtils.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2020-2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: @@ -11,6 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. + package io.synadia.json; import org.jspecify.annotations.NonNull; diff --git a/src/main/java/io/synadia/json/Encoding.java b/src/main/java/io/synadia/json/Encoding.java index f0d245e..6af4e44 100644 --- a/src/main/java/io/synadia/json/Encoding.java +++ b/src/main/java/io/synadia/json/Encoding.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2020-2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/JsonParseException.java b/src/main/java/io/synadia/json/JsonParseException.java index 6be503c..8cf216b 100644 --- a/src/main/java/io/synadia/json/JsonParseException.java +++ b/src/main/java/io/synadia/json/JsonParseException.java @@ -1,3 +1,19 @@ +// Copyright 2023 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package io.synadia.json; import java.io.IOException; diff --git a/src/main/java/io/synadia/json/JsonParser.java b/src/main/java/io/synadia/json/JsonParser.java index c25c8e7..2cbd4da 100644 --- a/src/main/java/io/synadia/json/JsonParser.java +++ b/src/main/java/io/synadia/json/JsonParser.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2023 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/JsonSerializable.java b/src/main/java/io/synadia/json/JsonSerializable.java index 5992f69..d514d53 100644 --- a/src/main/java/io/synadia/json/JsonSerializable.java +++ b/src/main/java/io/synadia/json/JsonSerializable.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2021-2023 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/JsonValue.java b/src/main/java/io/synadia/json/JsonValue.java index 0e17977..4c967e7 100644 --- a/src/main/java/io/synadia/json/JsonValue.java +++ b/src/main/java/io/synadia/json/JsonValue.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2023 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: @@ -504,17 +507,19 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = map != null ? map.hashCode() : 0; - result = 31 * result + (array != null ? array.hashCode() : 0); - result = 31 * result + (string != null ? string.hashCode() : 0); - result = 31 * result + (bool != null ? bool.hashCode() : 0); - result = 31 * result + (i != null ? i.hashCode() : 0); - result = 31 * result + (l != null ? l.hashCode() : 0); - result = 31 * result + (d != null ? d.hashCode() : 0); - result = 31 * result + (f != null ? f.hashCode() : 0); - result = 31 * result + (bd != null ? bd.hashCode() : 0); - result = 31 * result + (bi != null ? bi.hashCode() : 0); - result = 31 * result + type.hashCode(); - return result; + return 31 * type.hashCode() + + switch (type) { + case STRING -> string.hashCode(); + case BOOL -> bool.hashCode(); + case INTEGER -> i.hashCode(); + case LONG -> l.hashCode(); + case DOUBLE -> d.hashCode(); + case FLOAT -> f.hashCode(); + case BIG_DECIMAL -> bd.hashCode(); + case BIG_INTEGER -> bi.hashCode(); + case MAP -> map.hashCode(); + case ARRAY -> array.hashCode(); + default -> 0; + }; } } diff --git a/src/main/java/io/synadia/json/JsonValueSupplier.java b/src/main/java/io/synadia/json/JsonValueSupplier.java index 0018ea8..4b7ddfa 100644 --- a/src/main/java/io/synadia/json/JsonValueSupplier.java +++ b/src/main/java/io/synadia/json/JsonValueSupplier.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/JsonValueType.java b/src/main/java/io/synadia/json/JsonValueType.java index efdcf11..9961797 100644 --- a/src/main/java/io/synadia/json/JsonValueType.java +++ b/src/main/java/io/synadia/json/JsonValueType.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/JsonValueUtils.java b/src/main/java/io/synadia/json/JsonValueUtils.java index 8528186..6f3a7f2 100644 --- a/src/main/java/io/synadia/json/JsonValueUtils.java +++ b/src/main/java/io/synadia/json/JsonValueUtils.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/JsonWriteUtils.java b/src/main/java/io/synadia/json/JsonWriteUtils.java index eb09b7c..0f54dfd 100644 --- a/src/main/java/io/synadia/json/JsonWriteUtils.java +++ b/src/main/java/io/synadia/json/JsonWriteUtils.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/ListValueResolver.java b/src/main/java/io/synadia/json/ListValueResolver.java index 2fbdb76..688ee20 100644 --- a/src/main/java/io/synadia/json/ListValueResolver.java +++ b/src/main/java/io/synadia/json/ListValueResolver.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/main/java/io/synadia/json/MapBuilder.java b/src/main/java/io/synadia/json/MapBuilder.java index a33dfcd..8334aaa 100644 --- a/src/main/java/io/synadia/json/MapBuilder.java +++ b/src/main/java/io/synadia/json/MapBuilder.java @@ -1,4 +1,5 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/test/java/io/nats/client/api/AckPolicy.java b/src/test/java/io/nats/client/api/AckPolicy.java deleted file mode 100644 index edb092a..0000000 --- a/src/test/java/io/nats/client/api/AckPolicy.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Represents the Ack Policy of a consumer - */ -public enum AckPolicy { - /** - * Messages are acknowledged as soon as the server sends them. Clients do not need to ack. - */ - None("none"), - /** - * All messages with a sequence number less than the message acked are also acknowledged. E.g. reading a batch of messages 1 .. 100. Ack on message 100 will acknowledge 1 .. 99 as well. - */ - All("all"), - /** - * Each message must be acknowledged individually. Message can be acked out of sequence and create gaps of unacknowledged messages in the consumer. - */ - Explicit("explicit"); - - private final String policy; - - AckPolicy(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (AckPolicy env : AckPolicy.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static AckPolicy get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/ApiResponse.java b/src/test/java/io/nats/client/api/ApiResponse.java deleted file mode 100644 index ebde7a0..0000000 --- a/src/test/java/io/nats/client/api/ApiResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; - -public abstract class ApiResponse { - - protected final JsonValue jv; - - public ApiResponse(JsonValue jsonValue) { - jv = jsonValue; - } -} diff --git a/src/test/java/io/nats/client/api/ClusterInfo.java b/src/test/java/io/nats/client/api/ClusterInfo.java deleted file mode 100644 index b2f4114..0000000 --- a/src/test/java/io/nats/client/api/ClusterInfo.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.Nullable; - -import java.util.List; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.readString; -import static io.synadia.json.JsonValueUtils.readValue; - -/** - * Information about the cluster a stream is part of. - */ -public class ClusterInfo { - private final String name; - private final String leader; - private final List replicas; - - static ClusterInfo optionalInstance(JsonValue v) { - return v == null ? null : new ClusterInfo(v); - } - - ClusterInfo(JsonValue v) { - name = readString(v, NAME); - leader = readString(v, LEADER); - replicas = Replica.optionalListOf(readValue(v, REPLICAS)); - } - - /** - * The cluster name. Technically can be null - * @return the cluster or null - */ - @Nullable - public String getName() { - return name; - } - - /** - * The server name of the RAFT leader - * @return the leader or null - */ - @Nullable - public String getLeader() { - return leader; - } - - /** - * The members of the RAFT cluster. May be null if there are no replicas. - * @return the replicas or null - */ - @Nullable - public List getReplicas() { - return replicas; - } - - @Override - public String toString() { - return "ClusterInfo{" + - "name='" + name + '\'' + - ", leader='" + leader + '\'' + - ", replicas=" + replicas + - '}'; - } -} diff --git a/src/test/java/io/nats/client/api/CompressionOption.java b/src/test/java/io/nats/client/api/CompressionOption.java deleted file mode 100644 index e4ff97c..0000000 --- a/src/test/java/io/nats/client/api/CompressionOption.java +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Stream compression policies. - */ -public enum CompressionOption { - None("none"), - S2("s2"); - - private final String policy; - - CompressionOption(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (CompressionOption env : CompressionOption.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static CompressionOption get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/ConsumerConfiguration.java b/src/test/java/io/nats/client/api/ConsumerConfiguration.java deleted file mode 100644 index b301328..0000000 --- a/src/test/java/io/nats/client/api/ConsumerConfiguration.java +++ /dev/null @@ -1,1424 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.nats.client.support.ApiConstants; -import io.synadia.json.JsonParseException; -import io.synadia.json.JsonParser; -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.time.Duration; -import java.time.ZonedDateTime; -import java.util.*; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; -import static io.synadia.json.JsonWriteUtils.*; - -public class ConsumerConfiguration implements JsonSerializable { - @Deprecated - public static final Duration DURATION_MIN = Duration.ofNanos(1); - - public static final DeliverPolicy DEFAULT_DELIVER_POLICY = DeliverPolicy.All; - public static final AckPolicy DEFAULT_ACK_POLICY = AckPolicy.Explicit; - public static final ReplayPolicy DEFAULT_REPLAY_POLICY = ReplayPolicy.Instant; - public static final PriorityPolicy DEFAULT_PRIORITY_POLICY = PriorityPolicy.None; - - public static final Duration DURATION_UNSET = Duration.ZERO; - public static final Duration MIN_IDLE_HEARTBEAT = Duration.ofMillis(100); - - public static final int INTEGER_UNSET = -1; - public static final long LONG_UNSET = -1; - public static final long ULONG_UNSET = 0; - public static final long DURATION_UNSET_LONG = 0; - public static final long DURATION_MIN_LONG = 1; - public static final int STANDARD_MIN = 0; - public static final int MAX_DELIVER_MIN = 1; - - public static final long MIN_IDLE_HEARTBEAT_NANOS = MIN_IDLE_HEARTBEAT.toNanos(); - public static final long MIN_IDLE_HEARTBEAT_MILLIS = MIN_IDLE_HEARTBEAT.toMillis(); - - protected final DeliverPolicy deliverPolicy; - protected final AckPolicy ackPolicy; - protected final ReplayPolicy replayPolicy; - protected final String description; - protected final String durable; - protected final String name; - protected final String deliverSubject; - protected final String deliverGroup; - protected final String sampleFrequency; - protected final ZonedDateTime startTime; - protected final Duration ackWait; - protected final Duration idleHeartbeat; - protected final Duration maxExpires; - protected final Duration inactiveThreshold; - protected final Long startSeq; // server side this is unsigned - protected final Integer maxDeliver; - protected final Long rateLimit; // server side this is unsigned - protected final Integer maxAckPending; - protected final Integer maxPullWaiting; - protected final Integer maxBatch; - protected final Integer maxBytes; - protected final Integer numReplicas; - protected final ZonedDateTime pauseUntil; - protected final Boolean flowControl; - protected final Boolean headersOnly; - protected final Boolean memStorage; - protected final List backoff; - protected final Map metadata; - protected final List filterSubjects; - protected final List priorityGroups; - protected final PriorityPolicy priorityPolicy; - - // For the builder - protected ConsumerConfiguration(Builder b) - { - this.deliverPolicy = b.deliverPolicy; - this.ackPolicy = b.ackPolicy; - this.replayPolicy = b.replayPolicy; - - this.description = b.description; - this.durable = b.durable; - this.name = b.name; - this.startTime = b.startTime; - this.ackWait = b.ackWait; - this.sampleFrequency = b.sampleFrequency; - this.deliverSubject = b.deliverSubject; - this.deliverGroup = b.deliverGroup; - this.idleHeartbeat = b.idleHeartbeat; - this.maxExpires = b.maxExpires; - this.inactiveThreshold = b.inactiveThreshold; - - this.startSeq = b.startSeq; - this.maxDeliver = b.maxDeliver; - this.rateLimit = b.rateLimit; - this.maxAckPending = b.maxAckPending; - this.maxPullWaiting = b.maxPullWaiting; - this.maxBatch = b.maxBatch; - this.maxBytes = b.maxBytes; - this.numReplicas = b.numReplicas; - this.pauseUntil = b.pauseUntil; - - this.flowControl = b.flowControl; - this.headersOnly = b.headersOnly; - this.memStorage = b.memStorage; - - this.backoff = b.backoff; - this.metadata = b.metadata; - this.filterSubjects = b.filterSubjects; - - this.priorityGroups = b.priorityGroups; - this.priorityPolicy = b.priorityPolicy; - } - - /** - * Returns a JSON representation of this consumer configuration. - * @return json consumer configuration json string - */ - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addField(sb, DESCRIPTION, description); - addField(sb, DURABLE_NAME, durable); - addField(sb, NAME, name); - addField(sb, DELIVER_SUBJECT, deliverSubject); - addField(sb, DELIVER_GROUP, deliverGroup); - addField(sb, DELIVER_POLICY, GetOrDefault(deliverPolicy).toString()); - addFieldWhenGtZero(sb, OPT_START_SEQ, startSeq); - addField(sb, OPT_START_TIME, startTime); - addField(sb, ACK_POLICY, GetOrDefault(ackPolicy).toString()); - addFieldAsNanos(sb, ACK_WAIT, ackWait); - addFieldWhenGtZero(sb, MAX_DELIVER, maxDeliver); - addField(sb, MAX_ACK_PENDING, maxAckPending); - addField(sb, REPLAY_POLICY, GetOrDefault(replayPolicy).toString()); - addField(sb, SAMPLE_FREQ, sampleFrequency); - addFieldWhenGtZero(sb, RATE_LIMIT_BPS, rateLimit); - addFieldAsNanos(sb, IDLE_HEARTBEAT, idleHeartbeat); - addField(sb, FLOW_CONTROL, flowControl); - addField(sb, ApiConstants.MAX_WAITING, maxPullWaiting); - addField(sb, HEADERS_ONLY, headersOnly); - addField(sb, MAX_BATCH, maxBatch); - addField(sb, MAX_BYTES, maxBytes); - addFieldAsNanos(sb, MAX_EXPIRES, maxExpires); - addFieldAsNanos(sb, INACTIVE_THRESHOLD, inactiveThreshold); - addDurations(sb, BACKOFF, backoff); - addField(sb, NUM_REPLICAS, numReplicas); - addField(sb, PAUSE_UNTIL, pauseUntil); - addField(sb, MEM_STORAGE, memStorage); - addField(sb, METADATA, metadata); - if (filterSubjects != null) { - if (filterSubjects.size() > 1) { - addStrings(sb, FILTER_SUBJECTS, filterSubjects); - } - else if (filterSubjects.size() == 1) { - addField(sb, FILTER_SUBJECT, filterSubjects.getFirst()); - } - } - addStrings(sb, PRIORITY_GROUPS, priorityGroups); - if (priorityPolicy != null && priorityPolicy != DEFAULT_PRIORITY_POLICY) { - addField(sb, PRIORITY_POLICY, priorityPolicy.toString()); - } - return endJson(sb).toString(); - } - - /** - * Gets the name of the description of this consumer configuration. - * @return name of the description. - */ - @Nullable - public String getDescription() { - return description; - } - - /** - * Gets the name of the durable name for this consumer configuration. - * @return name of the durable. - */ - @Nullable - public String getDurable() { - return durable; - } - - /** - * Gets the name of the consumer name for this consumer configuration. - * @return name of the consumer. - */ - @Nullable - public String getName() { - return name; - } - - /** - * Gets the deliver subject of this consumer configuration. - * @return the deliver subject. - */ - @Nullable - public String getDeliverSubject() { - return deliverSubject; - } - - /** - * Gets the deliver group of this consumer configuration. - * @return the deliver group. - */ - @Nullable - public String getDeliverGroup() { - return deliverGroup; - } - - /** - * Gets the deliver policy of this consumer configuration. - * @return the deliver policy. - */ - @NonNull - public DeliverPolicy getDeliverPolicy() { - return GetOrDefault(deliverPolicy); - } - - /** - * Gets the start sequence of this consumer configuration. - * @return the start sequence. - */ - public long getStartSequence() { - return getOrUnsetUlong(startSeq); - } - - /** - * Gets the start time of this consumer configuration. - * @return the start time. - */ - @Nullable - public ZonedDateTime getStartTime() { - return startTime; - } - - /** - * Gets the acknowledgment policy of this consumer configuration. - * @return the acknowledgment policy. - */ - @NonNull - public AckPolicy getAckPolicy() { - return GetOrDefault(ackPolicy); - } - - /** - * Gets the acknowledgment wait of this consumer configuration. - * @return the acknowledgment wait duration. - */ - @Nullable - public Duration getAckWait() { - return ackWait; - } - - /** - * Gets the max delivery amount of this consumer configuration. - * @return the max delivery amount. - */ - public long getMaxDeliver() { - return getOrUnset(maxDeliver); - } - - /** - * Gets the filter subject of this consumer configuration. - * With the introduction of multiple filter subjects, this method will - * return null if there are not exactly one filter subjects - * @return the first filter subject. - */ - @Nullable - public String getFilterSubject() { - return filterSubjects == null || filterSubjects.size() != 1 ? null : filterSubjects.get(0); - } - - /** - * Gets the filter subjects as a list. May be null, otherwise won't be empty - * @return the list - */ - @Nullable - public List getFilterSubjects() { - return filterSubjects; - } - - /** - * Gets the priority groups as a list. May be null, otherwise won't be empty - * @return the list - */ - @Nullable - public List getPriorityGroups() { - return priorityGroups; - } - - /** - * Whether there are multiple filter subjects for this consumer configuration. - * @return true if there are multiple filter subjects - */ - public boolean hasMultipleFilterSubjects() { - return filterSubjects != null && filterSubjects.size() > 1; - } - - /** - * Gets the replay policy of this consumer configuration. - * @return the replay policy. - */ - @NonNull - public ReplayPolicy getReplayPolicy() { - return GetOrDefault(replayPolicy); - } - - /** - * Gets the rate limit for this consumer configuration. - * @return the rate limit in bits per second - */ - public long getRateLimit() { - return getOrUnsetUlong(rateLimit); - } - - /** - * Gets the maximum ack pending configuration. - * @return maximum ack pending. - */ - public long getMaxAckPending() { - return getOrUnset(maxAckPending); - } - - /** - * Gets the sample frequency. - * @return sampleFrequency. - */ - @Nullable - public String getSampleFrequency() { - return sampleFrequency; - } - - /** - * Gets the idle heart beat wait time - * @return the idle heart beat wait duration. - */ - @Nullable - public Duration getIdleHeartbeat() { - return idleHeartbeat; - } - - /** - * Get the flow control flag indicating whether it's on or off - * @return the flow control mode - */ - public boolean isFlowControl() { - // The way the builder and json reading works it's never false if it's not null - // but this way I can make code coverage happy and not assume. - return Boolean.TRUE.equals(flowControl); - } - - /** - * Get the number of pulls that can be outstanding on a pull consumer - * @return the max pull waiting - */ - public long getMaxPullWaiting() { - return getOrUnset(maxPullWaiting); - } - - /** - * Get the header only flag indicating whether it's on or off - * @return the flow control mode - */ - public boolean isHeadersOnly() { - return headersOnly != null && headersOnly; - } - - /** - * Get the mem storage flag whether it's on or off. - * @return the mem storage mode - */ - public boolean isMemStorage() { - return memStorage != null && memStorage; - } - - /** - * Get the max batch size for the server to allow on pull requests. - * @return the max batch size - */ - public long getMaxBatch() { - return getOrUnset(maxBatch); - } - - /** - * Get the max bytes size for the server to allow on pull requests. - * @return the max byte size - */ - public long getMaxBytes() { - return getOrUnset(maxBytes); - } - - /** - * Get the max amount of expire time for the server to allow on pull requests. - * @return the max expire - */ - @Nullable - public Duration getMaxExpires() { - return maxExpires; - } - - /** - * Get the amount of time before the consumer is deemed inactive. - * @return the inactive threshold - */ - @Nullable - public Duration getInactiveThreshold() { - return inactiveThreshold; - } - - /** - * Get the backoff list; may be empty, will never be null. - * @return the list - */ - @NonNull - public List getBackoff() { - return backoff == null ? Collections.emptyList() : backoff; - } - - /** - * Metadata for the consumer; may be empty, will never be null. - * @return the metadata map - */ - @NonNull - public Map getMetadata() { - return metadata == null ? Collections.emptyMap() : metadata; - } - - /** - * Get the number of consumer replicas. - * @return the replicas count - */ - public int getNumReplicas() { return getOrUnset(numReplicas); } - - /** - * Get the time until the consumer is paused. - * @return paused until time - */ - @Nullable - public ZonedDateTime getPauseUntil() { - return pauseUntil; - } - - /** - * Gets the priority policy of this consumer configuration. - * @return the priority policy. - */ - @NonNull - public PriorityPolicy getPriorityPolicy() { - return GetOrDefault(priorityPolicy); - } - - /** - * Gets whether deliver policy of this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean deliverPolicyWasSet() { - return deliverPolicy != null; - } - - /** - * Gets whether ack policy for this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean ackPolicyWasSet() { - return ackPolicy != null; - } - - /** - * Gets whether replay policy for this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean replayPolicyWasSet() { - return replayPolicy != null; - } - - /** - * Gets whether start sequence for this consumer configuration was set or left unset - * @return true if the start sequence was set by the user - */ - public boolean startSeqWasSet() { - return startSeq != null; - } - - /** - * Gets whether max deliver for this consumer configuration was set or left unset - * @return true if max deliver was set by the user - */ - public boolean maxDeliverWasSet() { - return maxDeliver != null; - } - - /** - * Gets whether rate limit for this consumer configuration was set or left unset - * @return true if rate limit was set by the user - */ - public boolean rateLimitWasSet() { - return rateLimit != null; - } - - /** - * Gets whether max ack pending for this consumer configuration was set or left unset - * @return true if mac ack pending was set by the user - */ - public boolean maxAckPendingWasSet() { - return maxAckPending != null; - } - - /** - * Gets whether max pull waiting for this consumer configuration was set or left unset - * @return true if max pull waiting was set by the user - */ - public boolean maxPullWaitingWasSet() { - return maxPullWaiting != null; - } - - /** - * Gets whether max batch for this consumer configuration was set or left unset - * @return true if max batch was set by the user - */ - public boolean maxBatchWasSet() { - return maxBatch != null; - } - - /** - * Gets whether max bytes for this consumer configuration was set or left unset - * @return true if max bytes was set by the user - */ - public boolean maxBytesWasSet() { - return maxBytes != null; - } - - /** - * Gets whether flow control for this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean flowControlWasSet() { - return flowControl != null; - } - - /** - * Gets whether headers only for this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean headersOnlyWasSet() { - return headersOnly != null; - } - - /** - * Gets whether mem storage for this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean memStorageWasSet() { - return memStorage != null; - } - - /** - * Gets whether num replicas for this consumer configuration was set or left unset - * @return true if num replicas was set by the user - */ - public boolean numReplicasWasSet() { - return numReplicas != null; - } - - /** - * Gets whether backoff for this consumer configuration was set or left unset - * @return true if num backoff was set by the user - */ - public boolean backoffWasSet() { - return backoff != null; - } - - /** - * Gets whether metadata for this consumer configuration was set or left unset - * @return true if num metadata was set by the user - */ - public boolean metadataWasSet() { - return metadata != null; - } - - /** - * Gets whether priority policy for this consumer configuration was set or left unset - * @return true if the policy was set, false if the policy was not set - */ - public boolean priorityPolicyWasSet() { - return priorityPolicy != null; - } - - /** - * Creates a builder for the options. - * @return a publish options builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a builder for the options. - * @param cc the consumer configuration - * @return a publish options builder - */ - public static Builder builder(ConsumerConfiguration cc) { - return cc == null ? new Builder() : new Builder(cc); - } - - /** - * ConsumerConfiguration is created using a Builder. The builder supports chaining and will - * create a default set of options if no methods are calls. - * - *

{@code new ConsumerConfiguration.Builder().build()} will create a default ConsumerConfiguration. - * - */ - public static class Builder { - private DeliverPolicy deliverPolicy; - private AckPolicy ackPolicy; - private ReplayPolicy replayPolicy; - - private String description; - private String durable; - private String name; - private String deliverSubject; - private String deliverGroup; - private String sampleFrequency; - - private ZonedDateTime startTime; - private Duration ackWait; - private Duration idleHeartbeat; - private Duration maxExpires; - private Duration inactiveThreshold; - - private Long startSeq; - private Integer maxDeliver; - private Long rateLimit; - private Integer maxAckPending; - private Integer maxPullWaiting; - private Integer maxBatch; - private Integer maxBytes; - private Integer numReplicas; - private ZonedDateTime pauseUntil; - - private Boolean flowControl; - private Boolean headersOnly; - private Boolean memStorage; - - private List backoff; - private Map metadata; - private List filterSubjects; - - private List priorityGroups; - private PriorityPolicy priorityPolicy; - - /** - * Construct the builder - */ - public Builder() {} - - /** - * Construct the builder and initialize values with the existing ConsumerConfiguration - * @param cc the consumer configuration to clone - */ - public Builder(ConsumerConfiguration cc) { - if (cc != null) { - this.deliverPolicy = cc.deliverPolicy; - this.ackPolicy = cc.ackPolicy; - this.replayPolicy = cc.replayPolicy; - - this.description = cc.description; - this.durable = cc.durable; - this.name = cc.name; - this.deliverSubject = cc.deliverSubject; - this.deliverGroup = cc.deliverGroup; - this.sampleFrequency = cc.sampleFrequency; - - this.startTime = cc.startTime; - this.ackWait = cc.ackWait; - this.idleHeartbeat = cc.idleHeartbeat; - this.maxExpires = cc.maxExpires; - this.inactiveThreshold = cc.inactiveThreshold; - - this.startSeq = cc.startSeq; - this.maxDeliver = cc.maxDeliver; - this.rateLimit = cc.rateLimit; - this.maxAckPending = cc.maxAckPending; - this.maxPullWaiting = cc.maxPullWaiting; - this.maxBatch = cc.maxBatch; - this.maxBytes = cc.maxBytes; - this.numReplicas = cc.numReplicas; - this.pauseUntil = cc.pauseUntil; - - this.flowControl = cc.flowControl; - this.headersOnly = cc.headersOnly; - this.memStorage = cc.memStorage; - - if (cc.backoff != null) { - this.backoff = new ArrayList<>(cc.backoff); - } - if (cc.metadata != null) { - this.metadata = new HashMap<>(cc.metadata); - } - if (cc.filterSubjects != null) { - this.filterSubjects = new ArrayList<>(cc.filterSubjects); - } - - if (cc.priorityGroups != null) { - this.priorityGroups = new ArrayList<>(cc.priorityGroups); - } - this.priorityPolicy = cc.priorityPolicy; - } - } - - /** - * Initialize values from the json string. - * @param json the json string to parse - * @return the builder - * @throws JsonParseException if the json is invalid - */ - public Builder json(String json) throws JsonParseException { - return jsonValue(JsonParser.parse(json)); - } - - /** - * Initialize values from the JsonValue object. - * @param jsonValue the json value object - * @return the builder - */ - public Builder jsonValue(JsonValue jsonValue) { - deliverPolicy(DeliverPolicy.get(readString(jsonValue, DELIVER_POLICY))); - ackPolicy(AckPolicy.get(readString(jsonValue, ACK_POLICY))); - - replayPolicy(ReplayPolicy.get(readString(jsonValue, REPLAY_POLICY))); - - description(readString(jsonValue, DESCRIPTION)); - durable(readString(jsonValue, DURABLE_NAME)); - name(readString(jsonValue, NAME)); - deliverSubject(readString(jsonValue, DELIVER_SUBJECT)); - deliverGroup(readString(jsonValue, DELIVER_GROUP)); - sampleFrequency(readString(jsonValue, SAMPLE_FREQ)); - startTime(readDate(jsonValue, OPT_START_TIME)); - ackWait(readNanosAsDuration(jsonValue, ACK_WAIT)); - maxExpires(readNanosAsDuration(jsonValue, MAX_EXPIRES)); - inactiveThreshold(readNanosAsDuration(jsonValue, INACTIVE_THRESHOLD)); - - startSequence(readLong(jsonValue, OPT_START_SEQ)); - maxDeliver(readLong(jsonValue, MAX_DELIVER, INTEGER_UNSET)); - rateLimit(readLong(jsonValue, RATE_LIMIT_BPS)); - maxAckPending(readLong(jsonValue, MAX_ACK_PENDING)); - maxPullWaiting(readLong(jsonValue, MAX_WAITING)); - maxBatch(readLong(jsonValue, MAX_BATCH)); - maxBytes(readLong(jsonValue, MAX_BYTES)); - - Integer r = readInteger(jsonValue, NUM_REPLICAS); - if (r != null) { - if (r == 0) { - numReplicas = 0; - } - else { - numReplicas(r); - } - } - - pauseUntil(readDate(jsonValue, PAUSE_UNTIL)); - - Duration idleHeartbeat = readNanosAsDuration(jsonValue, IDLE_HEARTBEAT); - if (idleHeartbeat != null) { - if (readBoolean(jsonValue, FLOW_CONTROL, false)) { - flowControl(idleHeartbeat); - } - else { - idleHeartbeat(idleHeartbeat); - } - } - - headersOnly(readBoolean(jsonValue, HEADERS_ONLY)); - memStorage(readBoolean(jsonValue, MEM_STORAGE)); - - backoff(readNanosAsDurationListOrEmpty(jsonValue, BACKOFF).toArray(new Duration[0])); - - metadata(readStringMapOrNull(jsonValue, METADATA)); - - String fs = readString(jsonValue, FILTER_SUBJECT); - if (fs == null || fs.trim().isEmpty()) { - filterSubjects(readStringListOrNull(jsonValue, FILTER_SUBJECTS)); - } - else { - filterSubject(fs); - } - - priorityGroups(readStringListOrNull(jsonValue, PRIORITY_GROUPS)); - priorityPolicy(PriorityPolicy.get(readString(jsonValue, PRIORITY_POLICY))); - - return this; - } - - /** - * Sets the description - * @param description the description - * @return the builder - */ - public Builder description(String description) { - this.description = description == null || description.trim().isEmpty() ? null : description; - return this; - } - - /** - * Sets the name of the durable consumer. - * Null or empty clears the field. - * @param durable name of the durable consumer. - * @return the builder - */ - public Builder durable(String durable) { - this.durable = durable; - return this; - } - - /** - * Sets the name of the consumer. - * Null or empty clears the field. - * @param name name of the consumer. - * @return the builder - */ - public Builder name(String name) { - this.name = name; - return this; - } - - /** - * Sets the delivery policy of the ConsumerConfiguration. - * @param policy the delivery policy. - * @return Builder - */ - public Builder deliverPolicy(DeliverPolicy policy) { - this.deliverPolicy = policy; - return this; - } - - /** - * Sets the subject to deliver messages to. - *

By setting the deliverySubject this configuration will create a push consumer. When left empty or set to NULL a pull consumer will be created. - * @param subject the subject. - * @return the builder - */ - public Builder deliverSubject(String subject) { - this.deliverSubject = subject == null || subject.trim().isEmpty() ? null : subject; - return this; - } - - /** - * Sets the group to deliver messages to. - * @param group the delivery group. - * @return the builder - */ - public Builder deliverGroup(String group) { - this.deliverSubject = group == null || group.trim().isEmpty() ? null : group; - return this; - } - - /** - * Sets the start sequence of the ConsumerConfiguration or null to unset / clear. - * @param sequence the start sequence - * @return Builder - */ - public Builder startSequence(Long sequence) { - this.startSeq = normalizeUlong(sequence); - return this; - } - - /** - * Sets the start sequence of the ConsumerConfiguration. - * @param sequence the start sequence - * @return Builder - */ - public Builder startSequence(long sequence) { - this.startSeq = normalizeUlong(sequence); - return this; - } - - /** - * Sets the start time of the ConsumerConfiguration. - * @param startTime the start time - * @return Builder - */ - public Builder startTime(ZonedDateTime startTime) { - this.startTime = startTime; - return this; - } - - /** - * Sets the acknowledgement policy of the ConsumerConfiguration. - * @param policy the acknowledgement policy. - * @return Builder - */ - public Builder ackPolicy(AckPolicy policy) { - this.ackPolicy = policy; - return this; - } - - /** - * Sets the acknowledgement wait duration of the ConsumerConfiguration. - * @param timeout the wait timeout - * @return Builder - */ - public Builder ackWait(Duration timeout) { - this.ackWait = normalize(timeout); - return this; - } - - /** - * Sets the acknowledgement wait duration of the ConsumerConfiguration. - * @param timeoutMillis the wait timeout in milliseconds - * @return Builder - */ - public Builder ackWait(long timeoutMillis) { - this.ackWait = normalizeDuration(timeoutMillis); - return this; - } - - /** - * Sets the maximum delivery amount of the ConsumerConfiguration or null to unset / clear. - * @param maxDeliver the maximum delivery amount - * @return Builder - */ - public Builder maxDeliver(Long maxDeliver) { - this.maxDeliver = normalize(maxDeliver, MAX_DELIVER_MIN); - return this; - } - - /** - * Sets the maximum delivery amount of the ConsumerConfiguration. - * @param maxDeliver the maximum delivery amount - * @return Builder - */ - public Builder maxDeliver(long maxDeliver) { - this.maxDeliver = normalize(maxDeliver, MAX_DELIVER_MIN); - return this; - } - - /** - * Sets the filter subject of the ConsumerConfiguration. - * Replaces any other filter subjects set in the builder - * @param filterSubject the filter subject - * @return Builder - */ - public Builder filterSubject(String filterSubject) { - if (filterSubject == null || filterSubject.trim().isEmpty()) { - this.filterSubjects = null; - } - else { - this.filterSubjects = Collections.singletonList(filterSubject); - } - return this; - } - - /** - * Sets the filter subjects of the ConsumerConfiguration. - * Replaces any other filter subjects set in the builder - * @param filterSubjects one or more filter subjects - * @return Builder - */ - public Builder filterSubjects(String... filterSubjects) { - return filterSubjects(Arrays.asList(filterSubjects)); - } - - /** - * Sets the filter subjects of the ConsumerConfiguration. - * Replaces any other filter subjects set in the builder - * @param filterSubjects the list of filter subjects - * @return Builder - */ - public Builder filterSubjects(List filterSubjects) { - this.filterSubjects = new ArrayList<>(); - if (filterSubjects != null) { - for (String fs : filterSubjects) { - if (fs != null && !fs.trim().isEmpty()) { - this.filterSubjects.add(fs); - } - } - } - if (this.filterSubjects.isEmpty()) { - this.filterSubjects = null; - } - return this; - } - - /** - * Sets the replay policy of the ConsumerConfiguration. - * @param policy the replay policy. - * @return Builder - */ - public Builder replayPolicy(ReplayPolicy policy) { - this.replayPolicy = policy; - return this; - } - - /** - * Sets the sample frequency of the ConsumerConfiguration. - * @param frequency the frequency - * @return Builder - */ - public Builder sampleFrequency(String frequency) { - this.sampleFrequency = frequency == null || frequency.trim().isEmpty() ? null : frequency; - return this; - } - - /** - * Set the rate limit of the ConsumerConfiguration or null to unset / clear. - * @param bitsPerSecond bits per second to deliver - * @return Builder - */ - public Builder rateLimit(Long bitsPerSecond) { - this.rateLimit = normalizeUlong(bitsPerSecond); - return this; - } - - /** - * Set the rate limit of the ConsumerConfiguration. - * @param bitsPerSecond bits per second to deliver - * @return Builder - */ - public Builder rateLimit(long bitsPerSecond) { - this.rateLimit = normalizeUlong(bitsPerSecond); - return this; - } - - /** - * Sets the maximum ack pending or null to unset / clear. - * @param maxAckPending maximum pending acknowledgements. - * @return Builder - */ - public Builder maxAckPending(Long maxAckPending) { - this.maxAckPending = normalize(maxAckPending, STANDARD_MIN); - return this; - } - - /** - * Sets the maximum ack pending. - * @param maxAckPending maximum pending acknowledgements. - * @return Builder - */ - public Builder maxAckPending(long maxAckPending) { - this.maxAckPending = normalize(maxAckPending, STANDARD_MIN); - return this; - } - - /** - * sets the idle heart beat wait time - * @param idleHeartbeat the idle heart beat duration - * @return Builder - */ - public Builder idleHeartbeat(Duration idleHeartbeat) { - if (idleHeartbeat == null) { - this.idleHeartbeat = null; - } - else { - long nanos = idleHeartbeat.toNanos(); - if (nanos <= DURATION_UNSET_LONG) { - this.idleHeartbeat = DURATION_UNSET; - } - else if (nanos < MIN_IDLE_HEARTBEAT_NANOS) { - throw new IllegalArgumentException("Duration must be greater than or equal to " + MIN_IDLE_HEARTBEAT_NANOS + " nanos."); - } - else { - this.idleHeartbeat = idleHeartbeat; - } - } - return this; - } - - /** - * sets the idle heart beat wait time - * @param idleHeartbeatMillis the idle heart beat duration in milliseconds - * @return Builder - */ - public Builder idleHeartbeat(long idleHeartbeatMillis) { - if (idleHeartbeatMillis <= DURATION_UNSET_LONG) { - this.idleHeartbeat = DURATION_UNSET; - } - else if (idleHeartbeatMillis < MIN_IDLE_HEARTBEAT_MILLIS) { - throw new IllegalArgumentException("Duration must be greater than or equal to " + MIN_IDLE_HEARTBEAT_MILLIS + " milliseconds."); - } - else { - this.idleHeartbeat = Duration.ofMillis(idleHeartbeatMillis); - } - return this; - } - - /** - * set the flow control on and set the idle heartbeat - * @param idleHeartbeat the idle heart beat duration - * @return Builder - */ - public Builder flowControl(Duration idleHeartbeat) { - this.flowControl = true; - return idleHeartbeat(idleHeartbeat); - } - - /** - * set the flow control on and set the idle heartbeat - * @param idleHeartbeatMillis the idle heart beat duration in milliseconds - * @return Builder - */ - public Builder flowControl(long idleHeartbeatMillis) { - this.flowControl = true; - return idleHeartbeat(idleHeartbeatMillis); - } - - /** - * sets the max amount of expire time for the server to allow on pull requests. - * @param maxExpires the max expire duration - * @return Builder - */ - public Builder maxExpires(Duration maxExpires) { - this.maxExpires = normalize(maxExpires); - return this; - } - - /** - * sets the max amount of expire time for the server to allow on pull requests. - * @param maxExpires the max expire duration in milliseconds - * @return Builder - */ - public Builder maxExpires(long maxExpires) { - this.maxExpires = normalizeDuration(maxExpires); - return this; - } - - /** - * sets the amount of time before the consumer is deemed inactive. - * @param inactiveThreshold the threshold duration - * @return Builder - */ - public Builder inactiveThreshold(Duration inactiveThreshold) { - this.inactiveThreshold = normalize(inactiveThreshold); - return this; - } - - /** - * sets the amount of time before the consumer is deemed inactive. - * @param inactiveThreshold the threshold duration in milliseconds - * @return Builder - */ - public Builder inactiveThreshold(long inactiveThreshold) { - this.inactiveThreshold = normalizeDuration(inactiveThreshold); - return this; - } - - /** - * sets the max pull waiting, the number of pulls that can be outstanding on a pull consumer, pulls received after this is reached are ignored. - * Use null to unset / clear. - * @param maxPullWaiting the max pull waiting - * @return Builder - */ - public Builder maxPullWaiting(Long maxPullWaiting) { - this.maxPullWaiting = normalize(maxPullWaiting, STANDARD_MIN); - return this; - } - - /** - * sets the max pull waiting, the number of pulls that can be outstanding on a pull consumer, pulls received after this is reached are ignored. - * @param maxPullWaiting the max pull waiting - * @return Builder - */ - public Builder maxPullWaiting(long maxPullWaiting) { - this.maxPullWaiting = normalize(maxPullWaiting, STANDARD_MIN); - return this; - } - - /** - * sets the max batch size for the server to allow on pull requests. - * @param maxBatch the max batch size - * @return Builder - */ - public Builder maxBatch(Long maxBatch) { - this.maxBatch = normalize(maxBatch, STANDARD_MIN); - return this; - } - - /** - * sets the max batch size for the server to allow on pull requests. - * @param maxBatch the max batch size - * @return Builder - */ - public Builder maxBatch(long maxBatch) { - this.maxBatch = normalize(maxBatch, STANDARD_MIN); - return this; - } - - /** - * sets the max bytes size for the server to allow on pull requests. - * @param maxBytes the max bytes size - * @return Builder - */ - public Builder maxBytes(Long maxBytes) { - this.maxBytes = normalize(maxBytes, STANDARD_MIN); - return this; - } - - /** - * sets the max bytes size for the server to allow on pull requests. - * @param maxBytes the max bytes size - * @return Builder - */ - public Builder maxBytes(long maxBytes) { - this.maxBytes = normalize(maxBytes, STANDARD_MIN); - return this; - } - - /** - * set the number of replicas for the consumer. When set do not inherit the - * replica count from the stream but specifically set it to this amount. - * @param numReplicas number of replicas for the consumer - * @return Builder - */ - public Builder numReplicas(Integer numReplicas) { - this.numReplicas = numReplicas; - return this; - } - - /** - * Sets the time to pause the consumer until. - * @param pauseUntil the time to pause - * @return Builder - */ - public Builder pauseUntil(ZonedDateTime pauseUntil) { - this.pauseUntil = pauseUntil; - return this; - } - - /** - * set the headers only flag saying to deliver only the headers of - * messages in the stream and not the bodies - * @param headersOnly the flag - * @return Builder - */ - public Builder headersOnly(Boolean headersOnly) { - this.headersOnly = headersOnly; - return this; - } - - /** - * set the mem storage flag to force the consumer state to be kept - * in memory rather than inherit the setting from the stream - * @param memStorage the flag - * @return Builder - */ - public Builder memStorage(Boolean memStorage) { - this.memStorage = memStorage; - return this; - } - - /** - * Set the list of backoff. Will override ackwait setting. - * @see Delivery Reliability - * @param backoffs zero or more backoff durations or an array of backoffs - * @return Builder - */ - public Builder backoff(Duration... backoffs) { - if (backoffs == null || (backoffs.length == 1 && backoffs[0] == null)) - { - backoff = null; - } - else - { - backoff = new ArrayList<>(); - for (Duration d : backoffs) - { - if (d != null) - { - if (d.toNanos() < DURATION_MIN_LONG) - { - throw new IllegalArgumentException("Backoff cannot be less than " + DURATION_MIN_LONG); - } - backoff.add(d); - } - } - } - return this; - } - - /** - * Set the list of backoff. Will override ackwait setting. - * @see Delivery Reliability - * @param backoffsMillis zero or more backoff in millis or an array of backoffsMillis - * @return Builder - */ - public Builder backoff(long... backoffsMillis) { - if (backoffsMillis == null) { - backoff = null; - } - else { - backoff = new ArrayList<>(); - for (long ms : backoffsMillis) { - if (ms < DURATION_MIN_LONG) { - throw new IllegalArgumentException("Backoff cannot be less than " + DURATION_MIN_LONG); - } - this.backoff.add(Duration.ofMillis(ms)); - } - } - return this; - } - - /** - * Sets the metadata for the configuration - * @param metadata the metadata map - * @return Builder - */ - public Builder metadata(Map metadata) { - this.metadata = metadata == null || metadata.isEmpty() ? null : new HashMap<>(metadata); - return this; - } - - /** - * Sets the priority groups of the ConsumerConfiguration. - * Replaces any other priority groups set in the builder - * @param priorityGroups one or more priority groups - * @return Builder - */ - public Builder priorityGroups(String... priorityGroups) { - return priorityGroups(Arrays.asList(priorityGroups)); - } - - /** - * Sets the priority groups of the ConsumerConfiguration. - * Replaces any other priority groups set in the builder - * @param priorityGroups the list of priority groups - * @return Builder - */ - public Builder priorityGroups(List priorityGroups) { - this.priorityGroups = new ArrayList<>(); - if (priorityGroups != null) { - for (String pg : priorityGroups) { - if (pg != null && !pg.trim().isEmpty()) { - this.priorityGroups.add(pg); - } - } - } - if (this.priorityGroups.isEmpty()) { - this.priorityGroups = null; - } - return this; - } - - /** - * Sets the priority policy of the ConsumerConfiguration. - * @param policy the priority policy. - * @return Builder - */ - public Builder priorityPolicy(PriorityPolicy policy) { - this.priorityPolicy = policy; - return this; - } - - /** - * Builds the ConsumerConfiguration - * @return The consumer configuration. - */ - public ConsumerConfiguration build() { - return new ConsumerConfiguration(this); - } - } - - @Override - public String toString() { - return "ConsumerConfiguration " + toJson(); - } - - protected static int getOrUnset(Integer val) - { - return val == null ? INTEGER_UNSET : val; - } - - protected static long getOrUnsetUlong(Long val) - { - return val == null || val < 0 ? ULONG_UNSET : val; - } - - protected static Integer normalize(Long l, int min) { - if (l == null) { - return null; - } - - if (l < min) { - return INTEGER_UNSET; - } - - if (l > Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } - - return l.intValue(); - } - - protected static Long normalizeUlong(Long u) - { - return u == null ? null : u <= ULONG_UNSET ? ULONG_UNSET : u; - } - - protected static Duration normalize(Duration d) - { - return d == null ? null : d.toNanos() <= DURATION_UNSET_LONG ? DURATION_UNSET : d; - } - - protected static Duration normalizeDuration(long millis) - { - return millis <= DURATION_UNSET_LONG ? DURATION_UNSET : Duration.ofMillis(millis); - } - - protected static DeliverPolicy GetOrDefault(DeliverPolicy p) { return p == null ? DEFAULT_DELIVER_POLICY : p; } - protected static AckPolicy GetOrDefault(AckPolicy p) { return p == null ? DEFAULT_ACK_POLICY : p; } - protected static ReplayPolicy GetOrDefault(ReplayPolicy p) { return p == null ? DEFAULT_REPLAY_POLICY : p; } - protected static PriorityPolicy GetOrDefault(PriorityPolicy p) { return p == null ? DEFAULT_PRIORITY_POLICY : p; } -} diff --git a/src/test/java/io/nats/client/api/ConsumerLimits.java b/src/test/java/io/nats/client/api/ConsumerLimits.java deleted file mode 100644 index afab22c..0000000 --- a/src/test/java/io/nats/client/api/ConsumerLimits.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.time.Duration; - -import static io.nats.client.api.ConsumerConfiguration.getOrUnset; -import static io.nats.client.support.ApiConstants.INACTIVE_THRESHOLD; -import static io.nats.client.support.ApiConstants.MAX_ACK_PENDING; -import static io.synadia.json.JsonValueUtils.readInteger; -import static io.synadia.json.JsonValueUtils.readNanosAsDuration; -import static io.synadia.json.JsonWriteUtils.*; - -/** - * ConsumerLimits - */ -public class ConsumerLimits implements JsonSerializable { - private final Duration inactiveThreshold; - private final Integer maxAckPending; - - static ConsumerLimits optionalInstance(JsonValue vConsumerLimits) { - return vConsumerLimits == null ? null : new ConsumerLimits(vConsumerLimits); - } - - public ConsumerLimits(JsonValue vConsumerLimits) { - inactiveThreshold = readNanosAsDuration(vConsumerLimits, INACTIVE_THRESHOLD); - maxAckPending = readInteger(vConsumerLimits, MAX_ACK_PENDING); - } - - /** - * Maximum value for inactive_threshold for consumers of this stream. Acts as a default when consumers do not set this value. - * @return the inactive threshold limit - */ - @Nullable - public Duration getInactiveThreshold() { - return inactiveThreshold; - } - - /** - * Maximum value for max_ack_pending for consumers of this stream. Acts as a default when consumers do not set this value. - * @return maximum ack pending limit - */ - public long getMaxAckPending() { - return getOrUnset(maxAckPending); - } - - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addFieldAsNanos(sb, INACTIVE_THRESHOLD, inactiveThreshold); - addField(sb, MAX_ACK_PENDING, maxAckPending); - return endJson(sb).toString(); - } -} diff --git a/src/test/java/io/nats/client/api/DeliverPolicy.java b/src/test/java/io/nats/client/api/DeliverPolicy.java deleted file mode 100644 index ca616c3..0000000 --- a/src/test/java/io/nats/client/api/DeliverPolicy.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * The delivery policy for this consumer. - */ -public enum DeliverPolicy { - All("all"), - Last("last"), - New("new"), - ByStartSequence("by_start_sequence"), - ByStartTime("by_start_time"), - LastPerSubject("last_per_subject"); - - private final String policy; - - DeliverPolicy(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (DeliverPolicy env : DeliverPolicy.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static DeliverPolicy get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/DiscardPolicy.java b/src/test/java/io/nats/client/api/DiscardPolicy.java deleted file mode 100644 index bc27b22..0000000 --- a/src/test/java/io/nats/client/api/DiscardPolicy.java +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Stream discard policies - */ -public enum DiscardPolicy { - New("new"), - Old("old"); - - private final String policy; - - DiscardPolicy(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (DiscardPolicy env : DiscardPolicy.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static DiscardPolicy get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/External.java b/src/test/java/io/nats/client/api/External.java deleted file mode 100644 index fe5705c..0000000 --- a/src/test/java/io/nats/client/api/External.java +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import io.synadia.json.JsonValueUtils; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import static io.nats.client.support.ApiConstants.API; -import static io.nats.client.support.ApiConstants.DELIVER; -import static io.synadia.json.JsonWriteUtils.*; - -/** - * External configuration referencing a stream source in another account - */ -public class External implements JsonSerializable { - private final String api; - private final String deliver; - - static External optionalInstance(JsonValue vExternal) { - return vExternal == null ? null : new External(vExternal); - } - - External(JsonValue vExternal) { - api = JsonValueUtils.readString(vExternal, API); - deliver = JsonValueUtils.readString(vExternal, DELIVER); - } - - /** - * Construct the External configuration - * @param api the api prefix - * @param deliver the delivery subject - */ - public External(String api, String deliver) { - this.api = api; - this.deliver = deliver; - } - - /** - * Returns a JSON representation of this mirror - * - * @return json mirror json string - */ - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addField(sb, API, api); - addField(sb, DELIVER, deliver); - return endJson(sb).toString(); - } - - /** - * The subject prefix that imports the other account $JS.API.CONSUMER.> subjects - * @return the api prefix - */ - @Nullable - public String getApi() { - return api; - } - - /** - * The delivery subject to use for the push consumer. - * @return delivery subject - */ - @Nullable - public String getDeliver() { - return deliver; - } - - @Override - public String toString() { - return "External{" + - "api='" + api + '\'' + - ", deliver='" + deliver + '\'' + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - External external = (External) o; - - if (api != null ? !api.equals(external.api) : external.api != null) return false; - return deliver != null ? deliver.equals(external.deliver) : external.deliver == null; - } - - @Override - public int hashCode() { - int result = api != null ? api.hashCode() : 0; - result = 31 * result + (deliver != null ? deliver.hashCode() : 0); - return result; - } - - /** - * Creates a builder for an External object. - * @return the builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Placement can be created using a Builder. - */ - public static class Builder { - private String api; - private String deliver; - - /** - * Set the api string. - * @param api the api - * @return the builder - */ - public Builder api(String api) { - this.api = api; - return this; - } - - /** - * Set the deliver string. - * @param deliver the deliver - * @return the builder - */ - public Builder deliver(String deliver) { - this.deliver = deliver; - return this; - } - - /** - * Build an External object - * @return the External object - */ - public External build() { - return new External(api, deliver); - } - } -} diff --git a/src/test/java/io/nats/client/api/LostStreamData.java b/src/test/java/io/nats/client/api/LostStreamData.java deleted file mode 100644 index f2832db..0000000 --- a/src/test/java/io/nats/client/api/LostStreamData.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.util.List; - -import static io.nats.client.support.ApiConstants.BYTES; -import static io.nats.client.support.ApiConstants.MSGS; -import static io.synadia.json.JsonValueUtils.readLong; -import static io.synadia.json.JsonValueUtils.readLongListOrEmpty; - -/** - * Information about lost stream data - */ -public class LostStreamData { - private final List messages; - private final Long bytes; - - static LostStreamData optionalInstance(JsonValue vLost) { - return vLost == null ? null : new LostStreamData(vLost); - } - - - LostStreamData(JsonValue vLost) { - messages = readLongListOrEmpty(vLost, MSGS); - bytes = readLong(vLost, BYTES); - } - - /** - * Get the lost message ids. May be empty - * @return the list of message ids - */ - @NonNull - public List getMessages() { - return messages; - } - - /** - * Get the number of bytes that were lost - * @return the number of lost bytes - */ - @Nullable - public Long getBytes() { - return bytes; - } - - @Override - public String toString() { - return "LostStreamData{" + - "messages=" + messages + - ", bytes=" + bytes + - '}'; - } -} diff --git a/src/test/java/io/nats/client/api/Mirror.java b/src/test/java/io/nats/client/api/Mirror.java deleted file mode 100644 index a3a0ea9..0000000 --- a/src/test/java/io/nats/client/api/Mirror.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; - -/** - * Mirror Information. Maintains a 1:1 mirror of another stream with name matching this property. - * When a mirror is configured subjects and sources must be empty. - */ -public class Mirror extends SourceBase { - - public static Mirror optionalInstance(JsonValue vMirror) { - return vMirror == null ? null : new Mirror(vMirror); - } - - public Mirror(JsonValue vMirror) { - super(vMirror); - } -} diff --git a/src/test/java/io/nats/client/api/MirrorInfo.java b/src/test/java/io/nats/client/api/MirrorInfo.java deleted file mode 100644 index a4402e5..0000000 --- a/src/test/java/io/nats/client/api/MirrorInfo.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - - -import io.synadia.json.JsonValue; - -/** - * Information about an upstream stream source in a mirror - */ -public class MirrorInfo extends SourceInfoBase { - - static MirrorInfo optionalInstance(JsonValue vMirror) { - return vMirror == null ? null : new MirrorInfo(vMirror); - } - - MirrorInfo(JsonValue vMirror) { - super(vMirror); - } - - @Override - public String toString() { - return "MirrorInfo " + super.toString(); - } -} diff --git a/src/test/java/io/nats/client/api/PeerInfo.java b/src/test/java/io/nats/client/api/PeerInfo.java deleted file mode 100644 index 147962a..0000000 --- a/src/test/java/io/nats/client/api/PeerInfo.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; - -import java.time.Duration; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; - -public class PeerInfo { - - private final String name; - private final boolean current; - private final boolean offline; - private final Duration active; - private final long lag; - - PeerInfo(JsonValue vPeerInfo) { - name = readString(vPeerInfo, NAME); - current = readBoolean(vPeerInfo, CURRENT, false); - offline = readBoolean(vPeerInfo, OFFLINE, false); - active = readNanosAsDuration(vPeerInfo, ACTIVE, Duration.ZERO); - lag = readLong(vPeerInfo, LAG, 0); - } - - /** - * The server name of the peer - * @return the name - */ - @NonNull - public String getName() { - return name; - } - - /** - * Indicates if the server is up-to-date and synchronised - * @return if is current - */ - public boolean isCurrent() { - return current; - } - - /** - * Indicates the node is considered offline by the group - * @return if is offline - */ - public boolean isOffline() { - return offline; - } - - /** - * Time since this peer was last seen - * @return the active time - */ - @NonNull - public Duration getActive() { - return active; - } - - /** - * How many uncommitted operations this peer is behind the leader - * @return the lag - */ - public long getLag() { - return lag; - } -} diff --git a/src/test/java/io/nats/client/api/Placement.java b/src/test/java/io/nats/client/api/Placement.java deleted file mode 100644 index e9198a8..0000000 --- a/src/test/java/io/nats/client/api/Placement.java +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; - -import static io.nats.client.support.ApiConstants.CLUSTER; -import static io.nats.client.support.ApiConstants.TAGS; -import static io.synadia.json.JsonValueUtils.readString; -import static io.synadia.json.JsonValueUtils.readStringListOrNull; -import static io.synadia.json.JsonWriteUtils.*; - -/** - * Placement directives to consider when placing replicas of a stream - */ -public class Placement implements JsonSerializable { - private final String cluster; - private final List tags; - - static Placement optionalInstance(JsonValue vPlacement) { - return vPlacement == null ? null : new Placement(vPlacement); - } - - Placement(JsonValue vPlacement) { - this.cluster = readString(vPlacement, CLUSTER); - this.tags = readStringListOrNull(vPlacement, TAGS); - } - - /** - * Construct a placement object - * @param cluster the cluster name - * @param tags the list of tags, may be null - */ - public Placement(String cluster, List tags) { - this.cluster = cluster == null || cluster.isEmpty() ? null : cluster; - this.tags = tags == null || tags.isEmpty() ? null : tags; - } - - public boolean hasData() { - return cluster != null || tags != null; - } - - /** - * The desired cluster name to place the stream. - * @return The cluster name - */ - @Nullable - public String getCluster() { - return cluster; - } - - /** - * Tags required on servers hosting this stream - * @return the list of tags - */ - @Nullable - public List getTags() { - return tags; - } - - @Override - public String toString() { - return "Placement{" + - "cluster='" + cluster + '\'' + - ", tags=" + tags + - '}'; - } - - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addField(sb, CLUSTER, cluster); - addStrings(sb, TAGS, tags); - return endJson(sb).toString(); - } - - /** - * Creates a builder for a placements object. - * @return the builder. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Placement can be created using a Builder. - */ - public static class Builder { - private String cluster; - private List tags; - - /** - * Set the cluster string. - * @param cluster the cluster - * @return the builder - */ - public Builder cluster(String cluster) { - this.cluster = cluster; - return this; - } - - /** - * Set the tags - * @param tags the list of tags - * @return the builder - */ - public Builder tags(String... tags) { - this.tags = Arrays.asList(tags); - return this; - } - - /** - * Set the tags - * @param tags the list of tags - * @return the builder - */ - public Builder tags(List tags) { - this.tags = tags; - return this; - } - - /** - * Build a Placement object - * @return the Placement - */ - public Placement build() { - return new Placement(cluster, tags); - } - } -} diff --git a/src/test/java/io/nats/client/api/PriorityPolicy.java b/src/test/java/io/nats/client/api/PriorityPolicy.java deleted file mode 100644 index ac65fe2..0000000 --- a/src/test/java/io/nats/client/api/PriorityPolicy.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Represents the Priority Policy of a consumer - */ -public enum PriorityPolicy { - None("none"), - Overflow("overflow"), - PinnedClient("pinned_client"); - - private final String policy; - - PriorityPolicy(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (PriorityPolicy env : PriorityPolicy.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static PriorityPolicy get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/ReplayPolicy.java b/src/test/java/io/nats/client/api/ReplayPolicy.java deleted file mode 100644 index 6d0953c..0000000 --- a/src/test/java/io/nats/client/api/ReplayPolicy.java +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Represents the replay policy of a consumer. - */ -public enum ReplayPolicy { - Instant("instant"), - Original("original"); - - private String policy; - - ReplayPolicy(String p) { - this.policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (ReplayPolicy env : ReplayPolicy.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static ReplayPolicy get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/Replica.java b/src/test/java/io/nats/client/api/Replica.java deleted file mode 100644 index 5bdba12..0000000 --- a/src/test/java/io/nats/client/api/Replica.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import io.synadia.json.JsonValueUtils; - -import java.util.List; - -public class Replica extends PeerInfo { - - static List optionalListOf(JsonValue vReplicas) { - return JsonValueUtils.listOfOrEmpty(vReplicas, Replica::new); - } - - Replica(JsonValue vReplica) { - super(vReplica); - } - - @Override - public String toString() { - return "Replica{" + - "name='" + getName() + '\'' + - ", current=" + isCurrent() + - ", offline=" + isOffline() + - ", active=" + getActive() + - ", lag=" + getLag() + - '}'; - } -} diff --git a/src/test/java/io/nats/client/api/Republish.java b/src/test/java/io/nats/client/api/Republish.java deleted file mode 100644 index 5504766..0000000 --- a/src/test/java/io/nats/client/api/Republish.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.readBoolean; -import static io.synadia.json.JsonValueUtils.readString; -import static io.synadia.json.JsonWriteUtils.*; - -/** - * Republish Configuration - */ -public class Republish implements JsonSerializable { - private final String source; - private final String destination; - private final boolean headersOnly; - - static Republish optionalInstance(JsonValue vRepublish) { - return vRepublish == null ? null : new Republish(vRepublish); - } - - Republish(JsonValue vRepublish) { - source = readString(vRepublish, SRC); - destination = readString(vRepublish, DEST); - headersOnly = readBoolean(vRepublish, HEADERS_ONLY, false); - } - - /** - * Get source, the Published subject matching filter - * @return the source - */ - @NonNull - public String getSource() { - return source; - } - - /** - * Get destination, the RePublish Subject template - * @return the destination - */ - @NonNull - public String getDestination() { - return destination; - } - - /** - * Get headersOnly, Whether to RePublish only headers (no body) - * @return headersOnly - */ - public boolean isHeadersOnly() { - return headersOnly; - } - - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addField(sb, SRC, source); - addField(sb, DEST, destination); - addField(sb, HEADERS_ONLY, headersOnly); - return endJson(sb).toString(); - } -} diff --git a/src/test/java/io/nats/client/api/RetentionPolicy.java b/src/test/java/io/nats/client/api/RetentionPolicy.java deleted file mode 100644 index c1c5c7f..0000000 --- a/src/test/java/io/nats/client/api/RetentionPolicy.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; - -/** - * Stream retention policies. - */ -public enum RetentionPolicy { - Limits("limits"), - Interest("interest"), - WorkQueue("workqueue"); - - private final String policy; - - RetentionPolicy(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - private static final Map strEnumHash = new HashMap<>(); - - static { - for (RetentionPolicy env : RetentionPolicy.values()) { - strEnumHash.put(env.toString(), env); - } - } - - @Nullable - public static RetentionPolicy get(String value) { - return strEnumHash.get(value); - } -} diff --git a/src/test/java/io/nats/client/api/ServerInfo.java b/src/test/java/io/nats/client/api/ServerInfo.java deleted file mode 100644 index 970b4b8..0000000 --- a/src/test/java/io/nats/client/api/ServerInfo.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonParseException; -import io.synadia.json.JsonParser; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; - -public class ServerInfo { - - public static final ServerInfo EMPTY_INFO = new ServerInfo("INFO {}"); - - private final String serverId; - private final String serverName; - private final String version; - private final String go; - private final String host; - private final int port; - private final boolean headersSupported; - private final boolean authRequired; - private final boolean tlsRequired; - private final boolean tlsAvailable; - private final long maxPayload; - private final List connectURLs; - private final int protocolVersion; - private final byte[] nonce; - private final boolean lameDuckMode; - private final boolean jetStream; - private final int clientId; - private final String clientIp; - private final String cluster; - - public ServerInfo(String json) { - // INFO{ INFO<\t>{ or { - if (json == null || json.length() < 6 || ('{' != json.charAt(0) && '{' != json.charAt(5))) { - throw new IllegalArgumentException("Invalid Server Info"); - } - - JsonValue jv; - try { - jv = JsonParser.parse(json, json.indexOf("{")); - } - catch (JsonParseException e) { - throw new IllegalArgumentException("Invalid Server Info Json"); - } - - serverId = readString(jv, SERVER_ID, "UNDEFINED"); - serverName = readString(jv, SERVER_NAME, "UNDEFINED"); - version = readString(jv, VERSION, "0.0.0"); - go = readString(jv, GO, "0.0.0"); - host = readString(jv, HOST, "UNDEFINED"); - headersSupported = readBoolean(jv, HEADERS, false); - authRequired = readBoolean(jv, AUTH_REQUIRED, false); - nonce = readBytes(jv, NONCE); - tlsRequired = readBoolean(jv, TLS_REQUIRED, false); - tlsAvailable = readBoolean(jv, TLS_AVAILABLE, false); - lameDuckMode = readBoolean(jv, LAME_DUCK_MODE, false); - jetStream = readBoolean(jv, JETSTREAM, false); - port = readInteger(jv, PORT, 0); - protocolVersion = readInteger(jv, PROTO, 0); - maxPayload = readLong(jv, MAX_PAYLOAD, 0); - clientId = readInteger(jv, CLIENT_ID, 0); - clientIp = readString(jv, CLIENT_IP, "0.0.0.0"); - cluster = readString(jv, CLUSTER); - connectURLs = readStringListOrEmpty(jv, CONNECT_URLS); - } - - public boolean isLameDuckMode() { - return lameDuckMode; - } - - @NonNull - public String getServerId() { - return this.serverId; - } - - @NonNull - public String getServerName() { - return serverName; - } - - @NonNull - public String getVersion() { - return this.version; - } - - @NonNull - public String getGoVersion() { - return this.go; - } - - @NonNull - public String getHost() { - return this.host; - } - - public int getPort() { - return this.port; - } - - public int getProtocolVersion() { - return this.protocolVersion; - } - - public boolean isHeadersSupported() { return this.headersSupported; } - - public boolean isAuthRequired() { - return this.authRequired; - } - - public boolean isTLSRequired() { - return this.tlsRequired; - } - - public boolean isTLSAvailable() { - return tlsAvailable; - } - - public long getMaxPayload() { - return this.maxPayload; - } - - @NonNull - public List getConnectURLs() { - return this.connectURLs; - } - - public byte @Nullable [] getNonce() { - return this.nonce; - } - - public boolean isJetStreamAvailable() { - return this.jetStream; - } - - public int getClientId() { - return clientId; - } - - @NonNull - public String getClientIp() { - return clientIp; - } - - @Nullable - public String getCluster() { - return cluster; - } - - @Override - public String toString() { - return "ServerInfo{" + - "serverId='" + serverId + '\'' + - ", serverName='" + serverName + '\'' + - ", version='" + version + '\'' + - ", go='" + go + '\'' + - ", host='" + host + '\'' + - ", port=" + port + - ", headersSupported=" + headersSupported + - ", authRequired=" + authRequired + - ", tlsRequired=" + tlsRequired + - ", tlsAvailable=" + tlsAvailable + - ", maxPayload=" + maxPayload + - ", connectURLs=" + connectURLs + - ", protocolVersion=" + protocolVersion + - ", nonce=" + Arrays.toString(nonce) + - ", lameDuckMode=" + lameDuckMode + - ", jetStream=" + jetStream + - ", clientId=" + clientId + - ", clientIp='" + clientIp + '\'' + - ", cluster='" + cluster + '\'' + - '}'; - } -} diff --git a/src/test/java/io/nats/client/api/Source.java b/src/test/java/io/nats/client/api/Source.java deleted file mode 100644 index 1dccb41..0000000 --- a/src/test/java/io/nats/client/api/Source.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - - -import io.synadia.json.JsonValue; -import io.synadia.json.JsonValueUtils; - -import java.util.List; - -/** - * Source Information - */ -public class Source extends SourceBase { - - static List optionalListOf(JsonValue vSources) { - return JsonValueUtils.listOfOrEmpty(vSources, Source::new); - } - - public Source(JsonValue vSource) { - super(vSource); - } -} diff --git a/src/test/java/io/nats/client/api/SourceBase.java b/src/test/java/io/nats/client/api/SourceBase.java deleted file mode 100644 index cb0c17e..0000000 --- a/src/test/java/io/nats/client/api/SourceBase.java +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; - -import java.time.ZonedDateTime; -import java.util.List; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; -import static io.synadia.json.JsonWriteUtils.*; - -public abstract class SourceBase implements JsonSerializable { - private final String name; - private final long startSeq; - private final ZonedDateTime startTime; - private final String filterSubject; - private final External external; - private final List subjectTransforms; - - SourceBase(JsonValue jv) { - name = readString(jv, NAME); - startSeq = readLong(jv, OPT_START_SEQ, 0); - startTime = readDate(jv, OPT_START_TIME); - filterSubject = readString(jv, FILTER_SUBJECT); - external = External.optionalInstance(readValue(jv, EXTERNAL)); - subjectTransforms = SubjectTransform.optionalListOf(readValue(jv, SUBJECT_TRANSFORMS)); - } - - /** - * Returns a JSON representation of this mirror - * @return json mirror json string - */ - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addField(sb, NAME, name); - addFieldWhenGreaterThan(sb, OPT_START_SEQ, startSeq, 0); - addField(sb, OPT_START_TIME, startTime); - addField(sb, FILTER_SUBJECT, filterSubject); - addField(sb, EXTERNAL, external); - addJsons(sb, SUBJECT_TRANSFORMS, subjectTransforms); - return endJson(sb).toString(); - } -} diff --git a/src/test/java/io/nats/client/api/SourceInfo.java b/src/test/java/io/nats/client/api/SourceInfo.java deleted file mode 100644 index 08a090c..0000000 --- a/src/test/java/io/nats/client/api/SourceInfo.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import io.synadia.json.JsonValueUtils; - -import java.util.List; - -/** - * Information about a stream being sourced - */ -public class SourceInfo extends SourceInfoBase { - - static List optionalListOf(JsonValue vSourceInfos) { - return JsonValueUtils.listOfOrEmpty(vSourceInfos, SourceInfo::new); - } - - SourceInfo(JsonValue vSourceInfo) { - super(vSourceInfo); - } - - @Override - public String toString() { - return "SourceInfo " + jv; - } -} diff --git a/src/test/java/io/nats/client/api/SourceInfoBase.java b/src/test/java/io/nats/client/api/SourceInfoBase.java deleted file mode 100644 index 6f98659..0000000 --- a/src/test/java/io/nats/client/api/SourceInfoBase.java +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.time.Duration; -import java.util.List; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; - -abstract class SourceInfoBase { - protected final JsonValue jv; - protected final String name; - protected final long lag; - protected final Duration active; - protected final External external; - protected final List subjectTransforms; - - SourceInfoBase(JsonValue vSourceInfo) { - jv = vSourceInfo; - name = readString(vSourceInfo, NAME); - lag = readLong(vSourceInfo, LAG, 0); - active = readNanosAsDuration(vSourceInfo, ACTIVE, Duration.ZERO); - external = External.optionalInstance(readValue(vSourceInfo, EXTERNAL)); - subjectTransforms = SubjectTransform.optionalListOf(readValue(vSourceInfo, SUBJECT_TRANSFORMS)); - } - - /** - * The name of the Stream being replicated - * @return the name - */ - @NonNull - public String getName() { - return name; - } - - /** - * How many uncommitted operations this peer is behind the leader - * @return the lag - */ - public long getLag() { - return lag; - } - - /** - * Time since this peer was last seen - * @return the time - */ - @NonNull - public Duration getActive() { - return active; - } - - /** - * Configuration referencing a stream source in another account or JetStream domain - * @return the external - */ - @Nullable - public External getExternal() { - return external; - } - - /** - * The list of subject transforms, if any - * @return the list of subject transforms - */ - @Nullable - public List getSubjectTransforms() { - return subjectTransforms; - } -} diff --git a/src/test/java/io/nats/client/api/StorageType.java b/src/test/java/io/nats/client/api/StorageType.java deleted file mode 100644 index 4b31991..0000000 --- a/src/test/java/io/nats/client/api/StorageType.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import org.jspecify.annotations.Nullable; - -/** - * Stream storage types. - */ -public enum StorageType { - File("file"), - Memory("memory"); - - private final String policy; - - StorageType(String p) { - policy = p; - } - - @Override - public String toString() { - return policy; - } - - @Nullable - public static StorageType get(String value) { - if (File.policy.equalsIgnoreCase(value)) { return File; } - if (Memory.policy.equalsIgnoreCase(value)) { return Memory; } - return null; - } -} diff --git a/src/test/java/io/nats/client/api/StreamAlternate.java b/src/test/java/io/nats/client/api/StreamAlternate.java deleted file mode 100644 index fc6a35d..0000000 --- a/src/test/java/io/nats/client/api/StreamAlternate.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import io.synadia.json.JsonValueUtils; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.util.List; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.readString; - -public class StreamAlternate { - private final String name; - private final String domain; - private final String cluster; - - static List optionalListOf(JsonValue vSourceInfos) { - return JsonValueUtils.listOfOrEmpty(vSourceInfos, StreamAlternate::new); - } - - StreamAlternate(JsonValue vLost) { - name = readString(vLost, NAME); - domain = readString(vLost, DOMAIN); - cluster = readString(vLost, CLUSTER); - } - - /** - * The mirror stream name - * @return the name - */ - @NonNull - public String getName() { - return name; - } - - /** - * The domain - * @return the domain - */ - @Nullable - public String getDomain() { - return domain; - } - - /** - * The name of the cluster holding the stream - * @return the cluster - */ - @NonNull - public String getCluster() { - return cluster; - } -} diff --git a/src/test/java/io/nats/client/api/StreamConfiguration.java b/src/test/java/io/nats/client/api/StreamConfiguration.java deleted file mode 100644 index 470a745..0000000 --- a/src/test/java/io/nats/client/api/StreamConfiguration.java +++ /dev/null @@ -1,819 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonParseException; -import io.synadia.json.JsonParser; -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; - -import java.time.Duration; -import java.util.*; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; -import static io.synadia.json.JsonWriteUtils.*; - -public class StreamConfiguration implements JsonSerializable { - - // see builder for defaults - private final String name; - private final String description; - private final List subjects; - private final RetentionPolicy retentionPolicy; - private final CompressionOption compressionOption; - private final long maxConsumers; - private final long maxMsgs; - private final long maxMsgsPerSubject; - private final long maxBytes; - private final Duration maxAge; - private final int maxMsgSize; - private final StorageType storageType; - private final int replicas; - private final boolean noAck; - private final String templateOwner; - private final DiscardPolicy discardPolicy; - private final Duration duplicateWindow; - private final Placement placement; - private final Republish republish; - private final SubjectTransform subjectTransform; - private final ConsumerLimits consumerLimits; - private final Mirror mirror; - private final List sources; - private final boolean sealed; - private final boolean allowRollup; - private final boolean allowDirect; - private final boolean mirrorDirect; - private final boolean denyDelete; - private final boolean denyPurge; - private final boolean discardNewPerSubject; - private final Map metadata; - private final long firstSequence; - private final boolean allowMessageTtl; - private final Duration subjectDeleteMarkerTtl; - - static StreamConfiguration instance(JsonValue v) { - return new Builder() - .retentionPolicy(RetentionPolicy.get(readString(v, RETENTION))) - .compressionOption(CompressionOption.get(readString(v, COMPRESSION))) - .storageType(StorageType.get(readString(v, STORAGE))) - .discardPolicy(DiscardPolicy.get(readString(v, DISCARD))) - .name(readString(v, NAME)) - .description(readString(v, DESCRIPTION)) - .maxConsumers(readLong(v, MAX_CONSUMERS, -1)) - .maxMessages(readLong(v, MAX_MSGS, -1)) - .maxMessagesPerSubject(readLong(v, MAX_MSGS_PER_SUB, -1)) - .maxBytes(readLong(v, MAX_BYTES, -1)) - .maxAge(readNanosAsDuration(v, MAX_AGE)) - .maximumMessageSize(readInteger(v, MAX_MSG_SIZE, -1)) - .replicas(readInteger(v, NUM_REPLICAS, 1)) - .noAck(readBoolean(v, NO_ACK, false)) - .templateOwner(readString(v, TEMPLATE_OWNER)) - .duplicateWindow(readNanosAsDuration(v, DUPLICATE_WINDOW)) - .subjects(readStringListOrEmpty(v, SUBJECTS)) - .placement(Placement.optionalInstance(readValue(v, PLACEMENT))) - .republish(Republish.optionalInstance(readValue(v, REPUBLISH))) - .subjectTransform(SubjectTransform.optionalInstance(readValue(v, SUBJECT_TRANSFORM))) - .consumerLimits(ConsumerLimits.optionalInstance(readValue(v, CONSUMER_LIMITS))) - .mirror(Mirror.optionalInstance(readValue(v, MIRROR))) - .sources(Source.optionalListOf(readValue(v, SOURCES))) - .sealed(readBoolean(v, SEALED, false)) - .allowRollup(readBoolean(v, ALLOW_ROLLUP_HDRS, false)) - .allowDirect(readBoolean(v, ALLOW_DIRECT, false)) - .mirrorDirect(readBoolean(v, MIRROR_DIRECT, false)) - .denyDelete(readBoolean(v, DENY_DELETE, false)) - .denyPurge(readBoolean(v, DENY_PURGE, false)) - .discardNewPerSubject(readBoolean(v, DISCARD_NEW_PER_SUBJECT, false)) - .metadata(readStringMapOrNull(v, METADATA)) - .firstSequence(readLong(v, FIRST_SEQ, 1)) - .allowMessageTtl(readBoolean(v, ALLOW_MSG_TTL, false)) - .subjectDeleteMarkerTtl(readNanosAsDuration(v, SUBJECT_DELETE_MARKER_TTL)) - .build(); - } - - // For the builder, assumes all validations are already done in builder - StreamConfiguration(Builder b) { - this.name = b.name; - this.description = b.description; - this.subjects = b.subjects; - this.retentionPolicy = b.retentionPolicy; - this.compressionOption = b.compressionOption; - this.maxConsumers = b.maxConsumers; - this.maxMsgs = b.maxMsgs; - this.maxMsgsPerSubject = b.maxMsgsPerSubject; - this.maxBytes = b.maxBytes; - this.maxAge = b.maxAge; - this.maxMsgSize = b.maxMsgSize; - this.storageType = b.storageType; - this.replicas = b.replicas; - this.noAck = b.noAck; - this.templateOwner = b.templateOwner; - this.discardPolicy = b.discardPolicy; - this.duplicateWindow = b.duplicateWindow; - this.placement = b.placement; - this.republish = b.republish; - this.subjectTransform = b.subjectTransform; - this.consumerLimits = b.consumerLimits; - this.mirror = b.mirror; - this.sources = b.sources; - this.sealed = b.sealed; - this.allowRollup = b.allowRollup; - this.allowDirect = b.allowDirect; - this.mirrorDirect = b.mirrorDirect; - this.denyDelete = b.denyDelete; - this.denyPurge = b.denyPurge; - this.discardNewPerSubject = b.discardNewPerSubject; - this.metadata = b.metadata; - this.firstSequence = b.firstSequence; - this.allowMessageTtl = b.allowMessageTtl; - this.subjectDeleteMarkerTtl = b.subjectDeleteMarkerTtl; - } - - /** - * Returns a StreamConfiguration deserialized from its JSON form. - * - * @see #toJson() - * @param json the json representing the Stream Configuration - * @return StreamConfiguration for the given json - * @throws JsonParseException thrown if the parsing fails for invalid json - */ - public static StreamConfiguration instance(String json) throws JsonParseException { - return instance(JsonParser.parse(json)); - } - - /** - * Returns a JSON representation of this consumer configuration. - * - * @return json consumer configuration to send to the server. - */ - @Override - @NonNull - public String toJson() { - - StringBuilder sb = beginJson(); - - addField(sb, NAME, name); - addField(sb, DESCRIPTION, description); - addStrings(sb, SUBJECTS, subjects); - addField(sb, RETENTION, retentionPolicy.toString()); - addEnumWhenNot(sb, COMPRESSION, compressionOption, CompressionOption.None); - addField(sb, MAX_CONSUMERS, maxConsumers); - addField(sb, MAX_MSGS, maxMsgs); - addField(sb, MAX_MSGS_PER_SUB, maxMsgsPerSubject); - addField(sb, MAX_BYTES, maxBytes); - addFieldAsNanos(sb, MAX_AGE, maxAge); - addField(sb, MAX_MSG_SIZE, maxMsgSize); - addField(sb, STORAGE, storageType.toString()); - addField(sb, NUM_REPLICAS, replicas); - addField(sb, NO_ACK, noAck); - addField(sb, TEMPLATE_OWNER, templateOwner); - addField(sb, DISCARD, discardPolicy.toString()); - addFieldAsNanos(sb, DUPLICATE_WINDOW, duplicateWindow); - if (placement != null && placement.hasData()) { - addField(sb, PLACEMENT, placement); - } - addField(sb, REPUBLISH, republish); - addField(sb, SUBJECT_TRANSFORM, subjectTransform); - addField(sb, CONSUMER_LIMITS, consumerLimits); - addField(sb, MIRROR, mirror); - addJsons(sb, SOURCES, sources); - addField(sb, SEALED, sealed); - addField(sb, ALLOW_ROLLUP_HDRS, allowRollup); - addField(sb, ALLOW_DIRECT, allowDirect); - addField(sb, MIRROR_DIRECT, mirrorDirect); - addField(sb, DENY_DELETE, denyDelete); - addField(sb, DENY_PURGE, denyPurge); - addField(sb, DISCARD_NEW_PER_SUBJECT, discardNewPerSubject); - addField(sb, METADATA, metadata); - addFieldWhenGreaterThan(sb, FIRST_SEQ, firstSequence, 1); - addField(sb, ALLOW_MSG_TTL, allowMessageTtl); - addFieldAsNanos(sb, SUBJECT_DELETE_MARKER_TTL, subjectDeleteMarkerTtl); - - return endJson(sb).toString(); - } - - /** - * Creates a builder for the stream configuration. - * @return a stream configuration builder - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a builder to copy the stream configuration. - * @param sc an existing StreamConfiguration - * @return a stream configuration builder - */ - public static Builder builder(StreamConfiguration sc) { - return new Builder(sc); - } - - /** - * StreamConfiguration is created using a Builder. The builder supports chaining and will - * create a default set of options if no methods are calls. - * - *

{@code new StreamConfiguration.Builder().build()} will create a new StreamConfiguration. - * - */ - @SuppressWarnings("UnusedReturnValue") - public static class Builder { - - private String name = null; - private String description = null; - private final List subjects = new ArrayList<>(); - private RetentionPolicy retentionPolicy = RetentionPolicy.Limits; - private CompressionOption compressionOption = CompressionOption.None; - private long maxConsumers = -1; - private long maxMsgs = -1; - private long maxMsgsPerSubject = -1; - private long maxBytes = -1; - private Duration maxAge = Duration.ZERO; - private int maxMsgSize = -1; - private StorageType storageType = StorageType.File; - private int replicas = 1; - private boolean noAck = false; - private String templateOwner = null; - private DiscardPolicy discardPolicy = DiscardPolicy.Old; - private Duration duplicateWindow = Duration.ZERO; - private Placement placement = null; - private Republish republish = null; - private SubjectTransform subjectTransform = null; - private ConsumerLimits consumerLimits = null; - private Mirror mirror = null; - private final List sources = new ArrayList<>(); - private boolean sealed = false; - private boolean allowRollup = false; - private boolean allowDirect = false; - private boolean mirrorDirect = false; - private boolean denyDelete = false; - private boolean denyPurge = false; - private boolean discardNewPerSubject = false; - private Map metadata; - private long firstSequence = 1; - private boolean allowMessageTtl = false; - private Duration subjectDeleteMarkerTtl; - - /** - * Default Builder - */ - public Builder() {} - - /** - * Update Builder, useful if you need to update a configuration - * @param sc the configuration to copy - */ - public Builder(StreamConfiguration sc) { - if (sc != null) { - this.name = sc.name; - this.description = sc.description; - subjects(sc.subjects); - this.retentionPolicy = sc.retentionPolicy; - this.compressionOption = sc.compressionOption; - this.maxConsumers = sc.maxConsumers; - this.maxMsgs = sc.maxMsgs; - this.maxMsgsPerSubject = sc.maxMsgsPerSubject; - this.maxBytes = sc.maxBytes; - this.maxAge = sc.maxAge; - this.maxMsgSize = sc.maxMsgSize; - this.storageType = sc.storageType; - this.replicas = sc.replicas; - this.noAck = sc.noAck; - this.templateOwner = sc.templateOwner; - this.discardPolicy = sc.discardPolicy; - this.duplicateWindow = sc.duplicateWindow; - this.placement = sc.placement; - this.republish = sc.republish; - this.subjectTransform = sc.subjectTransform; - this.consumerLimits = sc.consumerLimits; - this.mirror = sc.mirror; - sources(sc.sources); - this.sealed = sc.sealed; - this.allowRollup = sc.allowRollup; - this.allowDirect = sc.allowDirect; - this.mirrorDirect = sc.mirrorDirect; - this.denyDelete = sc.denyDelete; - this.denyPurge = sc.denyPurge; - this.discardNewPerSubject = sc.discardNewPerSubject; - if (sc.metadata != null) { - this.metadata = new HashMap<>(sc.metadata); - } - this.firstSequence = sc.firstSequence; - this.allowMessageTtl = sc.allowMessageTtl; - this.subjectDeleteMarkerTtl = sc.subjectDeleteMarkerTtl; - } - } - - /** - * Sets the name of the stream. - * @param name name of the stream. - * @return the builder - */ - public Builder name(String name) { - this.name = name; - return this; - } - - /** - * Sets the description - * @param description the description - * @return the builder - */ - public Builder description(String description) { - this.description = description; - return this; - } - - /** - * Sets the subjects in the StreamConfiguration. - * @param subjects the stream's subjects - * @return The Builder - */ - public Builder subjects(String... subjects) { - this.subjects.clear(); - return addSubjects(subjects); - } - - /** - * Sets the subjects in the StreamConfiguration. - * @param subjects the stream's subjects - * @return The Builder - */ - public Builder subjects(Collection subjects) { - this.subjects.clear(); - return addSubjects(subjects); - } - - /** - * Adds unique subjects into the StreamConfiguration. - * @param subjects the stream's subjects to add - * @return The Builder - */ - public Builder addSubjects(String... subjects) { - if (subjects != null) { - return addSubjects(Arrays.asList(subjects)); - } - return this; - } - - /** - * Adds unique subjects into the StreamConfiguration. - * @param subjects the stream's subjects to add - * @return The Builder - */ - public Builder addSubjects(Collection subjects) { - if (subjects != null) { - for (String sub : subjects) { - if (sub != null && !this.subjects.contains(sub)) { - this.subjects.add(sub); - } - } - } - return this; - } - - /** - * Sets the retention policy in the StreamConfiguration. - * @param policy the retention policy of the StreamConfiguration - * @return The Builder - */ - public Builder retentionPolicy(RetentionPolicy policy) { - this.retentionPolicy = policy == null ? RetentionPolicy.Limits : policy; - return this; - } - - /** - * Sets the compression option in the StreamConfiguration. - * @param compressionOption the compression option of the StreamConfiguration - * @return The Builder - */ - public Builder compressionOption(CompressionOption compressionOption) { - this.compressionOption = compressionOption == null ? CompressionOption.None : compressionOption; - return this; - } - - /** - * Sets the maximum number of consumers in the StreamConfiguration. - * @param maxConsumers the maximum number of consumers - * @return The Builder - */ - public Builder maxConsumers(long maxConsumers) { - this.maxConsumers = maxConsumers; - return this; - } - - /** - * Sets the maximum number of messages in the StreamConfiguration. - * @param maxMsgs the maximum number of messages - * @return The Builder - */ - public Builder maxMessages(long maxMsgs) { - this.maxMsgs = maxMsgs; - return this; - } - - /** - * Sets the maximum number of message per subject in the StreamConfiguration. - * @param maxMsgsPerSubject the maximum number of messages - * @return The Builder - */ - public Builder maxMessagesPerSubject(long maxMsgsPerSubject) { - this.maxMsgsPerSubject = maxMsgsPerSubject; - return this; - } - - /** - * Sets the maximum number of bytes in the StreamConfiguration. - * @param maxBytes the maximum number of bytes - * @return The Builder - */ - public Builder maxBytes(long maxBytes) { - this.maxBytes = maxBytes; - return this; - } - - /** - * Sets the maximum age in the StreamConfiguration. - * @param maxAge the maximum message age - * @return The Builder - */ - public Builder maxAge(Duration maxAge) { - this.maxAge = maxAge; - return this; - } - - /** - * Sets the maximum age in the StreamConfiguration. - * @param maxAgeMillis the maximum message age - * @return The Builder - */ - public Builder maxAge(long maxAgeMillis) { - this.maxAge = Duration.ofMillis(maxAgeMillis); - return this; - } - - /** - * Sets the maximum message size in the StreamConfiguration. - * @deprecated the server value is a 32-bit signed value. Use {@link #maximumMessageSize(int)} instead. - * @param maxMsgSize the maximum message size - * @return The Builder - */ - @Deprecated - public Builder maxMsgSize(long maxMsgSize) { - this.maxMsgSize = (int)maxMsgSize; - return this; - } - - /** - * Sets the maximum message size in the StreamConfiguration. - * @param maxMsgSize the maximum message size - * @return The Builder - */ - public Builder maximumMessageSize(int maxMsgSize) { - this.maxMsgSize = (int)maxMsgSize; - return this; - } - - /** - * Sets the storage type in the StreamConfiguration. - * @param storageType the storage type - * @return The Builder - */ - public Builder storageType(StorageType storageType) { - this.storageType = storageType == null ? StorageType.File : storageType; - return this; - } - - /** - * Sets the number of replicas a message must be stored on in the StreamConfiguration. - * Must be 1 to 5 inclusive - * @param replicas the number of replicas to store this message on - * @return The Builder - */ - public Builder replicas(int replicas) { - this.replicas = replicas; - return this; - } - - /** - * Sets the acknowledgement mode of the StreamConfiguration. if no acknowledgements are - * set, then acknowledgements are not sent back to the client. The default is false. - * @param noAck true to disable acknowledgements. - * @return The Builder - */ - public Builder noAck(boolean noAck) { - this.noAck = noAck; - return this; - } - - /** - * Sets the template a stream in the form of raw JSON. - * @param templateOwner the stream template of the stream. - * @return the builder - */ - public Builder templateOwner(String templateOwner) { - this.templateOwner = templateOwner == null || templateOwner.trim().isEmpty() ? null : templateOwner; - return this; - } - - /** - * Sets the discard policy in the StreamConfiguration. - * @param policy the discard policy of the StreamConfiguration - * @return The Builder - */ - public Builder discardPolicy(DiscardPolicy policy) { - this.discardPolicy = policy == null ? DiscardPolicy.Old : policy; - return this; - } - - /** - * Sets the duplicate checking window in the StreamConfiguration. A Duration.Zero - * disables duplicate checking. Duplicate checking is disabled by default. - * @param window duration to hold message ids for duplicate checking. - * @return The Builder - */ - public Builder duplicateWindow(Duration window) { - this.duplicateWindow = window; - return this; - } - - /** - * Sets the duplicate checking window in the StreamConfiguration. A Duration.Zero - * disables duplicate checking. Duplicate checking is disabled by default. - * @param windowMillis duration to hold message ids for duplicate checking. - * @return The Builder - */ - public Builder duplicateWindow(long windowMillis) { - this.duplicateWindow = Duration.ofMillis(windowMillis); - return this; - } - - /** - * Sets the placement directive object - * @param placement the placement directive object - * @return The Builder - */ - public Builder placement(Placement placement) { - this.placement = placement; - return this; - } - - /** - * Sets the republish config object - * @param republish the republish config object - * @return The Builder - */ - public Builder republish(Republish republish) { - this.republish = republish; - return this; - } - - /** - * Sets the subjectTransform config object - * @param subjectTransform the subjectTransform config object - * @return The Builder - */ - public Builder subjectTransform(SubjectTransform subjectTransform) { - this.subjectTransform = subjectTransform; - return this; - } - - /** - * Sets the consumerLimits config object - * @param consumerLimits the consumerLimits config object - * @return The Builder - */ - public Builder consumerLimits(ConsumerLimits consumerLimits) { - this.consumerLimits = consumerLimits; - return this; - } - - /** - * Sets the mirror object - * @param mirror the mirror object - * @return The Builder - */ - public Builder mirror(Mirror mirror) { - this.mirror = mirror; - return this; - } - - /** - * Sets the sources in the StreamConfiguration. - * @param sources the stream's sources - * @return The Builder - */ - public Builder sources(Source... sources) { - this.sources.clear(); - return addSources(sources); - } - - /** - * Add the sources into the StreamConfiguration. - * @param sources the stream's sources - * @return The Builder - */ - public Builder sources(Collection sources) { - this.sources.clear(); - return addSources(sources); - } - - /** - * Add the sources into the StreamConfiguration. - * @param sources the stream's sources - * @return The Builder - */ - public Builder addSources(Source... sources) { - return addSources(Arrays.asList(sources)); - } - - /** - * Sets the sources in the StreamConfiguration. - * @param sources the stream's sources - * @return The Builder - */ - public Builder addSources(Collection sources) { - if (sources != null) { - for (Source source : sources) { - if (source != null && !this.sources.contains(source)) { - this.sources.add(source); - } - } - } - return this; - } - - /** - * Add a source into the StreamConfiguration. - * @param source a stream source - * @return The Builder - */ - public Builder addSource(Source source) { - if (source != null && !this.sources.contains(source)) { - this.sources.add(source); - } - return this; - } - - /** - * Set whether to seal the stream. - * INTERNAL USE ONLY. Scoped protected for test purposes. - * @param sealed the sealed setting - * @return The Builder - */ - protected Builder sealed(boolean sealed) { - this.sealed = sealed; - return this; - } - - /** - * Set whether to allow the rollup feature for a stream - * @param allowRollup the allow rollup setting - * @return The Builder - */ - public Builder allowRollup(boolean allowRollup) { - this.allowRollup = allowRollup; - return this; - } - - /** - * Set whether to allow direct message access for a stream - * @param allowDirect the allow direct setting - * @return The Builder - */ - public Builder allowDirect(boolean allowDirect) { - this.allowDirect = allowDirect; - return this; - } - - /** - * Set whether to allow unified direct access for mirrors - * @param mirrorDirect the allow direct setting - * @return The Builder - */ - public Builder mirrorDirect(boolean mirrorDirect) { - this.mirrorDirect = mirrorDirect; - return this; - } - - /** - * Set whether to deny deleting messages from the stream - * @param denyDelete the deny delete setting - * @return The Builder - */ - public Builder denyDelete(boolean denyDelete) { - this.denyDelete = denyDelete; - return this; - } - - /** - * Set whether to deny purging messages from the stream - * @param denyPurge the deny purge setting - * @return The Builder - */ - public Builder denyPurge(boolean denyPurge) { - this.denyPurge = denyPurge; - return this; - } - - /** - * Set whether discard policy new with max message per subject applies to existing subjects, not just new subjects. - * @param discardNewPerSubject the setting - * @return The Builder - */ - public Builder discardNewPerSubject(boolean discardNewPerSubject) { - this.discardNewPerSubject = discardNewPerSubject; - return this; - } - - /** - * Set this stream to be sealed. This is irreversible. - * @return The Builder - */ - public Builder seal() { - this.sealed = true; - return this; - } - - /** - * Sets the metadata for the configuration - * @param metadata the metadata map - * @return The Builder - */ - public Builder metadata(Map metadata) { - this.metadata = metadata; - return this; - } - - /** - * Sets the first sequence to be used. 1 is the default. All values less than 2 are treated as 1. - * @param firstSeq specify the first_seq in the stream config when creating the stream. - * @return The Builder - */ - public Builder firstSequence(long firstSeq) { - this.firstSequence = firstSeq > 1 ? firstSeq : 1; - return this; - } - - /** - * Set to allow per message TTL to true - * @return The Builder - */ - public Builder allowMessageTtl() { - this.allowMessageTtl = true; - return this; - } - - /** - * Set allow per message TTL flag - * @param allowMessageTtl the flag - * @return The Builder - */ - public Builder allowMessageTtl(boolean allowMessageTtl) { - this.allowMessageTtl = allowMessageTtl; - return this; - } - - /** - * Set the subject delete marker TTL duration. Server accepts 1 second or more. - * null has the effect of clearing the subject delete marker TTL - * @param subjectDeleteMarkerTtl the TTL duration - * @return The Builder - */ - public Builder subjectDeleteMarkerTtl(Duration subjectDeleteMarkerTtl) { - this.subjectDeleteMarkerTtl = subjectDeleteMarkerTtl; - return this; - } - - /** - * Set the subject delete marker TTL duration in milliseconds. Server accepts 1 second or more. - * 0 or less has the effect of clearing the subject delete marker TTL - * @param subjectDeleteMarkerTtlMillis the TTL duration in milliseconds - * @return The Builder - */ - public Builder subjectDeleteMarkerTtl(long subjectDeleteMarkerTtlMillis) { - this.subjectDeleteMarkerTtl = Duration.ofMillis(subjectDeleteMarkerTtlMillis); - return this; - } - - /** - * Builds the StreamConfiguration - * @return a stream configuration. - */ - public StreamConfiguration build() { - return new StreamConfiguration(this); - } - } -} diff --git a/src/test/java/io/nats/client/api/StreamInfo.java b/src/test/java/io/nats/client/api/StreamInfo.java deleted file mode 100644 index 013cb0a..0000000 --- a/src/test/java/io/nats/client/api/StreamInfo.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.time.ZonedDateTime; -import java.util.List; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.readDate; -import static io.synadia.json.JsonValueUtils.readValue; - -/** - * The StreamInfo class contains information about a JetStream stream. - */ -public class StreamInfo extends ApiResponse { - - private final ZonedDateTime createTime; - private final StreamConfiguration config; - private final StreamState streamState; - private final ClusterInfo clusterInfo; - private final MirrorInfo mirrorInfo; - private final List sourceInfos; - private final List alternates; - private final ZonedDateTime timestamp; - - public StreamInfo(JsonValue vStreamInfo) { - super(vStreamInfo); - JsonValue jvConfig = readValue(jv, CONFIG); - config = StreamConfiguration.instance(jvConfig); - - createTime = readDate(jv, CREATED); - - streamState = new StreamState(readValue(jv, STATE)); - clusterInfo = ClusterInfo.optionalInstance(readValue(jv, CLUSTER)); - mirrorInfo = MirrorInfo.optionalInstance(readValue(jv, MIRROR)); - sourceInfos = SourceInfo.optionalListOf(readValue(jv, SOURCES)); - alternates = StreamAlternate.optionalListOf(readValue(jv, ALTERNATES)); - timestamp = readDate(jv, TIMESTAMP); - } - - /** - * Gets the stream configuration. Same as getConfig - * @return the stream configuration. - */ - @NonNull - public StreamConfiguration getConfiguration() { - return config; - } - - /** - * Gets the stream configuration. Same as getConfiguration - * @return the stream configuration. - */ - @NonNull - public StreamConfiguration getConfig() { - return config; - } - - /** - * Gets the stream state. - * @return the stream state - */ - @NonNull - public StreamState getStreamState() { - return streamState; - } - - /** - * Gets the creation time of the stream. - * @return the creation date and time. - */ - @NonNull - public ZonedDateTime getCreateTime() { - return createTime; - } - - @Nullable - public MirrorInfo getMirrorInfo() { - return mirrorInfo; - } - - @Nullable - public List getSourceInfos() { - return sourceInfos; - } - - @Nullable - public ClusterInfo getClusterInfo() { - return clusterInfo; - } - - @Nullable - public List getAlternates() { - return alternates; - } - - /** - * Gets the server time the info was gathered - * @return the server gathered timed - */ - @Nullable // doesn't exist in some versions of the server - public ZonedDateTime getTimestamp() { - return timestamp; - } - - @Override - public String toString() { - return "StreamInfo " + jv; - } -} diff --git a/src/test/java/io/nats/client/api/StreamState.java b/src/test/java/io/nats/client/api/StreamState.java deleted file mode 100644 index 8883819..0000000 --- a/src/test/java/io/nats/client/api/StreamState.java +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static io.nats.client.support.ApiConstants.*; -import static io.synadia.json.JsonValueUtils.*; - -public class StreamState { - private final long msgs; - private final long bytes; - private final long firstSeq; - private final long lastSeq; - private final long consumerCount; - private final long subjectCount; - private final long deletedCount; - private final ZonedDateTime firstTime; - private final ZonedDateTime lastTime; - private final List subjects; - private final List deletedStreamSequences; - private final LostStreamData lostStreamData; - private final Map subjectMap; - - StreamState(JsonValue vStreamState) { - msgs = readLong(vStreamState, MESSAGES, 0); - bytes = readLong(vStreamState, BYTES, 0); - firstSeq = readLong(vStreamState, FIRST_SEQ, 0); - lastSeq = readLong(vStreamState, LAST_SEQ, 0); - consumerCount = readLong(vStreamState, CONSUMER_COUNT, 0); - firstTime = readDate(vStreamState, FIRST_TS); - lastTime = readDate(vStreamState, LAST_TS); - subjectCount = readLong(vStreamState, NUM_SUBJECTS, 0); - deletedCount = readLong(vStreamState, NUM_DELETED, 0); - deletedStreamSequences = readLongListOrEmpty(vStreamState, DELETED); - lostStreamData = LostStreamData.optionalInstance(readValue(vStreamState, LOST)); - - subjects = new ArrayList<>(); - subjectMap = new HashMap<>(); - JsonValue vSubjects = readValue(vStreamState, SUBJECTS); - if (vSubjects != null && vSubjects.map != null) { - for (String subject : vSubjects.map.keySet()) { - Long count = getLong(vSubjects.map.get(subject)); - if (count != null) { - subjects.add(new Subject(subject, count)); - subjectMap.put(subject, count); - } - } - } - } - - /** - * Gets the message count of the stream. - * - * @return the message count - */ - public long getMsgCount() { - return msgs; - } - - /** - * Gets the byte count of the stream. - * - * @return the byte count - */ - public long getByteCount() { - return bytes; - } - - /** - * Gets the first sequence number of the stream. May be 0 if there are no messages. - * @return a sequence number - */ - public long getFirstSequence() { - return firstSeq; - } - - /** - * Gets the time stamp of the first message in the stream - * - * @return the first time - */ - @Nullable - public ZonedDateTime getFirstTime() { - return firstTime; - } - - /** - * Gets the last sequence of a message in the stream - * - * @return a sequence number - */ - public long getLastSequence() { - return lastSeq; - } - - /** - * Gets the time stamp of the last message in the stream - * - * @return the first time - */ - @Nullable - public ZonedDateTime getLastTime() { - return lastTime; - } - - /** - * Gets the number of consumers attached to the stream. - * - * @return the consumer count - */ - public long getConsumerCount() { - return consumerCount; - } - - /** - * Gets the count of subjects in the stream. - * - * @return the subject count - */ - public long getSubjectCount() { - return subjectCount; - } - - /** - * Get a list of the Subject objects. May be empty, for instance - * if the Stream Info request did not ask for subjects or if there are no subjects. - * @return the list of subjects - */ - @NonNull - public List getSubjects() { - return subjects; - } - - /** - * Get a map of subjects instead of a list of Subject objects. May be empty. - * @return the map - */ - @NonNull - public Map getSubjectMap() { - return subjectMap; - } - - /** - * Gets the count of deleted messages - * - * @return the deleted count - */ - public long getDeletedCount() { - return deletedCount; - } - - /** - * Get a list of the Deleted objects. May be empty if the Stream Info request did not ask for subjects - * or if there are no subjects. - * @return the list of subjects - */ - @NonNull - public List getDeleted() { - return deletedStreamSequences; - } - - /** - * Get the lost stream data information if available. - * @return the LostStreamData - */ - @Nullable - public LostStreamData getLostStreamData() { - return lostStreamData; - } - - @Override - public String toString() { - return "StreamState{" + - "msgs=" + msgs + - ", bytes=" + bytes + - ", firstSeq=" + firstSeq + - ", lastSeq=" + lastSeq + - ", consumerCount=" + consumerCount + - ", firstTime=" + firstTime + - ", lastTime=" + lastTime + - ", subjectCount=" + subjectCount + - ", subjects=" + subjects + - ", deletedCount=" + deletedCount + - ", deleteds=" + deletedStreamSequences + - ", lostStreamData=" + lostStreamData + - '}'; - } -} diff --git a/src/test/java/io/nats/client/api/Subject.java b/src/test/java/io/nats/client/api/Subject.java deleted file mode 100644 index 9c8c7ca..0000000 --- a/src/test/java/io/nats/client/api/Subject.java +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonValue; -import org.jspecify.annotations.NonNull; - -import java.util.ArrayList; -import java.util.List; - -import static io.synadia.json.JsonValueUtils.getLong; - -public class Subject implements Comparable { - private final String name; - private final long count; - - public static List listOf(JsonValue vSubjects) { - List list = new ArrayList<>(); - if (vSubjects != null && vSubjects.map != null) { - for (String subject : vSubjects.map.keySet()) { - Long count = getLong(vSubjects.map.get(subject)); - if (count != null) { - list.add(new Subject(subject, count)); - } - } - } - return list; - } - - public Subject(String name, long count) { - this.name = name; - this.count = count; - } - - /** - * Get the subject name - * @return the subject - */ - @NonNull - public String getName() { - return name; - } - - /** - * Get the subject message count - * @return the count - */ - public long getCount() { - return count; - } - - @Override - public String toString() { - return "Subject{" + - "name='" + name + '\'' + - ", count=" + count + - '}'; - } - - @Override - public int compareTo(Subject o) { - return name.compareTo(o.name); - } -} diff --git a/src/test/java/io/nats/client/api/SubjectTransform.java b/src/test/java/io/nats/client/api/SubjectTransform.java deleted file mode 100644 index dcb4eaa..0000000 --- a/src/test/java/io/nats/client/api/SubjectTransform.java +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.api; - -import io.synadia.json.JsonSerializable; -import io.synadia.json.JsonValue; -import io.synadia.json.JsonValueUtils; -import org.jspecify.annotations.NonNull; - -import java.util.List; - -import static io.nats.client.support.ApiConstants.DEST; -import static io.nats.client.support.ApiConstants.SRC; -import static io.synadia.json.JsonValueUtils.readString; -import static io.synadia.json.JsonWriteUtils.*; - -/** - * SubjectTransform - */ -public class SubjectTransform implements JsonSerializable { - private final String source; - private final String destination; - - static SubjectTransform optionalInstance(JsonValue vSubjectTransform) { - return vSubjectTransform == null ? null : new SubjectTransform(vSubjectTransform); - } - - static List optionalListOf(JsonValue vSubjectTransforms) { - return JsonValueUtils.listOfOrEmpty(vSubjectTransforms, SubjectTransform::new); - } - - public SubjectTransform(JsonValue vSubjectTransform) { - source = readString(vSubjectTransform, SRC); - destination = readString(vSubjectTransform, DEST); - } - - /** - * Get source, the subject matching filter - * @return the source - */ - @NonNull - public String getSource() { - return source; - } - - /** - * Get destination, the SubjectTransform Subject template - * @return the destination - */ - @NonNull - public String getDestination() { - return destination; - } - - @Override - @NonNull - public String toJson() { - StringBuilder sb = beginJson(); - addField(sb, SRC, source); - addField(sb, DEST, destination); - return endJson(sb).toString(); - } -} diff --git a/src/test/java/io/nats/client/support/ApiConstants.java b/src/test/java/io/nats/client/support/ApiConstants.java deleted file mode 100644 index 9df9d1d..0000000 --- a/src/test/java/io/nats/client/support/ApiConstants.java +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.support; - -public interface ApiConstants { - - String ACK_FLOOR = "ack_floor"; - String ACK_POLICY = "ack_policy"; - String ACK_WAIT = "ack_wait"; - String ACTION = "action"; - String ACTIVE = "active"; - String ALLOW_DIRECT = "allow_direct"; - String ALLOW_MSG_TTL = "allow_msg_ttl"; - String ALLOW_ROLLUP_HDRS = "allow_rollup_hdrs"; - String ALTERNATES = "alternates"; - String API = "api"; - String API_URL = "api_url"; - String AUTH_REQUIRED = "auth_required"; - String AVERAGE_PROCESSING_TIME = "average_processing_time"; - String BACKOFF = "backoff"; - String BATCH = "batch"; - String BUCKET = "bucket"; - String BYTES = "bytes"; - String CHUNKS = "chunks"; - String CLIENT_ID = "client_id"; - String CLIENT_IP = "client_ip"; - String CLUSTER = "cluster"; - String CODE = "code"; - String COMPRESSION = "compression"; - String CONFIG = "config"; - String CONNECT_URLS = "connect_urls"; - String CONSUMER_COUNT = "consumer_count"; - String CONSUMER_SEQ = "consumer_seq"; - String CONSUMER_LIMITS = "consumer_limits"; - String CONSUMERS = "consumers"; - String CREATED = "created"; - String CURRENT = "current"; - String DATA = "data"; - String DELETED = "deleted"; - String DELETED_DETAILS = "deleted_details"; - String DELIVER = "deliver"; - String DELIVER_GROUP = "deliver_group"; - String DELIVER_POLICY = "deliver_policy"; - String DELIVER_SUBJECT = "deliver_subject"; - String DELIVERED = "delivered"; - String DENY_DELETE = "deny_delete"; - String DENY_PURGE = "deny_purge"; - String DESCRIPTION = "description"; - String DEST = "dest"; - String DIGEST = "digest"; - String DISCARD = "discard"; - String DISCARD_NEW_PER_SUBJECT = "discard_new_per_subject"; - String DOMAIN = "domain"; - String DUPLICATE = "duplicate"; - String DUPLICATE_WINDOW = "duplicate_window"; - String ENDPOINTS = "endpoints"; - String DURABLE_NAME = "durable_name"; - String ERR_CODE = "err_code"; - String ERROR = "error"; - String ERRORS = "errors"; - String EXPIRES = "expires"; - String EXPIRES_IN = "expires_in"; - String EXTERNAL = "external"; - String FILTER = "filter"; - String FILTER_SUBJECT = "filter_subject"; - String FILTER_SUBJECTS = "filter_subjects"; - String FIRST_SEQ = "first_seq"; - String FIRST_TS = "first_ts"; - String FLOW_CONTROL = "flow_control"; - String GO = "go"; - String GROUP = "group"; - String HDRS = "hdrs"; - String HEADERS = "headers"; - String HEADERS_ONLY = "headers_only"; - String HOST = "host"; - String ID = "id"; - String IDLE_HEARTBEAT = "idle_heartbeat"; - String INACTIVE_THRESHOLD= "inactive_threshold"; - String INFLIGHT = "inflight"; - String INTERNAL = "internal"; - String JETSTREAM = "jetstream"; - String KEEP = "keep"; - String LAG = "lag"; - String LAME_DUCK_MODE = "ldm"; - String LAST_ACTIVE = "last_active"; - String LAST_BY_SUBJECT = "last_by_subj"; - String LAST_ERROR = "last_error"; - String LAST_SEQ = "last_seq"; - String LAST_TS = "last_ts"; - String LEADER = "leader"; - String LEVEL = "level"; - String LIMIT = "limit"; - String LIMITS = "limits"; - String LINK = "link"; - String LOST = "lost"; - String MAX_ACK_PENDING = "max_ack_pending"; - String MAX_AGE = "max_age"; - String MAX_BATCH = "max_batch"; - String MAX_BYTES = "max_bytes"; - String MAX_BYTES_REQUIRED= "max_bytes_required"; - String MAX_CONSUMERS = "max_consumers"; - String MAX_CHUNK_SIZE = "max_chunk_size"; - String MAX_DELIVER = "max_deliver"; - String MAX_EXPIRES = "max_expires"; - String MAX_MEMORY = "max_memory"; - String MAX_MSG_SIZE = "max_msg_size"; - String MAX_MSGS = "max_msgs"; - String MAX_MSGS_PER_SUB = "max_msgs_per_subject"; - String MAX_PAYLOAD = "max_payload"; - String MAX_STORAGE = "max_storage"; - String MAX_STREAMS = "max_streams"; - String MAX_WAITING = "max_waiting"; // this is correct! the meaning name is different than the field name - String MIN_PENDING = "min_pending"; - String MIN_ACK_PENDING = "min_ack_pending"; - String MEM_STORAGE = "mem_storage"; - String MEMORY = "memory"; - String MEMORY_MAX_STREAM_BYTES = "memory_max_stream_bytes"; - String MESSAGE = "message"; - String MESSAGES = "messages"; - String METADATA = "metadata"; - String MTIME = "mtime"; - String MIRROR = "mirror"; - String MIRROR_DIRECT = "mirror_direct"; - String MSGS = "msgs"; - String MULTI_LAST = "multi_last"; - String NAME = "name"; - String NEXT_BY_SUBJECT = "next_by_subj"; - String NO_ACK = "no_ack"; - String NO_ERASE = "no_erase"; - String NO_WAIT = "no_wait"; - String NONCE = "nonce"; - String NUID = "nuid"; - String NUM_ACK_PENDING = "num_ack_pending"; - String NUM_DELETED = "num_deleted"; - String NUM_ERRORS = "num_errors"; - String NUM_PENDING = "num_pending"; - String NUM_REDELIVERED = "num_redelivered"; - String NUM_REPLICAS = "num_replicas"; - String NUM_REQUESTS = "num_requests"; - String NUM_SUBJECTS = "num_subjects"; - String NUM_WAITING = "num_waiting"; - String OFFLINE = "offline"; - String OFFSET = "offset"; - String OPT_START_SEQ = "opt_start_seq"; - String OPT_START_TIME = "opt_start_time"; - String OPTIONS = "options"; - String PAUSED = "paused"; - String PAUSE_REMAINING = "pause_remaining"; - String PAUSE_UNTIL = "pause_until"; - String PLACEMENT = "placement"; - String PORT = "port"; - String PRIORITY_GROUPS = "priority_groups"; - String PRIORITY_POLICY = "priority_policy"; - String PROCESSING_TIME = "processing_time"; - String PROTO = "proto"; - String PURGED = "purged"; - String PUSH_BOUND = "push_bound"; - String QUEUE_GROUP = "queue_group"; - String RAISE_STATUS_WARNINGS = "raise_status_warnings"; - String RATE_LIMIT_BPS = "rate_limit_bps"; - String REPLAY_POLICY = "replay_policy"; - String REPLICA = "replica"; - String REPLICAS = "replicas"; - String REPUBLISH = "republish"; - String REQUEST = "request"; - String RESERVED_MEMORY = "reserved_memory"; - String RESERVED_STORAGE = "reserved_storage"; - String RESPONSE = "response"; - String RETENTION = "retention"; - String SAMPLE_FREQ = "sample_freq"; - String SCHEMA = "schema"; - String SEALED = "sealed"; - String SEQ = "seq"; - String SERVER_ID = "server_id"; - String SERVER_NAME = "server_name"; - String SIZE = "size"; - String SOURCE = "source"; - String SOURCES = "sources"; - String SRC = "src"; - String STARTED = "started"; - String START_TIME = "start_time"; - String STATE = "state"; - String STATS = "stats"; - String STORAGE = "storage"; - String STORAGE_MAX_STREAM_BYTES = "storage_max_stream_bytes"; - String STREAM_NAME = "stream_name"; - String STREAM_SEQ = "stream_seq"; - String STREAM = "stream"; - String STREAMS = "streams"; - String SUBJECT = "subject"; - String SUBJECT_DELETE_MARKER_TTL = "subject_delete_marker_ttl"; - String SUBJECT_TRANSFORM = "subject_transform"; - String SUBJECT_TRANSFORMS = "subject_transforms"; - String SUBJECTS = "subjects"; - String SUBJECTS_FILTER = "subjects_filter"; - String SUCCESS = "success"; - String TAGS = "tags"; - String TEMPLATE_OWNER = "template_owner"; - String THRESHOLD_PERCENT = "threshold_percent"; - String TIERS = "tiers"; - String TIME = "time"; - String TIMESTAMP = "ts"; - String TLS = "tls_required"; - String TLS_REQUIRED = TLS; - String TLS_AVAILABLE = "tls_available"; - String TOTAL = "total"; - String TYPE = "type"; - String UP_TO_SEQ = "up_to_seq"; - String UP_TO_TIME = "up_to_time"; - String VERSION = "version"; -} diff --git a/src/test/java/io/nats/client/support/DateTimeUtils.java b/src/test/java/io/nats/client/support/DateTimeUtils.java deleted file mode 100644 index 08c3fc8..0000000 --- a/src/test/java/io/nats/client/support/DateTimeUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.nats.client.support; - -import java.time.*; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -/** - * Internal json parsing helpers. - */ -public abstract class DateTimeUtils { - private DateTimeUtils() {} /* ensures cannot be constructed */ - - public static final ZoneId ZONE_ID_GMT = ZoneId.of("GMT"); - public static final ZonedDateTime DEFAULT_TIME = ZonedDateTime.of(1, 1, 1, 0, 0, 0, 0, ZONE_ID_GMT); - public static final DateTimeFormatter RFC3339_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nnnnnnnnn'Z'"); - private static final long NANO_FACTOR = 1_000_000_000; - - public static ZonedDateTime toGmt(ZonedDateTime zonedDateTime) { - return zonedDateTime.withZoneSameInstant(ZONE_ID_GMT); - } - - public static ZonedDateTime gmtNow() { - return ZonedDateTime.now().withZoneSameInstant(ZONE_ID_GMT); - } - - public static boolean equals(ZonedDateTime zdt1, ZonedDateTime zdt2) { - if (zdt1 == zdt2) return true; - if (zdt1 == null || zdt2 == null) return false; - return zdt1.withZoneSameInstant(ZONE_ID_GMT).equals(zdt2.withZoneSameInstant(ZONE_ID_GMT)); - } - - public static String toRfc3339(ZonedDateTime zonedDateTime) { - return RFC3339_FORMATTER.format(toGmt(zonedDateTime)); - } - - /** - * Parses a date time from the server. - * @param dateTime - date time from the server. - * @return a Zoned Date time. - */ - public static ZonedDateTime parseDateTime(String dateTime) { - return parseDateTime(dateTime, DEFAULT_TIME); - } - - public static ZonedDateTime parseDateTime(String dateTime, ZonedDateTime dflt) { - try { - return toGmt(ZonedDateTime.parse(dateTime)); - } - catch (DateTimeParseException s) { - return dflt; - } - } - - public static ZonedDateTime parseDateTimeThrowParseError(String dateTime) { - return toGmt(ZonedDateTime.parse(dateTime)); - } - - /** - * Parses a long timestamp with nano precission in epoch UTC to the system - * default time-zone date time - * - * @param timestampNanos String timestamp - * @return a local Zoned Date time. - */ - public static ZonedDateTime parseDateTimeNanos(String timestampNanos) { - return parseDateTimeNanos(timestampNanos, ZoneId.systemDefault()); - } - - /** - * Parses a long timestamp with nano precission in epoch UTC to a Zoned date - * time - * - * @param timestampNanos String timestamp - * @param zoneId ZoneId - * @return a Zoned Date time. - */ - public static ZonedDateTime parseDateTimeNanos(String timestampNanos, ZoneId zoneId) { - long ts = Long.parseLong(timestampNanos); - long seconds = ts / NANO_FACTOR; - long nanos = ts % NANO_FACTOR; - Instant utcInstant = Instant.ofEpochSecond(seconds, nanos); - OffsetDateTime utcOffsetDT = OffsetDateTime.ofInstant(utcInstant, ZoneOffset.UTC); - return utcOffsetDT.atZoneSameInstant(zoneId); - } - - public static ZonedDateTime fromNow(long millis) { - return ZonedDateTime.ofInstant(Instant.now().plusMillis(millis), ZONE_ID_GMT); - } - - public static ZonedDateTime fromNow(Duration dur) { - return ZonedDateTime.ofInstant(Instant.now().plusMillis(dur.toMillis()), ZONE_ID_GMT); - } -} diff --git a/src/test/java/io/synadia/json/Benchmark.java b/src/test/java/io/synadia/json/Benchmark.java deleted file mode 100644 index 2b9e2b1..0000000 --- a/src/test/java/io/synadia/json/Benchmark.java +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.synadia.json; - -import io.nats.client.api.ConsumerConfiguration; -import io.nats.client.api.StreamConfiguration; -import io.nats.client.api.StreamInfo; - -import java.text.NumberFormat; -import java.util.Locale; - -import static io.ResourceUtils.resourceAsBytes; - -public final class Benchmark { - static final String RESULTS_HEADER = " | Elapsed ms | Rounds | Rounds/Time | Time/Round |\n"; - static final String RESULTS_SEP = "-----------------------|-----------------|--------------|----------------|-------------------|\n"; - static final String RESULTS = "%-22s | %15s | %12s | %14s | %17s |\n"; - - static byte[] JSON_SI = resourceAsBytes("stream-info.json"); - static byte[] JSON_CC = resourceAsBytes("consumer-configuration.json"); - static JsonValue JV_SI = JsonParser.parseUnchecked(JSON_SI); - static JsonValue JV_CC = JsonParser.parseUnchecked(JSON_CC); - static StreamInfo SI = new StreamInfo(JV_SI); - static StreamConfiguration SC = SI.getConfiguration(); - static ConsumerConfiguration CC = ConsumerConfiguration.builder().jsonValue(JV_CC).build(); - - static long ROUNDS = 10_000_000; - static long REPORT_FREQUENCY = ROUNDS / 100; - static long NUM_DIFF_BENCHES = 7; - - public static void main(String[] args) { - long totalElapsed = 0; - long benchParseSiElapsed = 0; - long benchParseCcElapsed = 0; - long benchCreateSiElapsed = 0; - long benchCreateCcElapsed = 0; - long benchToJsonScElapsed = 0; - long benchToJsonCcElapsed = 0; - long benchUnitCoverage = 0; - for (int r = 1; r <= ROUNDS; r++) { - benchParseSiElapsed += benchParseSi(); - benchParseCcElapsed += benchParseCc(); - benchCreateSiElapsed += benchCreateSi(); - benchCreateCcElapsed += benchCreateCc(); - benchToJsonScElapsed += benchToJsonSc(); - benchToJsonCcElapsed += benchToJsonCc(); - benchUnitCoverage += BenchmarkUnitCoverage.unitCoverage(); - totalElapsed = benchParseSiElapsed + benchParseCcElapsed + benchCreateSiElapsed + benchCreateCcElapsed + benchToJsonScElapsed + benchToJsonCcElapsed + benchUnitCoverage; - if (r % REPORT_FREQUENCY == 0) { - printResults(r, - benchParseSiElapsed, benchParseCcElapsed, - benchCreateSiElapsed, benchCreateCcElapsed, - benchToJsonScElapsed, benchToJsonCcElapsed, - benchUnitCoverage, - totalElapsed); - } - } - - System.out.println("\n"); - printResults(ROUNDS, - benchParseSiElapsed, benchParseCcElapsed, - benchCreateSiElapsed, benchCreateCcElapsed, - benchToJsonScElapsed, benchToJsonCcElapsed, - benchUnitCoverage, - totalElapsed); - } - - private static void printResults(long rounds, long benchParseSiElapsed, long benchParseCcElapsed, long benchCreateSiElapsed, long benchCreateCcElapsed, long benchToJsonScElapsed, long benchToJsonCcElapsed, long benchUnitCoverage, long totalElapsed) { - System.out.println(); - System.out.printf(RESULTS_HEADER + RESULTS_SEP); - printResults("Parse Stream Info", benchParseSiElapsed, rounds); - printResults("Parse Consumer Config", benchParseCcElapsed, rounds); - printResults("Create Stream Info", benchCreateSiElapsed, rounds); - printResults("Create Consumer Config", benchCreateCcElapsed, rounds); - printResults("ToJson Stream Config", benchToJsonScElapsed, rounds); - printResults("ToJson Consumer Config", benchToJsonCcElapsed, rounds); - printResults("Unit Tests", benchUnitCoverage, rounds); - System.out.printf(RESULTS_SEP); - printResults("Total/Average", totalElapsed, rounds * NUM_DIFF_BENCHES); - } - - // ---------------------------------------------------------------------------------------------------- - // BENCHMARKS - // ---------------------------------------------------------------------------------------------------- - public static long benchParseSi() { - long start = System.nanoTime(); - JsonParser.parseUnchecked(JSON_SI); - return System.nanoTime() - start; - } - - public static long benchParseCc() { - long start = System.nanoTime(); - JsonParser.parseUnchecked(JSON_CC); - return System.nanoTime() - start; - } - - public static long benchCreateSi() { - long start = System.nanoTime(); - new StreamInfo(JV_SI); - return System.nanoTime() - start; - } - - public static long benchCreateCc() { - long start = System.nanoTime(); - ConsumerConfiguration.builder().jsonValue(JV_CC); - return System.nanoTime() - start; - } - - public static long benchToJsonSc() { - long start = System.nanoTime(); - SC.toJson(); - return System.nanoTime() - start; - } - - public static long benchToJsonCc() { - long start = System.nanoTime(); - CC.toJson(); - return System.nanoTime() - start; - } - - // ---------------------------------------------------------------------------------------------------- - // RESULT HELPERS - // ---------------------------------------------------------------------------------------------------- - private static void printResults(String label, Long elapsedNs, long rounds) { - float fElapsedNs = elapsedNs.floatValue(); - float elapsedMs = fElapsedNs / 1_000_000F; - String perTime = getOpsPerTime(fElapsedNs, elapsedMs, rounds); - String timePer = getTimePerOps(fElapsedNs, elapsedMs, rounds); - System.out.printf(RESULTS, label, format3(elapsedMs), format(rounds), perTime, timePer); - } - - private static String getOpsPerTime(float elapsedNs, float elapsedMs, long rounds) { - float nsPer = rounds / elapsedNs; - float msPer = rounds / elapsedMs; - return nsPer < 1F ? format3(msPer) + " r/ms" : format(nsPer) + " r/ns"; - } - - private static String getTimePerOps(float elapsedNs, float elapsedMs, long rounds) { - float nsPer = elapsedNs/ rounds; - float msPer = elapsedMs / rounds; - return nsPer < 1F ? format3(msPer) + " ms/r" : format(nsPer) + " ns/r"; - } - - public static String format(Number s) { - return NumberFormat.getNumberInstance(Locale.getDefault()).format(s); - } - - public static String format3(Number n) { - if (n.longValue() >= 1_000_000_000) { - return humanBytes(n.doubleValue()); - } - String f = format(n); - int at = f.indexOf('.'); - if (at == -1) { - return f; - } - if (at == 0) { - return f + "." + ZEROS.substring(0, 3); - } - return (f + ZEROS).substring(0, at + 3 + 1); - } - - public static String humanBytes(double bytes) { - if (bytes < HUMAN_BYTES_BASE) { - return String.format("%.2f b", bytes); - } - int exp = (int) (Math.log(bytes) / Math.log(HUMAN_BYTES_BASE)); - try { - return String.format("%.2f %s", bytes / Math.pow(HUMAN_BYTES_BASE, exp), HUMAN_BYTES_UNITS[exp]); - } - catch (Exception e) { - return String.format("%.2f b", bytes); - } - } - - private static final String ZEROS = "000000000"; - private static final long HUMAN_BYTES_BASE = 1024; - private static final String[] HUMAN_BYTES_UNITS = new String[] {"b", "kb", "mb", "gb", "tb", "pb", "eb"}; -} diff --git a/src/test/java/io/synadia/json/BenchmarkUnitCoverage.java b/src/test/java/io/synadia/json/BenchmarkUnitCoverage.java deleted file mode 100644 index c3069bf..0000000 --- a/src/test/java/io/synadia/json/BenchmarkUnitCoverage.java +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2025 Synadia Communications, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.synadia.json; - -import io.ResourceUtils; - -import java.nio.charset.StandardCharsets; -import java.time.Duration; - -import static io.synadia.json.JsonValue.*; -import static io.synadia.json.JsonValueUtils.*; - -@SuppressWarnings({"ResultOfMethodCallIgnored", "DataFlowIssue"}) -public final class BenchmarkUnitCoverage { - private static final String TEST_JSON = ResourceUtils.resourceAsString("test.json"); - private static final JsonValue TEST_JV = JsonParser.parseUnchecked(TEST_JSON); - private static final Duration DEFAULT_DURATION = Duration.ofSeconds(99); - - private static final String STRING = "string"; - private static final String INTEGER = "integer"; - private static final String LONG = "long"; - private static final String BIG_DECIMAL = "big_decimal"; - private static final String BOOL = "bool"; - private static final String DATE = "date"; - private static final String NANOS = "nanos"; - private static final String BASE_64_BASIC = "base_64_basic"; - private static final String BASE_64_URL = "base_64_url"; - private static final String MAP = "map"; - private static final String ARRAY = "array"; - private static final String MMAP = "mmap"; - private static final String SMAP = "smap"; - private static final String SLIST = "slist"; - private static final String MLIST = "mlist"; - private static final String ILIST = "ilist"; - private static final String LLIST = "llist"; - private static final String NLIST = "nlist"; - private static final String NOT_A_KEY = "not-a-key"; - - public static long unitCoverage() { - long start = System.nanoTime(); - - // testRead - read(TEST_JV, STRING, null, v -> v); - read(null, NOT_A_KEY, null, v -> v); - read(EMPTY_ARRAY, NOT_A_KEY, null, v -> v); - read(TRUE, NOT_A_KEY, null, v -> v); - read(FALSE, NOT_A_KEY, null, v -> v); - read(NULL, NOT_A_KEY, null, v -> v); - - // testReadStrings - readString(TEST_JV, STRING); - readBytes(TEST_JV, STRING); - readBytes(TEST_JV, STRING, StandardCharsets.UTF_8); - readString(TEST_JV, DATE); - readString(TEST_JV, BASE_64_BASIC); - readString(TEST_JV, BASE_64_URL); - readDate(TEST_JV, DATE); - readBase64Basic(TEST_JV, BASE_64_BASIC); - readBase64Url(TEST_JV, BASE_64_URL); - readBase64Basic(TEST_JV, INTEGER); - readBase64Url(TEST_JV, INTEGER); - readString(TEST_JV, INTEGER); - readString(TEST_JV, LONG); - readString(TEST_JV, BOOL); - readString(TEST_JV, MAP); - readString(TEST_JV, ARRAY); - readString(TEST_JV, NOT_A_KEY); - readString(TEST_JV, INTEGER, STRING); - readString(TEST_JV, LONG, STRING); - readString(TEST_JV, BOOL, STRING); - readString(TEST_JV, MAP, STRING); - readString(TEST_JV, ARRAY, STRING); - readString(TEST_JV, NOT_A_KEY, STRING); - readString(TEST_JV, NOT_A_KEY); - readString(TEST_JV, INTEGER); - readString(TEST_JV, STRING, STRING); - readString(TEST_JV, NOT_A_KEY, STRING); - readString(TEST_JV, INTEGER, STRING); - readString(null, NOT_A_KEY, STRING); - - // testReadInteger - readInteger(TEST_JV, INTEGER); - readInteger(TEST_JV, STRING); - readInteger(TEST_JV, BOOL); - readInteger(TEST_JV, MAP); - readInteger(TEST_JV, ARRAY); - readInteger(TEST_JV, NOT_A_KEY); - - readInteger(TEST_JV, STRING, 99); - readInteger(TEST_JV, BOOL, 99); - readInteger(TEST_JV, MAP, 99); - readInteger(TEST_JV, ARRAY, 99); - readInteger(TEST_JV, NOT_A_KEY, 99); - - readInteger(TEST_JV, INTEGER, 99); - readInteger(TEST_JV, STRING, 99); - readInteger(TEST_JV, BOOL, 99); - readInteger(TEST_JV, MAP, 99); - readInteger(TEST_JV, ARRAY, 99); - readInteger(TEST_JV, NOT_A_KEY, 99); - - // testReadLong - readLong(TEST_JV, INTEGER); - readLong(TEST_JV, LONG); - readLong(TEST_JV, STRING); - readLong(TEST_JV, BOOL); - readLong(TEST_JV, MAP); - readLong(TEST_JV, ARRAY); - readLong(TEST_JV, NOT_A_KEY); - readLong(TEST_JV, STRING, 99); - readLong(TEST_JV, BOOL, 99); - readLong(TEST_JV, MAP, 99); - readLong(TEST_JV, ARRAY, 99); - readLong(TEST_JV, NOT_A_KEY, 99); - readLong(TEST_JV, INTEGER, 99); - readLong(TEST_JV, LONG, 99); - readLong(TEST_JV, STRING, 99); - readLong(TEST_JV, BOOL, 99); - readLong(TEST_JV, MAP, 99); - readLong(TEST_JV, ARRAY, 99); - readLong(TEST_JV, NOT_A_KEY, 99); - - // testReadBoolean - readBoolean(TEST_JV, BOOL); - readBoolean(TEST_JV, STRING); - readBoolean(TEST_JV, INTEGER); - readBoolean(TEST_JV, LONG); - readBoolean(TEST_JV, MAP); - readBoolean(TEST_JV, ARRAY); - readBoolean(TEST_JV, NOT_A_KEY); - readBoolean(TEST_JV, BOOL, true); - readBoolean(TEST_JV, STRING, true); - readBoolean(TEST_JV, INTEGER, true); - readBoolean(TEST_JV, LONG, true); - readBoolean(TEST_JV, MAP, true); - readBoolean(TEST_JV, ARRAY, true); - readBoolean(TEST_JV, NOT_A_KEY, true); - readBoolean(TEST_JV, STRING, false); - readBoolean(TEST_JV, INTEGER, false); - readBoolean(TEST_JV, LONG, false); - readBoolean(TEST_JV, MAP, false); - readBoolean(TEST_JV, ARRAY, false); - readBoolean(TEST_JV, NOT_A_KEY, false); - - // testReadDate - readDate(TEST_JV, DATE); - readDate(TEST_JV, BOOL); - readDate(TEST_JV, MAP); - readDate(TEST_JV, ARRAY); - readDate(TEST_JV, NOT_A_KEY); - - // testReadNanosAsDuration - readNanosAsDuration(TEST_JV, NANOS); - readNanosAsDuration(TEST_JV, STRING); - readNanosAsDuration(TEST_JV, BOOL); - readNanosAsDuration(TEST_JV, MAP); - readNanosAsDuration(TEST_JV, ARRAY); - readNanosAsDuration(TEST_JV, NOT_A_KEY); - readNanosAsDuration(TEST_JV, NANOS, DEFAULT_DURATION); - readNanosAsDuration(TEST_JV, STRING, DEFAULT_DURATION); - readNanosAsDuration(TEST_JV, BOOL, DEFAULT_DURATION); - readNanosAsDuration(TEST_JV, MAP, DEFAULT_DURATION); - readNanosAsDuration(TEST_JV, ARRAY, DEFAULT_DURATION); - readNanosAsDuration(TEST_JV, NOT_A_KEY, DEFAULT_DURATION); - - // testObjectAndMaps - readMapObjectOrNull(TEST_JV, SMAP); - readMapMapOrNull(TEST_JV, SMAP); - readMapMapOrEmpty(TEST_JV, SMAP); - readMapObjectOrNull(TEST_JV, MMAP); - readMapObjectOrEmpty(TEST_JV, MMAP); - readMapMapOrNull(TEST_JV, MMAP); - readMapMapOrEmpty(TEST_JV, MMAP); - readStringMapOrNull(TEST_JV, MMAP); - readStringMapOrEmpty(TEST_JV, MMAP); - - // testArrays - listOfOrNull(null, jv -> jv); - listOfOrNull(readValue(TEST_JV, STRING), jv -> jv); - listOfOrNull(readValue(TEST_JV, SLIST), jv -> jv); - listOfOrEmpty(null, jv -> jv); - listOfOrEmpty(readValue(TEST_JV, STRING), jv -> jv); - listOfOrEmpty(readValue(TEST_JV, SLIST), jv -> jv); - readArrayOrNull(TEST_JV, STRING); - readArrayOrEmpty(TEST_JV, STRING); - readArrayOrNull(TEST_JV, SLIST); - readArrayOrEmpty(TEST_JV, SLIST); - readArrayOrNull(TEST_JV, MLIST); - readArrayOrEmpty(TEST_JV, MLIST); - readStringListOrNull(TEST_JV, STRING); - readStringListOrEmpty(TEST_JV, STRING); - readStringListOrNull(TEST_JV, SLIST); - readStringListOrEmpty(TEST_JV, SLIST); - readStringListOrNull(TEST_JV, MLIST); - readStringListOrEmpty(TEST_JV, MLIST); - readIntegerListOrNull(TEST_JV, STRING); - readIntegerListOrEmpty(TEST_JV, STRING); - readIntegerListOrNull(TEST_JV, SLIST); - readIntegerListOrEmpty(TEST_JV, SLIST); - readIntegerListOrNull(TEST_JV, LLIST); - readIntegerListOrEmpty(TEST_JV, LLIST); - readIntegerListOrNull(TEST_JV, MLIST); - readIntegerListOrEmpty(TEST_JV, MLIST); - readIntegerListOrNull(TEST_JV, ILIST); - readIntegerListOrEmpty(TEST_JV, ILIST); - readLongListOrNull(TEST_JV, STRING); - readLongListOrEmpty(TEST_JV, STRING); - readLongListOrNull(TEST_JV, SLIST); - readLongListOrEmpty(TEST_JV, SLIST); - readLongListOrNull(TEST_JV, MLIST); - readLongListOrEmpty(TEST_JV, MLIST); - readLongListOrNull(TEST_JV, ILIST); - readLongListOrEmpty(TEST_JV, ILIST); - readLongListOrNull(TEST_JV, LLIST); - readLongListOrEmpty(TEST_JV, LLIST); - readNanosAsDurationListOrNull(TEST_JV, STRING); - readNanosAsDurationListOrEmpty(TEST_JV, STRING); - readNanosAsDurationListOrNull(TEST_JV, NLIST); - readNanosAsDurationListOrEmpty(TEST_JV, NLIST); - - // testNotFoundOrWrongType() { - validateNotFoundOrWrongType(STRING, false, true, true, true, true, true, true); - validateNotFoundOrWrongType(INTEGER, true, true, false, false, true, true, true); - validateNotFoundOrWrongType(LONG, true, true, true, false, true, true, true); - validateNotFoundOrWrongType(BOOL, true, true, true, true, false, true, true); - validateNotFoundOrWrongType(DATE, false, false, true, true, false, true, true); - validateNotFoundOrWrongType(BASE_64_BASIC, false, true, true, true, true, true, true); - validateNotFoundOrWrongType(BIG_DECIMAL, true, true, true, true, true, true, true); - validateNotFoundOrWrongType(MAP, true, true, true, true, true, false, true); - validateNotFoundOrWrongType(ARRAY, true, true, true, true, true, true, false); - validateNotFoundOrWrongType(SMAP, true, true, true, true, true, false, true); - validateNotFoundOrWrongType(SLIST, true, true, true, true, true, true, false); - validateNotFoundOrWrongType(NOT_A_KEY, true, true, true, true, true, true, true); - - // testGetIntLong - JsonValue x = readValue(TEST_JV, STRING); - JsonValue i = new JsonValue(Integer.MAX_VALUE); - JsonValue li = new JsonValue((long)Integer.MAX_VALUE); - JsonValue lmax = new JsonValue(Long.MAX_VALUE); - JsonValue lmin = new JsonValue(Long.MIN_VALUE); - getInt(i, -1); - getInt(li, -1); - getInt(x, -1); - getInt(JsonValue.NULL, -1); - getInt(EMPTY_MAP, -1); - getInt(EMPTY_ARRAY, -1); - getInteger(i); - getInteger(li); - getInteger(x); - getInteger(lmax); - getInteger(lmin); - getInteger(JsonValue.NULL); - getInteger(EMPTY_MAP); - getInteger(EMPTY_ARRAY); - getLong(i); - getLong(li); - getLong(lmax); - getLong(lmin); - getLong(x); - getLong(JsonValue.NULL); - getLong(EMPTY_MAP); - getLong(EMPTY_ARRAY); - getLong(i, -1); - getLong(li, -1); - getLong(lmax, -1); - getLong(lmin, -1); - getLong(x, -1); - getLong(JsonValue.NULL, -1); - getLong(EMPTY_MAP, -1); - getLong(EMPTY_ARRAY, -1); - - return System.nanoTime() - start; - } - - private static void validateNotFoundOrWrongType( - String key, - boolean notString, - boolean notDate, - boolean notInteger, - boolean notLong, - boolean notBoolean, - boolean notMap, - boolean notArray) - { - JsonValue jv = readValue(TEST_JV, key); - if (notString) { - readBytes(TEST_JV, key); - readBytes(TEST_JV, key, StandardCharsets.UTF_8); - readDate(TEST_JV, key); - } - else { - readBytes(TEST_JV, key); - readBytes(TEST_JV, key, StandardCharsets.UTF_8); - } - if (notDate) { - if (jv == null || jv.string == null) { - readDate(TEST_JV, key); - } - } - if (notInteger) { - readInteger(TEST_JV, key); - readInteger(TEST_JV, key, -1); - } - if (notLong) { - readLong(TEST_JV, key); - readLong(TEST_JV, key, -1); - } - if (notBoolean) { - readBoolean(TEST_JV, key); - readBoolean(TEST_JV, key, false); - } - - if (notMap) { - readMapObjectOrNull(TEST_JV, key); - readMapObjectOrEmpty(TEST_JV, key); - readMapMapOrNull(TEST_JV, key); - readMapMapOrEmpty(TEST_JV, key); - readStringMapOrNull(TEST_JV, key); - readStringMapOrEmpty(TEST_JV, key); - } - if (notArray) { - readArrayOrNull(TEST_JV, key); - readArrayOrEmpty(TEST_JV, key); - } - } -} diff --git a/src/test/java/io/synadia/json/DateTimeUtilsTests.java b/src/test/java/io/synadia/json/DateTimeUtilsTests.java index 5cef21a..28b697b 100644 --- a/src/test/java/io/synadia/json/DateTimeUtilsTests.java +++ b/src/test/java/io/synadia/json/DateTimeUtilsTests.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/test/java/io/synadia/json/EncodingTests.java b/src/test/java/io/synadia/json/EncodingTests.java index ee59885..e5717fd 100644 --- a/src/test/java/io/synadia/json/EncodingTests.java +++ b/src/test/java/io/synadia/json/EncodingTests.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/test/java/io/synadia/json/JsonParsingTests.java b/src/test/java/io/synadia/json/JsonParsingTests.java index 39e3fd7..f76530a 100644 --- a/src/test/java/io/synadia/json/JsonParsingTests.java +++ b/src/test/java/io/synadia/json/JsonParsingTests.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: @@ -14,8 +17,6 @@ package io.synadia.json; import io.ResourceUtils; -import nl.jqno.equalsverifier.EqualsVerifier; -import nl.jqno.equalsverifier.Warning; import org.jspecify.annotations.NonNull; import org.junit.jupiter.api.Test; @@ -317,24 +318,6 @@ public void testNullJsonValue() { assertEquals(JsonValue.NULL, new JsonValue((BigInteger) null)); } - @Test - public void equalsContract() { - Map map1 = new HashMap<>(); - map1.put("1", new JsonValue(1)); - Map map2 = new HashMap<>(); - map1.put("2", new JsonValue(2)); - List list3 = new ArrayList<>(); - list3.add(new JsonValue(3)); - List list4 = new ArrayList<>(); - list4.add(new JsonValue(4)); - EqualsVerifier.simple().forClass(JsonValue.class) - .withPrefabValues(Map.class, map1, map2) - .withPrefabValues(List.class, list3, list4) - .withIgnoredFields("object", "number", "mapOrder") - .suppress(Warning.BIGDECIMAL_EQUALITY) - .verify(); - } - private void validateParse(JsonValue expected, String json) throws JsonParseException { char[] ca = json.toCharArray(); byte[] ba = json.getBytes(); @@ -825,4 +808,55 @@ public void testCoverageAndEdges() { String json2 = jv.toJson(); assertEquals(json, json2); } + + @Test + public void testBasics() { + Map map1 = new HashMap<>(); + map1.put("key", new JsonValue("value2")); + Map map2 = new HashMap<>(); + map1.put("key", new JsonValue("value2")); + List list1 = new ArrayList<>(); + list1.add(new JsonValue("item1")); + List list2 = new ArrayList<>(); + list2.add(new JsonValue("item2")); + JsonValue[] array1 = {new JsonValue("item1"), new JsonValue(41)}; + JsonValue[] array2 = {new JsonValue("item2"), new JsonValue(42)}; + + JsonValue[] jvs = new JsonValue[]{ + new JsonValue("test string"), + new JsonValue("another string"), + new JsonValue(true), + new JsonValue(false), + new JsonValue(42), + new JsonValue(43), + new JsonValue(72L), + new JsonValue(73L), + new JsonValue(3.14), + new JsonValue(3.15), + new JsonValue(3.14f), + new JsonValue(3.15f), + new JsonValue(new BigDecimal("123.456")), + new JsonValue(new BigDecimal("321.456")), + new JsonValue(new BigInteger("123456789012345")), + new JsonValue(new BigInteger("134567890123456")), + new JsonValue(map1), + new JsonValue(map2), + new JsonValue(list1), + new JsonValue(list2), + new JsonValue(array1), + new JsonValue(array2) + }; + for (int i = 0; i < jvs.length; i++) { + for (int j = 0; j < jvs.length; j++) { + if (i == j) { + assertEquals(jvs[i], jvs[j]); + assertEquals(jvs[i].hashCode(), jvs[j].hashCode()); + } + else { + assertNotEquals(jvs[i], jvs[j]); + assertNotEquals(jvs[i].hashCode(), jvs[j].hashCode()); + } + } + } + } } diff --git a/src/test/java/io/synadia/json/JsonUnicodeParsingTest.java b/src/test/java/io/synadia/json/JsonUnicodeParsingTest.java index 821ff77..e91165d 100644 --- a/src/test/java/io/synadia/json/JsonUnicodeParsingTest.java +++ b/src/test/java/io/synadia/json/JsonUnicodeParsingTest.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/test/java/io/synadia/json/JsonValueUtilsTests.java b/src/test/java/io/synadia/json/JsonValueUtilsTests.java index 4870b0e..62eb837 100644 --- a/src/test/java/io/synadia/json/JsonValueUtilsTests.java +++ b/src/test/java/io/synadia/json/JsonValueUtilsTests.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2020-2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: diff --git a/src/test/java/io/synadia/json/JsonWriteUtilsTests.java b/src/test/java/io/synadia/json/JsonWriteUtilsTests.java index 955e079..67b8e5e 100644 --- a/src/test/java/io/synadia/json/JsonWriteUtilsTests.java +++ b/src/test/java/io/synadia/json/JsonWriteUtilsTests.java @@ -1,4 +1,7 @@ -// Copyright 2025 Synadia Communications, Inc. +// Copyright 2025 The NATS Authors +// +// Modifications Copyright 2025-2026 Synadia Communications, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: