From 6c21a222f05007d24c3206e1d9aebb929a4956e1 Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Thu, 4 Jun 2026 22:05:15 +0300 Subject: [PATCH 1/5] [improve][misc] Migrate Swagger annotations to OpenAPI 3 (Swagger Core v3, jakarta) Completes the Swagger migration deferred from PIP-472: Swagger 1.6.2 (io.swagger, javax-era, EOL) is replaced with Swagger Core v3 io.swagger.core.v3:swagger-annotations-jakarta:2.2.50 across the whole codebase, and OpenAPI document generation is restored in the Gradle build. Annotations (61 Java files): - @Api -> @Tag (+@Hidden where v1 had hidden=true), @ApiOperation -> @Operation, @ApiResponse(code=, message=, response=, responseContainer=) -> @ApiResponse(responseCode=, description=, content=) with @ArraySchema / additionalPropertiesSchema container mappings, @ApiParam -> @Parameter (bound params incl. @FormDataParam multipart parts) / @RequestBody (body params), @ApiModel/@ApiModelProperty -> @Schema with requiredMode, @Example/@ExampleProperty -> @ExampleObject. - Map-valued responses use @Schema(type = "object", additionalPropertiesSchema = X.class) - the only form the swagger-core 2.2.50 resolver actually renders; the @Content-level additionalPropertiesSchema = @Schema(implementation = X.class) form silently emits additionalProperties: {}. - Protobuf/lightproto types in @Schema(implementation=) are replaced with type = "object" schemas (Jackson introspection crashes on them and the endpoints emit protobuf JSON anyway). - BaseGenerateDocumentation reflection ported to @Schema (generateDocByApiModelProperty -> generateDocBySchema and friends). - Removed the unused NoSwaggerDocumentation marker annotation and stale workaround comments for swagger-api/swagger-core#449 and swagger-ui#558 (both fixed upstream years ago); nested map schemas are now expressed precisely. - Fixed malformed example JSON payloads that degraded to plain strings in generated docs (trailing comma, stray '+', missing comma). Build: - Version catalog: swagger = 2.2.50, swagger-annotations -> io.swagger.core.v3:swagger-annotations-jakarta; swagger-core alias removed (no code uses swagger-core classes). - New io.swagger.core.v3.swagger-gradle-plugin (2.2.50) configuration in pulsar-broker replicating the Maven build's `swagger` profile from branch-4.2: 7 ResolveTask instances with the same output file names, base info/servers from src/main/openapi/*.json, assembled by ./gradlew :pulsar-broker:swaggerDocs into build/docs with the flat + v2/ + v3/ layout published on pulsar.apache.org. The plugin's default javax resolver dependencies are overridden with swagger-jaxrs2-jakarta on the swaggerDeps configuration. - pulsar-docs-tools, pulsar-websocket and pulsar-client-tools now declare guava/commons-lang3 explicitly (previously leaked onto the compile classpath via swagger-core 1.x transitives). - io.kubernetes:client-java's transitive Swagger 1.x annotations are excluded everywhere: they are inert metadata on the generated k8s models (verified: no Methodref/Fieldref in any class, runtime jar has zero references) and the JVM ignores missing annotation types. - Shade include pattern updated to the io.swagger.core.v3 group; LICENSE.bin.txt entries updated (checkBinaryLicense passes for server and shell distributions). Verification: generated documents are operation-identical with the published 4.2.1 docs (597/597 operations across all 7 files, zero drift); every annotated resource class in the repo (broker, functions worker, websocket, proxy) resolves cleanly through the real scanner; map-valued responses render the same additionalProperties value schemas as 4.2.1. Assisted-by: Claude Code (Opus 4.8) --- ...pulsar.client-shade-conventions.gradle.kts | 2 +- .../server/src/assemble/LICENSE.bin.txt | 4 +- .../shell/src/assemble/LICENSE.bin.txt | 2 +- gradle/libs.versions.toml | 9 +- pulsar-broker-auth-oidc/build.gradle.kts | 2 + pulsar-broker/build.gradle.kts | 102 +- .../broker/admin/impl/BrokerStatsBase.java | 74 +- .../pulsar/broker/admin/impl/BrokersBase.java | 185 +- .../broker/admin/impl/ClustersBase.java | 433 +-- .../broker/admin/impl/FunctionsBase.java | 510 ++- .../admin/impl/MetadataMigrationBase.java | 29 +- .../pulsar/broker/admin/impl/SinksBase.java | 381 +- .../pulsar/broker/admin/impl/SourcesBase.java | 413 +- .../pulsar/broker/admin/impl/TenantsBase.java | 84 +- .../pulsar/broker/admin/v2/Bookies.java | 60 +- .../pulsar/broker/admin/v2/BrokerStats.java | 46 +- .../pulsar/broker/admin/v2/Brokers.java | 5 +- .../pulsar/broker/admin/v2/Clusters.java | 5 +- .../admin/v2/ExtNonPersistentTopics.java | 49 +- .../broker/admin/v2/ExtPersistentTopics.java | 49 +- .../pulsar/broker/admin/v2/Functions.java | 212 +- .../broker/admin/v2/MetadataMigration.java | 5 +- .../pulsar/broker/admin/v2/Namespaces.java | 1752 +++++---- .../broker/admin/v2/NonPersistentTopics.java | 302 +- .../broker/admin/v2/PersistentTopics.java | 3310 +++++++++-------- .../broker/admin/v2/ResourceGroups.java | 53 +- .../broker/admin/v2/ResourceQuotas.java | 84 +- .../broker/admin/v2/ScalableTopics.java | 271 +- .../broker/admin/v2/SchemasResource.java | 194 +- .../pulsar/broker/admin/v2/Segments.java | 195 +- .../pulsar/broker/admin/v2/Tenants.java | 5 +- .../apache/pulsar/broker/admin/v2/Worker.java | 147 +- .../pulsar/broker/admin/v2/WorkerStats.java | 39 +- .../pulsar/broker/admin/v3/Functions.java | 5 +- .../pulsar/broker/admin/v3/Packages.java | 119 +- .../apache/pulsar/broker/admin/v3/Sink.java | 4 +- .../apache/pulsar/broker/admin/v3/Sinks.java | 5 +- .../apache/pulsar/broker/admin/v3/Source.java | 4 +- .../pulsar/broker/admin/v3/Sources.java | 5 +- .../pulsar/broker/admin/v3/Transactions.java | 240 +- .../pulsar/broker/lookup/v2/TopicLookup.java | 37 +- .../org/apache/pulsar/broker/rest/Topics.java | 95 +- .../broker/web/NoSwaggerDocumentation.java | 23 - pulsar-broker/src/main/openapi/admin-v2.json | 16 + .../src/main/openapi/functions-v3.json | 16 + pulsar-broker/src/main/openapi/lookup-v2.json | 16 + .../src/main/openapi/packages-v3.json | 16 + pulsar-broker/src/main/openapi/sink-v3.json | 16 + pulsar-broker/src/main/openapi/source-v3.json | 16 + .../src/main/openapi/transactions-v3.json | 16 + pulsar-client-tools/build.gradle.kts | 5 +- .../impl/conf/ClientConfigurationData.java | 253 +- .../impl/conf/ConsumerConfigurationData.java | 129 +- .../impl/conf/ProducerConfigurationData.java | 68 +- .../impl/conf/ReaderConfigurationData.java | 50 +- .../common/functions/UpdateOptionsImpl.java | 9 +- .../data/AutoFailoverPolicyDataImpl.java | 17 +- .../BrokerNamespaceIsolationDataImpl.java | 23 +- .../common/policies/data/ClusterDataImpl.java | 104 +- .../policies/data/ClusterPoliciesImpl.java | 15 +- .../policies/data/FailureDomainImpl.java | 11 +- .../data/NamespaceIsolationDataImpl.java | 29 +- .../common/policies/data/TenantInfoImpl.java | 13 +- .../common/util/PulsarSslConfiguration.java | 88 +- pulsar-docs-tools/build.gradle.kts | 3 +- .../docs/tools/BaseGenerateDocumentation.java | 34 +- .../localrun-shaded/build.gradle.kts | 2 +- pulsar-functions/runtime/build.gradle.kts | 2 + pulsar-functions/secrets/build.gradle.kts | 2 + pulsar-functions/worker/build.gradle.kts | 7 +- .../worker/rest/WorkerReadinessResource.java | 20 +- .../rest/api/v2/FunctionsApiV2Resource.java | 202 +- .../rest/api/v2/WorkerApiV2Resource.java | 137 +- .../rest/api/v2/WorkerStatsApiV2Resource.java | 43 +- .../rest/api/v3/FunctionsApiV3Resource.java | 188 +- .../worker/rest/api/v3/SinkApiV3Resource.java | 4 +- .../rest/api/v3/SinksApiV3Resource.java | 154 +- .../rest/api/v3/SourceApiV3Resource.java | 4 +- .../rest/api/v3/SourcesApiV3Resource.java | 169 +- .../apache/pulsar/proxy/stats/ProxyStats.java | 41 +- .../proxy/util/CmdGenerateDocumentation.java | 8 +- pulsar-websocket/build.gradle.kts | 5 +- .../admin/v2/WebSocketProxyStatsV2.java | 34 +- tests/integration/build.gradle.kts | 4 + 84 files changed, 6345 insertions(+), 5194 deletions(-) delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/web/NoSwaggerDocumentation.java create mode 100644 pulsar-broker/src/main/openapi/admin-v2.json create mode 100644 pulsar-broker/src/main/openapi/functions-v3.json create mode 100644 pulsar-broker/src/main/openapi/lookup-v2.json create mode 100644 pulsar-broker/src/main/openapi/packages-v3.json create mode 100644 pulsar-broker/src/main/openapi/sink-v3.json create mode 100644 pulsar-broker/src/main/openapi/source-v3.json create mode 100644 pulsar-broker/src/main/openapi/transactions-v3.json diff --git a/build-logic/conventions/src/main/kotlin/pulsar.client-shade-conventions.gradle.kts b/build-logic/conventions/src/main/kotlin/pulsar.client-shade-conventions.gradle.kts index a7013d9b5b2b6..1435aaef76d9f 100644 --- a/build-logic/conventions/src/main/kotlin/pulsar.client-shade-conventions.gradle.kts +++ b/build-logic/conventions/src/main/kotlin/pulsar.client-shade-conventions.gradle.kts @@ -60,7 +60,7 @@ tasks.named("shadowJ include(dependency("io.opencensus:.*")) include(dependency("io.perfmark:.*")) include(dependency("io.prometheus:.*")) - include(dependency("io.swagger:.*")) + include(dependency("io.swagger.core.v3:.*")) include(dependency("jakarta.activation:jakarta.activation-api")) include(dependency("jakarta.annotation:jakarta.annotation-api")) include(dependency("jakarta.inject:jakarta.inject-api")) diff --git a/distribution/server/src/assemble/LICENSE.bin.txt b/distribution/server/src/assemble/LICENSE.bin.txt index 272bacce1bddb..8a4f3fdefb82e 100644 --- a/distribution/server/src/assemble/LICENSE.bin.txt +++ b/distribution/server/src/assemble/LICENSE.bin.txt @@ -274,9 +274,7 @@ The Apache Software License, Version 2.0 * J2ObjC Annotations -- com.google.j2objc-j2objc-annotations-1.3.jar * Netty Reactive Streams -- com.typesafe.netty-netty-reactive-streams-2.0.6.jar * Swagger - - io.swagger-swagger-annotations-1.6.2.jar - - io.swagger-swagger-core-1.6.2.jar - - io.swagger-swagger-models-1.6.2.jar + - io.swagger.core.v3-swagger-annotations-jakarta-2.2.50.jar * slog -- io.github.merlimat.slog-slog-0.9.7.jar * DataSketches - com.yahoo.datasketches-memory-0.8.3.jar diff --git a/distribution/shell/src/assemble/LICENSE.bin.txt b/distribution/shell/src/assemble/LICENSE.bin.txt index 6688d8800b89d..8e9aa8ccba08a 100644 --- a/distribution/shell/src/assemble/LICENSE.bin.txt +++ b/distribution/shell/src/assemble/LICENSE.bin.txt @@ -334,7 +334,7 @@ The Apache Software License, Version 2.0 - listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar * J2ObjC Annotations -- j2objc-annotations-1.3.jar * Netty Reactive Streams -- netty-reactive-streams-2.0.6.jar - * Swagger -- swagger-annotations-1.6.2.jar + * Swagger -- swagger-annotations-jakarta-2.2.50.jar * DataSketches - memory-0.8.3.jar - sketches-core-0.8.3.jar diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2174e5bd8099c..8414597bf2156 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -112,8 +112,8 @@ audience-annotations = "0.12.0" # Misc curator = "5.7.1" reflections = "0.10.2" -# swagger stays 1.6.2 in Phase A (javax→jakarta core); migrated to Swagger Core 2.x (io.swagger.core.v3) in Phase B -swagger = "1.6.2" +# OpenAPI 3 annotations (io.swagger.core.v3, jakarta variant) used for REST API and config docs annotations +swagger = "2.2.50" typetools = "0.5.0" jna = "5.18.1" java-semver = "0.9.0" @@ -338,8 +338,8 @@ aircompressor = { module = "io.airlift:aircompressor", version.ref = "aircompres gson = { module = "com.google.code.gson:gson", version.ref = "gson" } re2j = { module = "com.google.re2j:re2j", version.ref = "re2j" } completable-futures = { module = "com.spotify:completable-futures", version.ref = "completable-futures" } -swagger-annotations = { module = "io.swagger:swagger-annotations", version.ref = "swagger" } -swagger-core = { module = "io.swagger:swagger-core", version.ref = "swagger" } +swagger-annotations = { module = "io.swagger.core.v3:swagger-annotations-jakarta", version.ref = "swagger" } +swagger-jaxrs2 = { module = "io.swagger.core.v3:swagger-jaxrs2-jakarta", version.ref = "swagger" } picocli = { module = "info.picocli:picocli", version.ref = "picocli" } picocli-shell-jline3 = { module = "info.picocli:picocli-shell-jline3", version.ref = "picocli" } jline = { module = "org.jline:jline", version.ref = "jline3" } @@ -475,6 +475,7 @@ protobuf = "com.google.protobuf:0.9.6" shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } rat = "org.nosphere.apache.rat:0.8.1" spotless = "com.diffplug.spotless:8.4.0" +swagger = { id = "io.swagger.core.v3.swagger-gradle-plugin", version.ref = "swagger" } version-catalog-update = "nl.littlerobots.version-catalog-update:1.1.0" versions = "com.github.ben-manes.versions:0.53.0" crlf = "com.github.vlsi.crlf:3.0.1" diff --git a/pulsar-broker-auth-oidc/build.gradle.kts b/pulsar-broker-auth-oidc/build.gradle.kts index 8001b53fed56f..a76540c1fb734 100644 --- a/pulsar-broker-auth-oidc/build.gradle.kts +++ b/pulsar-broker-auth-oidc/build.gradle.kts @@ -33,6 +33,8 @@ dependencies { implementation(libs.jackson.annotations) implementation(libs.kubernetes.client.java) { exclude(group = "software.amazon.awssdk") + // Swagger 1.x annotations on the generated k8s models are inert metadata; nothing reads them at runtime + exclude(group = "io.swagger", module = "swagger-annotations") } implementation(libs.okhttp3) implementation(libs.commons.lang3) diff --git a/pulsar-broker/build.gradle.kts b/pulsar-broker/build.gradle.kts index 80c9ade313695..3016b7fdea0bb 100644 --- a/pulsar-broker/build.gradle.kts +++ b/pulsar-broker/build.gradle.kts @@ -22,6 +22,7 @@ plugins { id("pulsar.test-certs-conventions") alias(libs.plugins.protobuf) alias(libs.plugins.lightproto) + alias(libs.plugins.swagger) } dependencies { @@ -38,7 +39,7 @@ dependencies { implementation(project(":pulsar-client-messagecrypto-bc")) implementation(project(":pulsar-functions:pulsar-functions-worker")) implementation(project(":pulsar-docs-tools")) { - exclude(group = "io.swagger") + exclude(group = "io.swagger.core.v3") } implementation(project(":pulsar-package-management:pulsar-package-core")) implementation(project(":pulsar-package-management:pulsar-package-filesystem-storage")) @@ -104,7 +105,6 @@ dependencies { implementation(project(":pulsar-functions:pulsar-functions-proto")) compileOnly(libs.swagger.annotations) - compileOnly(libs.swagger.core) compileOnly(libs.jsr305) testImplementation(project(":testmocks")) @@ -212,3 +212,101 @@ lightproto { // TransactionPendingAck.proto imports PulsarApi.proto from pulsar-common extraProtoPaths.from(rootProject.layout.projectDirectory) } + +// ── OpenAPI (Swagger) REST API documentation ──────────────────────────────── +// Mirrors the Maven build's `swagger` profile (kongchen swagger-maven-plugin, Swagger 1.x), +// ported to the official Swagger Core v3 gradle plugin. Run on demand: +// ./gradlew :pulsar-broker:swaggerDocs (outputs to pulsar-broker/build/docs/) +// The plugin's default `swaggerDeps` resolver dependencies target javax.ws.rs; declaring +// our own dependencies on the configuration replaces them with the jakarta variants. +dependencies { + "swaggerDeps"(libs.commons.lang3) + "swaggerDeps"(libs.swagger.jaxrs2) + "swaggerDeps"(libs.jakarta.ws.rs.api) + "swaggerDeps"(libs.jakarta.servlet.api) +} + +fun registerSwaggerTask( + name: String, + fileName: String, + baseInfoFile: String, + configure: io.swagger.v3.plugins.gradle.tasks.ResolveTask.() -> Unit, +) = tasks.register(name) { + group = "documentation" + description = "Generates $fileName.json OpenAPI documentation" + buildClasspath.setFrom(configurations["swaggerDeps"]) + classpath.setFrom(sourceSets["main"].runtimeClasspath) + outputDir.set(layout.buildDirectory.dir("swagger/$name")) + outputFileName.set(fileName) + outputFormat.set(io.swagger.v3.plugins.gradle.tasks.ResolveTask.Format.JSON) + openApiFile.set(file("src/main/openapi/$baseInfoFile")) + prettyPrint.set(true) + sortOutput.set(true) + readAllResources.set(true) + configure() +} + +registerSwaggerTask("swaggerAdminV2", "swagger", "admin-v2.json") { + resourceClasses.set(setOf( + "org.apache.pulsar.broker.admin.v2.Bookies", + "org.apache.pulsar.broker.admin.v2.BrokerStats", + "org.apache.pulsar.broker.admin.v2.Brokers", + "org.apache.pulsar.broker.admin.v2.Clusters", + "org.apache.pulsar.broker.admin.v2.Functions", + "org.apache.pulsar.broker.admin.v2.Namespaces", + "org.apache.pulsar.broker.admin.v2.NonPersistentTopics", + "org.apache.pulsar.broker.admin.v2.PersistentTopics", + // See https://github.com/apache/pulsar/issues/18947 + // "org.apache.pulsar.broker.admin.v2.ExtPersistentTopics", + // "org.apache.pulsar.broker.admin.v2.ExtNonPersistentTopics", + "org.apache.pulsar.broker.admin.v2.ResourceGroups", + "org.apache.pulsar.broker.admin.v2.ResourceQuotas", + "org.apache.pulsar.broker.admin.v2.SchemasResource", + "org.apache.pulsar.broker.admin.v2.Tenants", + "org.apache.pulsar.broker.admin.v2.Worker", + "org.apache.pulsar.broker.admin.v2.WorkerStats", + )) +} + +registerSwaggerTask("swaggerLookup", "swaggerlookup", "lookup-v2.json") { + resourcePackages.set(setOf("org.apache.pulsar.broker.lookup.v2")) +} + +registerSwaggerTask("swaggerFunctions", "swaggerfunctions", "functions-v3.json") { + resourceClasses.set(setOf("org.apache.pulsar.broker.admin.v3.Functions")) +} + +registerSwaggerTask("swaggerTransactions", "swaggertransactions", "transactions-v3.json") { + resourceClasses.set(setOf("org.apache.pulsar.broker.admin.v3.Transactions")) +} + +registerSwaggerTask("swaggerSource", "swaggersource", "source-v3.json") { + resourceClasses.set(setOf("org.apache.pulsar.broker.admin.v3.Sources")) +} + +registerSwaggerTask("swaggerSink", "swaggersink", "sink-v3.json") { + resourceClasses.set(setOf("org.apache.pulsar.broker.admin.v3.Sinks")) +} + +registerSwaggerTask("swaggerPackages", "swaggerpackages", "packages-v3.json") { + resourceClasses.set(setOf("org.apache.pulsar.broker.admin.v3.Packages")) +} + +// Assemble the documentation set in the layout published on pulsar.apache.org (see e.g. +// pulsar-site static/swagger//): all files flat, plus v2/ and v3/ subdirectory copies +// grouped by REST API version. +tasks.register("swaggerDocs") { + group = "documentation" + description = "Generates all OpenAPI REST API documentation files to build/docs" + into(layout.buildDirectory.dir("docs")) + val v2Tasks = listOf("swaggerAdminV2", "swaggerLookup") + val v3Tasks = listOf("swaggerFunctions", "swaggerTransactions", "swaggerSource", "swaggerSink", "swaggerPackages") + v2Tasks.forEach { t -> + from(tasks.named(t)) + from(tasks.named(t)) { into("v2") } + } + v3Tasks.forEach { t -> + from(tasks.named(t)) + from(tasks.named(t)) { into("v3") } + } +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java index 9bdfad4d457e5..e7f26d33c8c95 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java @@ -18,16 +18,18 @@ */ package org.apache.pulsar.broker.admin.impl; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.StreamingOutput; -import java.io.OutputStream; import java.util.Collection; import java.util.Map; import org.apache.bookkeeper.mledger.proto.PendingBookieOpsStats; @@ -48,10 +50,12 @@ public class BrokerStatsBase extends AdminResource { @GET @Path("/metrics") - @ApiOperation(value = "Gets the metrics for Monitoring", - notes = "Requested should be executed by Monitoring agent on each broker to fetch the metrics", - response = Metrics.class, responseContainer = "List") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Gets the metrics for Monitoring", + description = "Requested should be executed by Monitoring agent on each broker to fetch the metrics") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Metrics.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public Collection getMetrics() throws Exception { // Ensure super user access only validateSuperUserAccess(); @@ -66,9 +70,11 @@ public Collection getMetrics() throws Exception { @GET @Path("/mbeans") - @ApiOperation(value = "Get all the mbean details of this broker JVM", - response = Metrics.class, responseContainer = "List") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get all the mbean details of this broker JVM") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get all the mbean details of this broker JVM", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Metrics.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public Collection getMBeans() throws Exception { // Ensure super user access only validateSuperUserAccess(); @@ -83,10 +89,13 @@ public Collection getMBeans() throws Exception { @GET @Path("/destinations") - @ApiOperation(value = "Get all the topic stats by namespace", response = OutputStream.class, - responseContainer = "OutputStream") // https://github.com/swagger-api/swagger-ui/issues/558 - // map support missing - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get all the topic stats by namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get all the topic stats by namespace", + content = @Content(mediaType = "application/json", + schema = @Schema(type = "object", description = "Nested JSON object:" + + " namespace -> bundle range -> persistent/non-persistent -> topic -> stats"))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public StreamingOutput getTopics2() throws Exception { // Ensure super user access only validateSuperUserAccess(); @@ -101,9 +110,13 @@ public StreamingOutput getTopics2() throws Exception { @GET @Path("/allocator-stats/{allocator}") - @ApiOperation(value = "Get the stats for the Netty allocator. Available allocators are 'default' and 'ml-cache'", - response = AllocatorStats.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get the stats for the Netty allocator. Available allocators are 'default' and 'ml-cache'") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get the stats for the Netty allocator. Available allocators are 'default' " + + "and 'ml-cache'", + content = @Content(schema = @Schema(implementation = AllocatorStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public AllocatorStats getAllocatorStats(@PathParam("allocator") String allocatorName) throws Exception { // Ensure super user access only validateSuperUserAccess(); @@ -120,15 +133,14 @@ public AllocatorStats getAllocatorStats(@PathParam("allocator") String allocator @GET @Path("/bookieops") - @ApiOperation(value = "Get pending bookie client op stats by namespace", - notes = "Returns a nested map structure which Swagger does not fully support for display. " - + "Structure: Map>." - + " Please refer to this structure for details.", - response = PendingBookieOpsStats.class, - // https://github.com/swagger-api/swagger-core/issues/449 - // nested containers are not supported - responseContainer = "Map") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get pending bookie client op stats by namespace", + description = "Returns a nested map structure: Map>.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get pending bookie client op stats by namespace", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesSchema = + @Schema(additionalPropertiesSchema = PendingBookieOpsStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public Map> getPendingBookieOpsStats() { // Ensure super user access only validateSuperUserAccess(); @@ -144,9 +156,11 @@ public Map> getPendingBookieOpsStats( @GET @Path("/load-report") - @ApiOperation(value = "Get Load for this broker", notes = "consists of topics stats & systemResourceUsage", - response = LoadReport.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get Load for this broker", description = "consists of topics stats & systemResourceUsage") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get Load for this broker", + content = @Content(schema = @Schema(implementation = LoadReport.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public LoadManagerReport getLoadReport() throws Exception { // Ensure super user access only validateSuperUserAccess(); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java index e4774932ab56e..c2ef621c14cad 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java @@ -19,10 +19,13 @@ package org.apache.pulsar.broker.admin.impl; import com.google.common.collect.Maps; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; @@ -68,17 +71,20 @@ public class BrokersBase extends AdminResource { @GET @Path("/{cluster}") - @ApiOperation( - value = "Get the list of active brokers (broker ids) in the cluster." - + "If authorization is not enabled, any cluster name is valid.", - response = String.class, - responseContainer = "Set") + @Operation( + summary = "Get the list of active brokers (broker ids) in the cluster." + + "If authorization is not enabled, any cluster name is valid.") @ApiResponses( value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve this cluster"), - @ApiResponse(code = 401, message = "Authentication required"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 404, message = "Cluster does not exist: cluster={clustername}") }) + @ApiResponse(responseCode = "200", + description = "Get the list of active brokers (broker ids) in the cluster." + + "If authorization is not enabled, any cluster name is valid.", + content = @Content(array = @ArraySchema(uniqueItems = true, + schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve this cluster"), + @ApiResponse(responseCode = "401", description = "Authentication required"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "404", description = "Cluster does not exist: cluster={clustername}") }) public void getActiveBrokers(@Suspended final AsyncResponse asyncResponse, @PathParam("cluster") String cluster) { validateBothSuperuserAndBrokerOperation(cluster == null ? pulsar().getConfiguration().getClusterName() @@ -104,29 +110,33 @@ public void getActiveBrokers(@Suspended final AsyncResponse asyncResponse, } @GET - @ApiOperation( - value = "Get the list of active brokers (broker ids) in the local cluster." - + "If authorization is not enabled", - response = String.class, - responseContainer = "Set") + @Operation( + summary = "Get the list of active brokers (broker ids) in the local cluster." + + "If authorization is not enabled") @ApiResponses( value = { - @ApiResponse(code = 401, message = "Authentication required"), - @ApiResponse(code = 403, message = "This operation requires super-user access") }) + @ApiResponse(responseCode = "200", + description = "Get the list of active brokers (broker ids) in the local cluster." + + "If authorization is not enabled", + content = @Content(array = @ArraySchema(uniqueItems = true, + schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", description = "Authentication required"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access") }) public void getActiveBrokers(@Suspended final AsyncResponse asyncResponse) throws Exception { getActiveBrokers(asyncResponse, null); } @GET @Path("/leaderBroker") - @ApiOperation( - value = "Get the information of the leader broker.", - response = BrokerInfo.class) + @Operation( + summary = "Get the information of the leader broker.") @ApiResponses( value = { - @ApiResponse(code = 401, message = "Authentication required"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 404, message = "Leader broker not found") }) + @ApiResponse(responseCode = "200", description = "Get the information of the leader broker.", + content = @Content(schema = @Schema(implementation = BrokerInfo.class))), + @ApiResponse(responseCode = "401", description = "Authentication required"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "404", description = "Leader broker not found") }) public void getLeaderBroker(@Suspended final AsyncResponse asyncResponse) { validateBothSuperuserAndBrokerOperation(pulsar().getConfig().getClusterName(), pulsar().getBrokerId(), BrokerOperation.GET_LEADER_BROKER) @@ -150,12 +160,15 @@ public void getLeaderBroker(@Suspended final AsyncResponse asyncResponse) { @GET @Path("/{clusterName}/{brokerId}/ownedNamespaces") - @ApiOperation(value = "Get the list of namespaces served by the specific broker id", - response = NamespaceOwnershipStatus.class, responseContainer = "Map") + @Operation(summary = "Get the list of namespaces served by the specific broker id") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the cluster"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Cluster doesn't exist") }) + @ApiResponse(responseCode = "200", + description = "Get the list of namespaces served by the specific broker id", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = NamespaceOwnershipStatus.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the cluster"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist") }) public void getOwnedNamespaces(@Suspended final AsyncResponse asyncResponse, @PathParam("clusterName") String cluster, @PathParam("brokerId") String brokerId) { @@ -180,14 +193,15 @@ public void getOwnedNamespaces(@Suspended final AsyncResponse asyncResponse, @POST @Path("/configuration/{configName}/{configValue}") - @ApiOperation(value = + @Operation(summary = "Update dynamic serviceconfiguration into zk only. This operation requires Pulsar super-user privileges.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Service configuration updated successfully"), - @ApiResponse(code = 403, message = "You don't have admin permission to update service-configuration"), - @ApiResponse(code = 404, message = "Configuration not found"), - @ApiResponse(code = 412, message = "Invalid dynamic-config value"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "204", description = "Service configuration updated successfully"), + @ApiResponse(responseCode = "403", + description = "You don't have admin permission to update service-configuration"), + @ApiResponse(responseCode = "404", description = "Configuration not found"), + @ApiResponse(responseCode = "412", description = "Invalid dynamic-config value"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void updateDynamicConfiguration(@Suspended AsyncResponse asyncResponse, @PathParam("configName") String configName, @PathParam("configValue") String configValue) { @@ -213,13 +227,15 @@ public void updateDynamicConfiguration(@Suspended AsyncResponse asyncResponse, @DELETE @Path("/configuration/{configName}") - @ApiOperation(value = + @Operation(summary = "Delete dynamic ServiceConfiguration into metadata only." + " This operation requires Pulsar super-user privileges.") - @ApiResponses(value = { @ApiResponse(code = 204, message = "Service configuration delete successfully"), - @ApiResponse(code = 403, message = "You don't have admin permission to update service-configuration"), - @ApiResponse(code = 412, message = "Invalid dynamic-config value"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Service configuration delete successfully"), + @ApiResponse(responseCode = "403", + description = "You don't have admin permission to update service-configuration"), + @ApiResponse(responseCode = "412", description = "Invalid dynamic-config value"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void deleteDynamicConfiguration( @Suspended AsyncResponse asyncResponse, @PathParam("configName") String configName) { @@ -243,12 +259,14 @@ public void deleteDynamicConfiguration( @GET @Path("/configuration/values") - @ApiOperation(value = "Get value of all dynamic configurations' value overridden on local config", - response = String.class, responseContainer = "Map") + @Operation(summary = "Get value of all dynamic configurations' value overridden on local config") @ApiResponses(value = { - @ApiResponse(code = 403, message = "You don't have admin permission to view configuration"), - @ApiResponse(code = 404, message = "Configuration not found"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "200", + description = "Get value of all dynamic configurations' value overridden on local config", + content = @Content(schema = @Schema(type = "object", additionalPropertiesSchema = String.class))), + @ApiResponse(responseCode = "403", description = "You don't have admin permission to view configuration"), + @ApiResponse(responseCode = "404", description = "Configuration not found"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getAllDynamicConfigurations(@Suspended AsyncResponse asyncResponse) { validateBothSuperuserAndBrokerOperation(pulsar().getConfig().getClusterName(), pulsar().getBrokerId(), BrokerOperation.LIST_DYNAMIC_CONFIGURATIONS) @@ -265,10 +283,11 @@ public void getAllDynamicConfigurations(@Suspended AsyncResponse asyncResponse) @GET @Path("/configuration") - @ApiOperation(value = "Get all updatable dynamic configurations's name", - response = String.class, responseContainer = "List") + @Operation(summary = "Get all updatable dynamic configurations's name") @ApiResponses(value = { - @ApiResponse(code = 403, message = "You don't have admin permission to get configuration")}) + @ApiResponse(responseCode = "200", description = "Get all updatable dynamic configurations's name", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "You don't have admin permission to get configuration")}) public void getDynamicConfigurationName(@Suspended AsyncResponse asyncResponse) { validateBothSuperuserAndBrokerOperation(pulsar().getConfig().getClusterName(), pulsar().getBrokerId(), BrokerOperation.LIST_DYNAMIC_CONFIGURATIONS) @@ -284,9 +303,14 @@ public void getDynamicConfigurationName(@Suspended AsyncResponse asyncResponse) @GET @Path("/configuration/runtime") - @ApiOperation(value = "Get all runtime configurations. This operation requires Pulsar super-user privileges.", - response = String.class, responseContainer = "Map") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get all runtime configurations. This operation requires Pulsar super-user privileges.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get all runtime configurations. This operation requires Pulsar super-user " + + "privileges.", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = String.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void getRuntimeConfiguration(@Suspended AsyncResponse asyncResponse) { validateBothSuperuserAndBrokerOperation(pulsar().getConfig().getClusterName(), pulsar().getBrokerId(), BrokerOperation.LIST_RUNTIME_CONFIGURATIONS) @@ -329,8 +353,11 @@ private synchronized CompletableFuture persistDynamicConfigurationAsync( @GET @Path("/internal-configuration") - @ApiOperation(value = "Get the internal configuration data", response = InternalConfigurationData.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get the internal configuration data") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the internal configuration data", + content = @Content(schema = @Schema(implementation = InternalConfigurationData.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void getInternalConfigurationData(@Suspended AsyncResponse asyncResponse) { validateBothSuperuserAndBrokerOperation(pulsar().getConfig().getClusterName(), pulsar().getBrokerId(), BrokerOperation.GET_INTERNAL_CONFIGURATION_DATA) @@ -346,11 +373,11 @@ public void getInternalConfigurationData(@Suspended AsyncResponse asyncResponse) @GET @Path("/backlog-quota-check") - @ApiOperation(value = "An REST endpoint to trigger backlogQuotaCheck") + @Operation(summary = "An REST endpoint to trigger backlogQuotaCheck") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Everything is OK"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Everything is OK"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void backlogQuotaCheck(@Suspended AsyncResponse asyncResponse) { validateBothSuperuserAndBrokerOperation(pulsar().getConfig().getClusterName(), pulsar().getBrokerId(), BrokerOperation.CHECK_BACKLOG_QUOTA) @@ -369,10 +396,10 @@ public void backlogQuotaCheck(@Suspended AsyncResponse asyncResponse) { @GET @Path("/ready") - @ApiOperation(value = "Check if the broker is fully initialized") + @Operation(summary = "Check if the broker is fully initialized") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Broker is ready"), - @ApiResponse(code = 500, message = "Broker is not ready") }) + @ApiResponse(responseCode = "200", description = "Broker is ready"), + @ApiResponse(responseCode = "500", description = "Broker is not ready") }) public void isReady(@Suspended AsyncResponse asyncResponse) { if (pulsar().getState() == State.Started) { asyncResponse.resume(Response.ok("ok").build()); @@ -383,14 +410,14 @@ public void isReady(@Suspended AsyncResponse asyncResponse) { @GET @Path("/health") - @ApiOperation(value = "Run a healthCheck against the broker") + @Operation(summary = "Run a healthCheck against the broker") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Everything is OK"), - @ApiResponse(code = 307, message = "Current broker is not the target broker"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Cluster doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Service unavailable")}) + @ApiResponse(responseCode = "200", description = "Everything is OK"), + @ApiResponse(responseCode = "307", description = "Current broker is not the target broker"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Service unavailable")}) public void healthCheck(@Suspended AsyncResponse asyncResponse, @QueryParam("brokerId") String brokerId) { if (pulsar().getState() == State.Closed || pulsar().getState() == State.Closing) { @@ -465,25 +492,27 @@ private CompletableFuture internalDeleteDynamicConfigurationOnMetadataAsyn @GET @Path("/version") - @ApiOperation(value = "Get version of current broker") + @Operation(summary = "Get version of current broker") @ApiResponses(value = { - @ApiResponse(code = 200, message = "The Pulsar version", response = String.class), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "200", description = "The Pulsar version", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public String version() throws Exception { return PulsarVersion.getVersion(); } @POST @Path("/shutdown") - @ApiOperation(value = + @Operation(summary = "Shutdown broker gracefully.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Execute shutdown command successfully"), - @ApiResponse(code = 403, message = "You don't have admin permission to update service-configuration"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Execute shutdown command successfully"), + @ApiResponse(responseCode = "403", + description = "You don't have admin permission to update service-configuration"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void shutDownBrokerGracefully( - @ApiParam(name = "maxConcurrentUnloadPerSec", - value = "if the value absent(value=0) means no concurrent limitation.") + @Parameter(name = "maxConcurrentUnloadPerSec", + description = "if the value absent(value=0) means no concurrent limitation.") @QueryParam("maxConcurrentUnloadPerSec") int maxConcurrentUnloadPerSec, @QueryParam("forcedTerminateTopic") @DefaultValue("true") boolean forcedTerminateTopic, @Suspended final AsyncResponse asyncResponse diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java index 8b9c8f9e0bb64..3b8d7e4ff7820 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java @@ -19,12 +19,15 @@ package org.apache.pulsar.broker.admin.impl; import static jakarta.ws.rs.core.Response.Status.PRECONDITION_FAILED; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; @@ -80,13 +83,12 @@ public class ClustersBase extends AdminResource { @GET - @ApiOperation( - value = "Get the list of all the Pulsar clusters.", - response = String.class, - responseContainer = "Set") + @Operation(summary = "Get the list of all the Pulsar clusters.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Return a list of clusters."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Return a list of clusters.", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = String.class), uniqueItems = true))), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getClusters(@Suspended AsyncResponse asyncResponse) { clusterResources().listAsync() @@ -101,19 +103,19 @@ public void getClusters(@Suspended AsyncResponse asyncResponse) { @GET @Path("/{cluster}") - @ApiOperation( - value = "Get the configuration for the specified cluster.", - response = ClusterDataImpl.class, - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get the configuration for the specified cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Return the cluster data.", response = ClusterDataImpl.class), - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Return the cluster data.", + content = @Content(schema = @Schema(implementation = ClusterDataImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getCluster(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.GET_CLUSTER) .thenCompose(__ -> clusterResources().getClusterAsync(cluster)) @@ -132,32 +134,33 @@ public void getCluster(@Suspended AsyncResponse asyncResponse, @PUT @Path("/{cluster}") - @ApiOperation( - value = "Create a new cluster.", - notes = "This operation requires Pulsar superuser privileges, and the name cannot contain the '/' characters." + @Operation( + summary = "Create a new cluster.", + description = "This operation requires Pulsar superuser privileges, and the name cannot contain the '/'" + + " characters." ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Cluster has been created."), - @ApiResponse(code = 400, message = "Bad request parameter."), - @ApiResponse(code = 403, message = "You don't have admin permission to create the cluster."), - @ApiResponse(code = 409, message = "Cluster already exists."), - @ApiResponse(code = 412, message = "Cluster name is not valid."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Cluster has been created."), + @ApiResponse(responseCode = "400", description = "Bad request parameter."), + @ApiResponse(responseCode = "403", description = "You don't have admin permission to create the cluster."), + @ApiResponse(responseCode = "409", description = "Cluster already exists."), + @ApiResponse(responseCode = "412", description = "Cluster name is not valid."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void createCluster( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam( - value = "The cluster data", + @RequestBody( + description = "The cluster data", required = true, - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.APPLICATION_JSON, + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + examples = @ExampleObject( value = """ { "serviceUrl": "http://pulsar.example.com:8080", - "brokerServiceUrl": "pulsar://pulsar.example.com:6651", + "brokerServiceUrl": "pulsar://pulsar.example.com:6651" } """ ) @@ -202,26 +205,26 @@ public void createCluster( @POST @Path("/{cluster}") - @ApiOperation( - value = "Update the configuration for a cluster.", - notes = "This operation requires Pulsar superuser privileges.") + @Operation( + summary = "Update the configuration for a cluster.", + description = "This operation requires Pulsar superuser privileges.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Cluster has been updated."), - @ApiResponse(code = 400, message = "Bad request parameter."), - @ApiResponse(code = 403, message = "Don't have admin permission or policies are read-only."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Cluster has been updated."), + @ApiResponse(responseCode = "400", description = "Bad request parameter."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policies are read-only."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void updateCluster( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam( - value = "The cluster data", + @RequestBody( + description = "The cluster data", required = true, - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.APPLICATION_JSON, + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + examples = @ExampleObject( value = """ { "serviceUrl": "http://pulsar.example.com:8080", @@ -260,21 +263,21 @@ public void updateCluster( @GET @Path("/{cluster}/migrate") - @ApiOperation( - value = "Get the cluster migration configuration for the specified cluster.", - response = ClusterDataImpl.class, - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get the cluster migration configuration for the specified cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Return the cluster data.", response = ClusterDataImpl.class), - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Return the cluster data.", + content = @Content(schema = @Schema(implementation = ClusterDataImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getClusterMigration( @Suspended AsyncResponse asyncResponse, - @ApiParam( - value = "The cluster name", + @Parameter( + description = "The cluster name", required = true ) @PathParam("cluster") String cluster) { @@ -301,28 +304,28 @@ public void getClusterMigration( @POST @Path("/{cluster}/migrate") - @ApiOperation( - value = "Update the configuration for a cluster migration.", - notes = "This operation requires Pulsar superuser privileges.") + @Operation( + summary = "Update the configuration for a cluster migration.", + description = "This operation requires Pulsar superuser privileges.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Cluster has been updated."), - @ApiResponse(code = 400, message = "Cluster url must not be empty."), - @ApiResponse(code = 403, message = "Don't have admin permission or policies are read-only."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Cluster has been updated."), + @ApiResponse(responseCode = "400", description = "Cluster url must not be empty."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policies are read-only."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void updateClusterMigration( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "Is cluster migrated", required = true) + @Parameter(description = "Is cluster migrated", required = true) @QueryParam("migrated") boolean isMigrated, - @ApiParam( - value = "The cluster url data", + @RequestBody( + description = "The cluster url data", required = true, - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.APPLICATION_JSON, + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + examples = @ExampleObject( value = """ { "serviceUrl": "http://pulsar.example.com:8080", @@ -365,25 +368,24 @@ public void updateClusterMigration( @POST @Path("/{cluster}/peers") - @ApiOperation( - value = "Update peer-cluster-list for a cluster.", - notes = "This operation requires Pulsar superuser privileges.") + @Operation( + summary = "Update peer-cluster-list for a cluster.", + description = "This operation requires Pulsar superuser privileges.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Cluster has been updated."), - @ApiResponse(code = 403, message = "Don't have admin permission or policies are read-only."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 412, message = "Peer cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "204", description = "Cluster has been updated."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policies are read-only."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "412", description = "Peer cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void setPeerClusterNames(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam( - value = "The list of peer cluster names", + @RequestBody( + description = "The list of peer cluster names", required = true, - examples = @Example( - value = @ExampleProperty(mediaType = MediaType.APPLICATION_JSON, - value = """ + content = @Content(mediaType = MediaType.APPLICATION_JSON, + examples = @ExampleObject(value = """ [ "cluster-a", "cluster-b" @@ -441,19 +443,20 @@ private CompletableFuture innerSetPeerClusterNamesAsync(String cluster, @GET @Path("/{cluster}/peers") - @ApiOperation( - value = "Get the peer-cluster data for the specified cluster.", - response = String.class, - responseContainer = "Set", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get the peer-cluster data for the specified cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", description = "Get the peer-cluster data for the specified cluster.", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = String.class), uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getPeerCluster(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.GET_PEER_CLUSTER) .thenCompose(__ -> clusterResources().getClusterAsync(cluster)) @@ -473,19 +476,19 @@ public void getPeerCluster(@Suspended AsyncResponse asyncResponse, @DELETE @Path("/{cluster}") - @ApiOperation( - value = "Delete an existing cluster.", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Delete an existing cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Cluster has been deleted."), - @ApiResponse(code = 403, message = "Don't have admin permission or policies are read-only."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 412, message = "Cluster is not empty."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "204", description = "Cluster has been deleted."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policies are read-only."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "412", description = "Cluster is not empty."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void deleteCluster(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.DELETE_CLUSTER) .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync()) @@ -536,20 +539,22 @@ private CompletableFuture internalDeleteClusterAsync(String cluster) { @GET @Path("/{cluster}/namespaceIsolationPolicies") - @ApiOperation( - value = "Get the namespace isolation policies assigned to the cluster.", - response = NamespaceIsolationDataImpl.class, - responseContainer = "Map", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get the namespace isolation policies assigned to the cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", + description = "Get the namespace isolation policies assigned to the cluster.", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = NamespaceIsolationDataImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getNamespaceIsolationPolicies( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) @PathParam("cluster") String cluster + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster ) { validateBothSuperuserAndClusterPolicyOperation(cluster, PolicyName.NAMESPACE_ISOLATION, PolicyOperation.READ) .thenCompose(__ -> validateClusterExistAsync(cluster, Status.NOT_FOUND)) @@ -594,21 +599,23 @@ private CompletableFuture> internalGetNa @GET @Path("/{cluster}/namespaceIsolationPolicies/{policyName}") - @ApiOperation( - value = "Get the single namespace isolation policy assigned to the cluster.", - response = NamespaceIsolationDataImpl.class, - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get the single namespace isolation policy assigned to the cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Policy doesn't exist."), - @ApiResponse(code = 412, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", + description = "Get the single namespace isolation policy assigned to the cluster.", + content = @Content(schema = @Schema(implementation = NamespaceIsolationDataImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Policy doesn't exist."), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getNamespaceIsolationPolicy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The name of the namespace isolation policy", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, + @Parameter(description = "The name of the namespace isolation policy", required = true) @PathParam("policyName") String policyName ) { validateBothSuperuserAndClusterPolicyOperation(cluster, PolicyName.NAMESPACE_ISOLATION, PolicyOperation.READ) @@ -633,21 +640,24 @@ public void getNamespaceIsolationPolicy( @GET @Path("/{cluster}/namespaceIsolationPolicies/brokers") - @ApiOperation( - value = "Get list of brokers with namespace-isolation policies attached to them.", - response = BrokerNamespaceIsolationDataImpl.class, - responseContainer = "set", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get list of brokers with namespace-isolation policies attached to them.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Namespace-isolation policies not found."), - @ApiResponse(code = 412, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", + description = "Get list of brokers with namespace-isolation policies attached to them.", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = BrokerNamespaceIsolationDataImpl.class), + uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Namespace-isolation policies not found."), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getBrokersWithNamespaceIsolationPolicy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster) { validateBothSuperuserAndClusterPolicyOperation(cluster, PolicyName.NAMESPACE_ISOLATION, PolicyOperation.READ) .thenCompose(__ -> validateClusterExistAsync(cluster, Status.PRECONDITION_FAILED)) @@ -690,22 +700,24 @@ private BrokerNamespaceIsolationData internalGetBrokerNsIsolationData( @GET @Path("/{cluster}/namespaceIsolationPolicies/brokers/{broker}") - @ApiOperation( - value = "Get a broker with namespace-isolation policies attached to it.", - response = BrokerNamespaceIsolationDataImpl.class, - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get a broker with namespace-isolation policies attached to it.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Namespace-isolation policies/ Broker not found."), - @ApiResponse(code = 412, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "200", + description = "Get a broker with namespace-isolation policies attached to it.", + content = @Content(schema = @Schema(implementation = BrokerNamespaceIsolationDataImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Namespace-isolation policies/ Broker not found."), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void getBrokerWithNamespaceIsolationPolicy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The broker name (:)", required = true, + @Parameter(description = "The broker name (:)", required = true, example = "broker1:8080") @PathParam("broker") String broker) { validateBothSuperuserAndClusterPolicyOperation(cluster, PolicyName.NAMESPACE_ISOLATION, PolicyOperation.READ) @@ -726,25 +738,25 @@ public void getBrokerWithNamespaceIsolationPolicy( @POST @Path("/{cluster}/namespaceIsolationPolicies/{policyName}") - @ApiOperation( - value = "Set namespace isolation policy.", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Set namespace isolation policy.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Set namespace isolation policy successfully."), - @ApiResponse(code = 400, message = "Namespace isolation policy data is invalid."), - @ApiResponse(code = 403, message = "Don't have admin permission or policies are read-only."), - @ApiResponse(code = 404, message = "Namespace isolation policy doesn't exist."), - @ApiResponse(code = 412, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "204", description = "Set namespace isolation policy successfully."), + @ApiResponse(responseCode = "400", description = "Namespace isolation policy data is invalid."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policies are read-only."), + @ApiResponse(responseCode = "404", description = "Namespace isolation policy doesn't exist."), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void setNamespaceIsolationPolicy( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The namespace isolation policy name", required = true) + @Parameter(description = "The namespace isolation policy name", required = true) @PathParam("policyName") String policyName, - @ApiParam(value = "The namespace isolation policy data", required = true) + @RequestBody(description = "The namespace isolation policy data", required = true) NamespaceIsolationDataImpl policyData ) { validateBothSuperuserAndClusterPolicyOperation(cluster, PolicyName.NAMESPACE_ISOLATION, PolicyOperation.WRITE) @@ -905,22 +917,22 @@ private CompletableFuture filterAndUnloadMatchedNamespaceAsync(String clus @DELETE @Path("/{cluster}/namespaceIsolationPolicies/{policyName}") - @ApiOperation( - value = "Delete namespace isolation policy.", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Delete namespace isolation policy.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Delete namespace isolation policy successfully."), - @ApiResponse(code = 403, message = "Don't have admin permission or policies are read only."), - @ApiResponse(code = 404, message = "Namespace isolation policy doesn't exist."), - @ApiResponse(code = 412, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "204", description = "Delete namespace isolation policy successfully."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policies are read only."), + @ApiResponse(responseCode = "404", description = "Namespace isolation policy doesn't exist."), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void deleteNamespaceIsolationPolicy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The namespace isolation policy name", required = true) + @Parameter(description = "The namespace isolation policy name", required = true) @PathParam("policyName") String policyName ) { validateBothSuperuserAndClusterPolicyOperation(cluster, PolicyName.NAMESPACE_ISOLATION, PolicyOperation.WRITE) @@ -957,25 +969,26 @@ public void deleteNamespaceIsolationPolicy( @POST @Path("/{cluster}/failureDomains/{domainName}") - @ApiOperation( - value = "Set the failure domain of the cluster.", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Set the failure domain of the cluster.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Set the failure domain of the cluster successfully."), - @ApiResponse(code = 403, message = "Don't have admin permission."), - @ApiResponse(code = 404, message = "Failure domain doesn't exist."), - @ApiResponse(code = 409, message = "Broker already exists in another domain."), - @ApiResponse(code = 412, message = "Cluster doesn't exist."), - @ApiResponse(code = 500, message = "Internal server error.") + @ApiResponse(responseCode = "204", description = "Set the failure domain of the cluster successfully."), + @ApiResponse(responseCode = "403", description = "Don't have admin permission."), + @ApiResponse(responseCode = "404", description = "Failure domain doesn't exist."), + @ApiResponse(responseCode = "409", description = "Broker already exists in another domain."), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist."), + @ApiResponse(responseCode = "500", description = "Internal server error.") }) public void setFailureDomain( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The failure domain name", required = true) + @Parameter(description = "The failure domain name", required = true) @PathParam("domainName") String domainName, - @ApiParam(value = "The configuration data of a failure domain", required = true) FailureDomainImpl domain + @RequestBody(description = "The configuration data of a failure domain", required = true) + FailureDomainImpl domain ) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.UPDATE_FAILURE_DOMAIN) .thenCompose(__ -> validateClusterExistAsync(cluster, PRECONDITION_FAILED)) @@ -1012,19 +1025,20 @@ public void setFailureDomain( @GET @Path("/{cluster}/failureDomains") - @ApiOperation( - value = "Get the cluster failure domains.", - response = FailureDomainImpl.class, - responseContainer = "Map", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get the cluster failure domains.", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Get the cluster failure domains.", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = FailureDomainImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void getFailureDomains( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster ) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.GET_FAILURE_DOMAIN) @@ -1073,22 +1087,23 @@ public void getFailureDomains( @GET @Path("/{cluster}/failureDomains/{domainName}") - @ApiOperation( - value = "Get a domain in a cluster", - response = FailureDomainImpl.class, - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Get a domain in a cluster", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "FailureDomain doesn't exist"), - @ApiResponse(code = 412, message = "Cluster doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Get a domain in a cluster", + content = @Content(schema = @Schema(implementation = FailureDomainImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "FailureDomain doesn't exist"), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void getDomain( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The failure domain name", required = true) + @Parameter(description = "The failure domain name", required = true) @PathParam("domainName") String domainName ) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.GET_FAILURE_DOMAIN) @@ -1112,22 +1127,22 @@ public void getDomain( @DELETE @Path("/{cluster}/failureDomains/{domainName}") - @ApiOperation( - value = "Delete the failure domain of the cluster", - notes = "This operation requires Pulsar superuser privileges." + @Operation( + summary = "Delete the failure domain of the cluster", + description = "This operation requires Pulsar superuser privileges." ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Delete the failure domain of the cluster successfully"), - @ApiResponse(code = 403, message = "Don't have admin permission or policy is read only"), - @ApiResponse(code = 404, message = "FailureDomain doesn't exist"), - @ApiResponse(code = 412, message = "Cluster doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Delete the failure domain of the cluster successfully"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission or policy is read only"), + @ApiResponse(responseCode = "404", description = "FailureDomain doesn't exist"), + @ApiResponse(responseCode = "412", description = "Cluster doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void deleteFailureDomain( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "The cluster name", required = true) + @Parameter(description = "The cluster name", required = true) @PathParam("cluster") String cluster, - @ApiParam(value = "The failure domain name", required = true) + @Parameter(description = "The failure domain name", required = true) @PathParam("domainName") String domainName ) { validateBothSuperuserAndClusterOperation(cluster, ClusterOperation.DELETE_FAILURE_DOMAIN) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java index 106fc935d7d16..ad6a9c0eb92fa 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java @@ -18,12 +18,13 @@ */ package org.apache.pulsar.broker.admin.impl; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -59,27 +60,28 @@ Functions functions() { } @POST - @ApiOperation(value = "Creates a new Pulsar Function in cluster mode") + @Operation(summary = "Creates a new Pulsar Function in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request (The Pulsar Function already exists, etc.)"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "Pulsar Function successfully created") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", + description = "Invalid request (The Pulsar Function already exists, etc.)"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully created") }) @Path("/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) public void registerFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, final @FormDataParam("data") InputStream uploadedInputStream, final @FormDataParam("data") FormDataContentDisposition fileDetail, final @FormDataParam("url") String functionPkgUrl, - @ApiParam( - value = "You can submit a function (in any languages that you are familiar with) \n" + @Parameter( + description = "You can submit a function (in any languages that you are familiar with) \n" + "to a Pulsar cluster. Follow the steps below. \n" + "1. Create a JSON object using some of the following parameters.\n" + "A JSON value presenting configuration payload of a Pulsar Function.\n" @@ -167,56 +169,34 @@ public void registerFunction( + "- **cleanupSubscription**\n" + " Whether the subscriptions of a Pulsar Function created or used should be deleted" + " when the Pulsar Function is deleted.\n" - + "2. Encapsulate the JSON object to a multipart object.", - examples = @Example( - value = { - @ExampleProperty( - mediaType = MediaType.TEXT_PLAIN, - value = """ - Examples - 1. Create a JSON object - { - "inputs": "persistent://public/default/input-topic", - "parallelism": "4", - "output": "persistent://public/default/output-topic", - "log-topic": "persistent://public/default/log-topic", - "classname": "org.example.test.ExclamationFunction", - "jar": "java-function-1.0-SNAPSHOT.jar" - } - 2. Encapsulate the JSON object to a multipart object (in Python) - from requests_toolbelt.multipart.encoder import MultipartEncoders - mp_encoder = MultipartEncoder([('functionConfig',(None, json.dumps(config),\ - 'application/json'))])""" - ) - } - ) - ) + + "2. Encapsulate the JSON object to a multipart object.") final @FormDataParam("functionConfig") FunctionConfig functionConfig) { functions().registerFunction(tenant, namespace, functionName, uploadedInputStream, fileDetail, functionPkgUrl, functionConfig, authParams()); } @PUT - @ApiOperation(value = "Updates a Pulsar Function currently running in cluster mode") + @Operation(summary = "Updates a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request (The Pulsar Function doesn't exist, etc.)"), - @ApiResponse(code = 200, message = "Pulsar Function successfully updated") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", + description = "Invalid request (The Pulsar Function doesn't exist, etc.)"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated") }) @Path("/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) public void updateFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, final @FormDataParam("data") InputStream uploadedInputStream, final @FormDataParam("data") FormDataContentDisposition fileDetail, final @FormDataParam("url") String functionPkgUrl, - @ApiParam( - value = "A JSON value presenting configuration payload of a Pulsar Function." + @Parameter( + description = "A JSON value presenting configuration payload of a Pulsar Function." + " An example of the expected Pulsar Function can be found here.\n" + "- **autoAck**\n" + " Whether or not the framework acknowledges messages automatically.\n" @@ -299,25 +279,9 @@ public void updateFunction( + " SecretProviderConfigurator.getSecretObjectType() method. \n" + "- **cleanupSubscription**\n" + " Whether the subscriptions of a Pulsar Function created or used" - + " should be deleted when the Pulsar Function is deleted.\n", - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.APPLICATION_JSON, - value = """ - { - "inputs": "persistent://public/default/input-topic", - "parallelism": 4, - "output": "persistent://public/default/output-topic", - "log-topic": "persistent://public/default/log-topic", - "classname": "org.example.test.ExclamationFunction", - "jar": "java-function-1.0-SNAPSHOT.jar" - } - """ - ) - ) - ) + + " should be deleted when the Pulsar Function is deleted.\n") final @FormDataParam("functionConfig") FunctionConfig functionConfig, - @ApiParam(value = "The update options is for the Pulsar Function that needs to be updated.") + @Parameter(description = "The update options is for the Pulsar Function that needs to be updated.") final @FormDataParam("updateOptions") UpdateOptionsImpl updateOptions) throws IOException { functions().updateFunction(tenant, namespace, functionName, uploadedInputStream, fileDetail, @@ -326,65 +290,72 @@ public void updateFunction( @DELETE - @ApiOperation(value = "Deletes a Pulsar Function currently running in cluster mode") + @Operation(summary = "Deletes a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function doesn't exist"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "The Pulsar Function was successfully deleted") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function doesn't exist"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "The Pulsar Function was successfully deleted") }) @Path("/{tenant}/{namespace}/{functionName}") public void deregisterFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) { functions().deregisterFunction(tenant, namespace, functionName, authParams()); } @GET - @ApiOperation( - value = "Fetches information about a Pulsar Function currently running in cluster mode", - response = FunctionConfig.class + @Operation( + summary = "Fetches information about a Pulsar Function currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 404, message = "The Pulsar Function doesn't exist") + @ApiResponse(responseCode = "200", + description = "Fetches information about a Pulsar Function currently running in cluster mode", + content = @Content(schema = @Schema(implementation = FunctionConfig.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function doesn't exist") }) @Path("/{tenant}/{namespace}/{functionName}") public FunctionConfig getFunctionInfo( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) throws IOException { return functions().getFunctionInfo(tenant, namespace, functionName, authParams()); } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function instance", - response = FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData.class + @Operation( + summary = "Displays the status of a Pulsar Function instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The Pulsar Function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Function instance", + content = @Content(schema = @Schema( + implementation = FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/status") public FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData getFunctionInstanceStatus( - @ApiParam(value = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = "The instanceId of a Pulsar Function (if instance-id is not provided," + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Function") + final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Function") + final @PathParam("functionName") String functionName, + @Parameter(description = "The instanceId of a Pulsar Function (if instance-id is not provided," + " the stats of all instances is returned") final @PathParam("instanceId") String instanceId) throws IOException { return functions().getFunctionInstanceStatus(tenant, namespace, functionName, @@ -392,71 +363,79 @@ public FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData getFunct } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function", - response = FunctionStatus.class + @Operation( + summary = "Displays the status of a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The Pulsar Function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Function", + content = @Content(schema = @Schema(implementation = FunctionStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/status") public FunctionStatus getFunctionStatus( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) throws IOException { return functions().getFunctionStatus(tenant, namespace, functionName, uri.getRequestUri(), authParams()); } @GET - @ApiOperation( - value = "Displays the stats of a Pulsar Function", - response = FunctionStatsImpl.class + @Operation( + summary = "Displays the stats of a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The Pulsar Function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the stats of a Pulsar Function", + content = @Content(schema = @Schema(implementation = FunctionStatsImpl.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/stats") public FunctionStatsImpl getFunctionStats( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) throws IOException { return functions().getFunctionStats(tenant, namespace, functionName, uri.getRequestUri(), authParams()); } @GET - @ApiOperation( - value = "Displays the stats of a Pulsar Function instance", - response = FunctionInstanceStatsDataImpl.class + @Operation( + summary = "Displays the stats of a Pulsar Function instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The Pulsar Function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the stats of a Pulsar Function instance", + content = @Content(schema = @Schema(implementation = FunctionInstanceStatsDataImpl.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/stats") public FunctionInstanceStatsDataImpl getFunctionInstanceStats( - @ApiParam(value = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = "The instanceId of a Pulsar Function" + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Function") + final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Function") + final @PathParam("functionName") String functionName, + @Parameter(description = "The instanceId of a Pulsar Function" + " (if instance-id is not provided, the stats of all instances is returned") final @PathParam( "instanceId") String instanceId) throws IOException { return functions().getFunctionsInstanceStats(tenant, namespace, functionName, instanceId, @@ -464,47 +443,52 @@ public FunctionInstanceStatsDataImpl getFunctionInstanceStats( } @GET - @ApiOperation( - value = "Lists all Pulsar Functions currently deployed in a given namespace", - response = String.class, - responseContainer = "Collection" + @Operation( + summary = "Lists all Pulsar Functions currently deployed in a given namespace" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions") + @ApiResponse(responseCode = "200", + description = "Lists all Pulsar Functions currently deployed in a given namespace", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions") }) @Path("/{tenant}/{namespace}") public List listFunctions( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace) { return functions().listFunctions(tenant, namespace, authParams()); } @POST - @ApiOperation( - value = "Triggers a Pulsar Function with a user-specified value or file data", - response = String.class + @Operation( + summary = "Triggers a Pulsar Function with a user-specified value or file data" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Triggers a Pulsar Function with a user-specified value or file data", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/trigger") @Consumes(MediaType.MULTIPART_FORM_DATA) public String triggerFunction( - @ApiParam(value = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = "The value with which you want to trigger the Pulsar Function") final @FormDataParam( - "data") String triggerValue, - @ApiParam(value = "The path to the file that contains the data with" + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Function") + final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Function") + final @PathParam("functionName") String functionName, + @Parameter(description = "The value with which you want to trigger the Pulsar Function") + final @FormDataParam("data") String triggerValue, + @Parameter(description = "The path to the file that contains the data with" + " which you'd like to trigger the Pulsar Function") final @FormDataParam("dataStream") InputStream triggerStream, - @ApiParam(value = "The specific topic name that the Pulsar Function" + @Parameter(description = "The specific topic name that the Pulsar Function" + " consumes from which you want to inject the data to") final @FormDataParam("topic") String topic) { return functions().triggerFunction(tenant, namespace, functionName, triggerValue, @@ -512,39 +496,40 @@ public String triggerFunction( } @GET - @ApiOperation( - value = "Fetch the current state associated with a Pulsar Function", - response = FunctionState.class + @Operation( + summary = "Fetch the current state associated with a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The key does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Fetch the current state associated with a Pulsar Function", + content = @Content(schema = @Schema(implementation = FunctionState.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The key does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/state/{key}") public FunctionState getFunctionState( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = "The stats key") + @Parameter(description = "The stats key") final @PathParam("key") String key) { return functions().getFunctionState(tenant, namespace, functionName, key, authParams()); } @POST - @ApiOperation( - value = "Put the state associated with a Pulsar Function" + @Operation( + summary = "Put the state associated with a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/state/{key}") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -557,21 +542,24 @@ public void putFunctionState(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart an instance of a Pulsar Function") + @Operation(summary = "Restart an instance of a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartFunction( - @ApiParam(value = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Function") + final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Function") + final @PathParam("functionName") String functionName, + @Parameter(description = "The instanceId of a Pulsar Function (if instance-id is not provided, all instances are restarted") final @PathParam("instanceId") String instanceId) { functions().restartFunctionInstance(tenant, namespace, functionName, instanceId, @@ -579,40 +567,42 @@ public void restartFunction( } @POST - @ApiOperation(value = "Restart all instances of a Pulsar Function") + @Operation(summary = "Restart all instances of a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) { functions().restartFunctionInstances(tenant, namespace, functionName, authParams()); } @POST - @ApiOperation(value = "Stop an instance of a Pulsar Function") + @Operation(summary = "Stop an instance of a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopFunction( - @ApiParam(value = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Function") + final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Function") + final @PathParam("functionName") String functionName, + @Parameter(description = "The instanceId of a Pulsar Function (if instance-id is not provided, all instances are stopped. ") final @PathParam("instanceId") String instanceId) { functions().stopFunctionInstance(tenant, namespace, functionName, instanceId, @@ -620,40 +610,42 @@ public void stopFunction( } @POST - @ApiOperation(value = "Stop all instances of a Pulsar Function") + @Operation(summary = "Stop all instances of a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) { functions().stopFunctionInstances(tenant, namespace, functionName, authParams()); } @POST - @ApiOperation(value = "Start an instance of a Pulsar Function") + @Operation(summary = "Start an instance of a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/start") @Consumes(MediaType.APPLICATION_JSON) public void startFunction( - @ApiParam(value = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = "The instanceId of a Pulsar Function" + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Function") + final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Function") + final @PathParam("functionName") String functionName, + @Parameter(description = "The instanceId of a Pulsar Function" + " (if instance-id is not provided, all instances sre started. ") final @PathParam("instanceId") String instanceId) { functions().startFunctionInstance(tenant, namespace, functionName, instanceId, @@ -661,28 +653,28 @@ public void startFunction( } @POST - @ApiOperation(value = "Start all instances of a Pulsar Function") + @Operation(summary = "Start all instances of a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/start") @Consumes(MediaType.APPLICATION_JSON) public void startFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName) { functions().startFunctionInstances(tenant, namespace, functionName, authParams()); } @POST - @ApiOperation( - value = "Uploads Pulsar Function file data (Admin only)", + @Operation( + summary = "Uploads Pulsar Function file data (Admin only)", hidden = true ) @Path("/upload") @@ -693,8 +685,8 @@ public void uploadFunction(final @FormDataParam("data") InputStream uploadedInpu } @GET - @ApiOperation( - value = "Downloads Pulsar Function file data (Admin only)", + @Operation( + summary = "Downloads Pulsar Function file data (Admin only)", hidden = true ) @Path("/download") @@ -703,34 +695,36 @@ public StreamingOutput downloadFunction(final @QueryParam("path") String path) { } @GET - @ApiOperation( - value = "Downloads Pulsar Function file data", + @Operation( + summary = "Downloads Pulsar Function file data", hidden = true ) @Path("/{tenant}/{namespace}/{functionName}/download") public StreamingOutput downloadFunction( - @ApiParam(value = "The tenant of a Pulsar Function") + @Parameter(description = "The tenant of a Pulsar Function") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Function") + @Parameter(description = "The namespace of a Pulsar Function") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Function") + @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, - @ApiParam(value = "Whether to download the transform-function") + @Parameter(description = "Whether to download the transform-function") final @QueryParam("transform-function") boolean transformFunction) { return functions().downloadFunction(tenant, namespace, functionName, authParams(), transformFunction); } @GET - @ApiOperation( - value = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", - response = ConnectorDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", + description = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", + content = @Content(array = + @ArraySchema(schema = @Schema(implementation = ConnectorDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/connectors") @Deprecated @@ -742,14 +736,15 @@ public List getConnectorsList() throws IOException { } @POST - @ApiOperation( - value = "Reload the built-in Functions" + @Operation( + summary = "Reload the built-in Functions" ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/builtins/reload") public void reloadBuiltinFunctions() throws IOException { @@ -757,15 +752,16 @@ public void reloadBuiltinFunctions() throws IOException { } @GET - @ApiOperation( - value = "Fetches the list of built-in Pulsar functions", - response = FunctionDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches the list of built-in Pulsar functions" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", description = "Fetches the list of built-in Pulsar functions", + content = @Content(array = + @ArraySchema(schema = @Schema(implementation = FunctionDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/builtins") @Produces(MediaType.APPLICATION_JSON) @@ -774,14 +770,14 @@ public List getBuiltinFunction() { } @PUT - @ApiOperation(value = "Updates a Pulsar Function on the worker leader", hidden = true) + @Operation(summary = "Updates a Pulsar Function on the worker leader", hidden = true) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "The requester doesn't have super-user permissions"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 307, message = "Redirecting to the worker leader"), - @ApiResponse(code = 200, message = "Pulsar Function successfully updated") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have super-user permissions"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "307", description = "Redirecting to the worker leader"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated") }) @Path("/leader/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/MetadataMigrationBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/MetadataMigrationBase.java index ee0e39ba2d7ee..fd4aaa3eb1f78 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/MetadataMigrationBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/MetadataMigrationBase.java @@ -18,10 +18,12 @@ */ package org.apache.pulsar.broker.admin.impl; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; @@ -41,10 +43,11 @@ public class MetadataMigrationBase extends AdminResource { @GET @Path("/status") - @ApiOperation(value = "Get current migration status", response = MigrationState.class) + @Operation(summary = "Get current migration status") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Migration status retrieved successfully"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Migration status retrieved successfully", + content = @Content(schema = @Schema(implementation = MigrationState.class))), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public MigrationState getStatus() { validateSuperUserAccess(); @@ -64,15 +67,15 @@ public MigrationState getStatus() { @POST @Path("/start") - @ApiOperation(value = "Start metadata store migration") + @Operation(summary = "Start metadata store migration") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Migration started successfully"), - @ApiResponse(code = 400, message = "Invalid target URL"), - @ApiResponse(code = 409, message = "Migration already in progress"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "204", description = "Migration started successfully"), + @ApiResponse(responseCode = "400", description = "Invalid target URL"), + @ApiResponse(responseCode = "409", description = "Migration already in progress"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void startMigration( - @ApiParam(value = "Target metadata store URL", required = true) + @Parameter(description = "Target metadata store URL", required = true) @QueryParam("target") String targetUrl) { validateSuperUserAccess(); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java index 5250f9dfe76ec..0f96ca799344e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java @@ -18,12 +18,14 @@ */ package org.apache.pulsar.broker.admin.impl; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -54,27 +56,29 @@ Sinks sinks() { } @POST - @ApiOperation(value = "Creates a new Pulsar Sink in cluster mode") + @Operation(summary = "Creates a new Pulsar Sink in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request (The Pulsar Sink already exists, etc.)"), - @ApiResponse(code = 200, message = "Pulsar Sink successfully created"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "400", description = "Invalid request (The Pulsar Sink already exists, etc.)"), + @ApiResponse(responseCode = "200", description = "Pulsar Sink successfully created"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to authorize," + " failed to get tenant data, failed to process package, etc.)"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}") @Consumes(MediaType.MULTIPART_FORM_DATA) - public void registerSink(@ApiParam(value = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") final @PathParam("namespace") + public void registerSink(@Parameter(description = "The tenant of a Pulsar Sink") + final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") final @PathParam("sinkName") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName, final @FormDataParam("data") InputStream uploadedInputStream, final @FormDataParam("data") FormDataContentDisposition fileDetail, final @FormDataParam("url") String sinkPkgUrl, - @ApiParam(value = + @Parameter(description = "You can submit a sink (in any languages that you are familiar with) " + "to a Pulsar cluster. Follow the steps below.\n" + "1. Create a JSON object using some of the following parameters.\n" @@ -141,10 +145,10 @@ public void registerSink(@ApiParam(value = "The tenant of a Pulsar Sink") final + "- **runtimeFlags**\n" + " Any flags that you want to pass to the runtime as a single string\n" + "2. Encapsulate the JSON object to a multipart object.", - examples = @Example( - value = { - @ExampleProperty( - mediaType = MediaType.TEXT_PLAIN, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema(implementation = SinkConfig.class), + examples = @ExampleObject( value = """ Example 1. Create a JSON object. @@ -162,8 +166,7 @@ public void registerSink(@ApiParam(value = "The tenant of a Pulsar Sink") final [('sinkConfig',\ (None, json.dumps(config), 'application/json'))]) """ - ) - } + ) ) ) final @FormDataParam("sinkConfig") SinkConfig sinkConfig) { @@ -172,27 +175,30 @@ public void registerSink(@ApiParam(value = "The tenant of a Pulsar Sink") final } @PUT - @ApiOperation(value = "Updates a Pulsar Sink currently running in cluster mode") + @Operation(summary = "Updates a Pulsar Sink currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 400, message = + @ApiResponse(responseCode = "400", description = "Invalid request (The Pulsar Sink doesn't exist, update contains no change, etc.)"), - @ApiResponse(code = 200, message = "Pulsar Sink successfully updated"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "The Pulsar Sink doesn't exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Pulsar Sink successfully updated"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to authorize, failed to process package, etc.)"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}") @Consumes(MediaType.MULTIPART_FORM_DATA) - public void updateSink(@ApiParam(value = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") final @PathParam("namespace") + public void updateSink(@Parameter(description = "The tenant of a Pulsar Sink") + final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName, + @Parameter(description = "The name of a Pulsar Sink") + final @PathParam("sinkName") String sinkName, final @FormDataParam("data") InputStream uploadedInputStream, final @FormDataParam("data") FormDataContentDisposition fileDetail, final @FormDataParam("url") String sinkPkgUrl, - @ApiParam(value = + @Parameter(description = "A JSON value presenting config payload of a Pulsar Sink." + " All available configuration options are:\n" + "- **classname**\n" @@ -253,9 +259,10 @@ public void updateSink(@ApiParam(value = "The tenant of a Pulsar Sink") final @P + " created/used should be deleted when the functions is deleted\n" + "- **runtimeFlags**\n" + " Any flags that you want to pass to the runtime as a single string\n", - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.APPLICATION_JSON, + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = SinkConfig.class), + examples = @ExampleObject( value = """ { "classname": "org.example.SinkStressTest", @@ -268,7 +275,7 @@ public void updateSink(@ApiParam(value = "The tenant of a Pulsar Sink") final @P ) ) final @FormDataParam("sinkConfig") SinkConfig sinkConfig, - @ApiParam(value = "Update options for the Pulsar Sink") + @Parameter(description = "Update options for the Pulsar Sink") final @FormDataParam("updateOptions") UpdateOptionsImpl updateOptions) { sinks().updateSink(tenant, namespace, sinkName, uploadedInputStream, fileDetail, sinkPkgUrl, sinkConfig, authParams(), updateOptions); @@ -277,268 +284,288 @@ public void updateSink(@ApiParam(value = "The tenant of a Pulsar Sink") final @P @DELETE - @ApiOperation(value = "Deletes a Pulsar Sink currently running in cluster mode") + @Operation(summary = "Deletes a Pulsar Sink currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid deregister request"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 200, message = "The Pulsar Sink was successfully deleted"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "400", description = "Invalid deregister request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "200", description = "The Pulsar Sink was successfully deleted"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to authorize, failed to deregister, etc.)"), - @ApiResponse(code = 408, message = "Got InterruptedException while deregistering the Pulsar Sink"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "408", + description = "Got InterruptedException while deregistering the Pulsar Sink"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}") - public void deregisterSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void deregisterSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName) { sinks().deregisterFunction(tenant, namespace, sinkName, authParams()); } @GET - @ApiOperation( - value = "Fetches information about a Pulsar Sink currently running in cluster mode", - response = SinkConfig.class + @Operation( + summary = "Fetches information about a Pulsar Sink currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Fetches information about a Pulsar Sink currently running in cluster mode", + content = @Content(schema = @Schema(implementation = SinkConfig.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}") - public SinkConfig getSinkInfo(@ApiParam(value = "The tenant of a Pulsar Sink") + public SinkConfig getSinkInfo(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName) throws IOException { return sinks().getSinkInfo(tenant, namespace, sinkName, authParams()); } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Sink instance", - response = SinkStatus.SinkInstanceStatus.SinkInstanceStatusData.class + @Operation( + summary = "Displays the status of a Pulsar Sink instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this sink"), - @ApiResponse(code = 400, message = "The Pulsar Sink instance does not exist"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 500, message = "Internal Server Error (got exception while getting status, etc.)"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Sink instance", + content = @Content(schema = + @Schema(implementation = SinkStatus.SinkInstanceStatus.SinkInstanceStatusData.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this sink"), + @ApiResponse(responseCode = "400", description = "The Pulsar Sink instance does not exist"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "500", + description = "Internal Server Error (got exception while getting status, etc.)"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/status") public SinkStatus.SinkInstanceStatus.SinkInstanceStatusData getSinkInstanceStatus( - @ApiParam(value = "The tenant of a Pulsar Sink") + @Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName, - @ApiParam(value = "The instanceId of a Pulsar Sink") + @Parameter(description = "The instanceId of a Pulsar Sink") final @PathParam("instanceId") String instanceId) throws IOException { return sinks().getSinkInstanceStatus( tenant, namespace, sinkName, instanceId, uri.getRequestUri(), authParams()); } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Sink running in cluster mode", - response = SinkStatus.class + @Operation( + summary = "Displays the status of a Pulsar Sink running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this sink"), - @ApiResponse(code = 400, message = "Invalid get status request"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Sink running in" + + " cluster mode", + content = @Content(schema = @Schema(implementation = SinkStatus.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this sink"), + @ApiResponse(responseCode = "400", description = "Invalid get status request"), + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sinkName}/status") - public SinkStatus getSinkStatus(@ApiParam(value = "The tenant of a Pulsar Sink") + public SinkStatus getSinkStatus(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName) throws IOException { return sinks().getSinkStatus(tenant, namespace, sinkName, uri.getRequestUri(), authParams()); } @GET - @ApiOperation( - value = "Lists all Pulsar Sinks currently deployed in a given namespace", - response = String.class, - responseContainer = "Collection" + @Operation( + summary = "Lists all Pulsar Sinks currently deployed in a given namespace" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid list request"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 500, message = "Internal server error (failed to authorize, etc.)"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Lists all Pulsar Sinks currently deployed in a given namespace", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "400", description = "Invalid list request"), + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to authorize, etc.)"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}") - public List listSinks(@ApiParam(value = "The tenant of a Pulsar Sink") + public List listSinks(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace) { return sinks().listFunctions(tenant, namespace, authParams()); } @POST - @ApiOperation(value = "Restart an instance of a Pulsar Sink") + @Operation(summary = "Restart an instance of a Pulsar Sink") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this sink"), - @ApiResponse(code = 400, message = "Invalid restart request"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this sink"), + @ApiResponse(responseCode = "400", description = "Invalid restart request"), + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to restart the instance of" + " a Pulsar Sink, failed to authorize, etc.)"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) - public void restartSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void restartSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName, - @ApiParam(value = "The instanceId of a Pulsar Sink") + @Parameter(description = "The instanceId of a Pulsar Sink") final @PathParam("instanceId") String instanceId) { sinks().restartFunctionInstance(tenant, namespace, sinkName, instanceId, uri.getRequestUri(), authParams()); } @POST - @ApiOperation(value = "Restart all instances of a Pulsar Sink") + @Operation(summary = "Restart all instances of a Pulsar Sink") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid restart request"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid restart request"), + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to restart the Pulsar Sink, failed to authorize, etc.)"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}/restart") @Consumes(MediaType.APPLICATION_JSON) - public void restartSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void restartSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName) { sinks().restartFunctionInstances(tenant, namespace, sinkName, authParams()); } @POST - @ApiOperation(value = "Stop an instance of a Pulsar Sink") + @Operation(summary = "Stop an instance of a Pulsar Sink") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid stop request"), - @ApiResponse(code = 404, message = "The Pulsar Sink instance does not exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid stop request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink instance does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to stop the Pulsar Sink, failed to authorize, etc.)"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) - public void stopSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void stopSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName, - @ApiParam(value = "The instanceId of a Pulsar Sink") + @Parameter(description = "The instanceId of a Pulsar Sink") final @PathParam("instanceId") String instanceId) { sinks().stopFunctionInstance(tenant, namespace, sinkName, instanceId, uri.getRequestUri(), authParams()); } @POST - @ApiOperation(value = "Stop all instances of a Pulsar Sink") + @Operation(summary = "Stop all instances of a Pulsar Sink") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid stop request"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid stop request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to stop the Pulsar Sink, failed to authorize, etc.)"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}/stop") @Consumes(MediaType.APPLICATION_JSON) - public void stopSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void stopSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName) { sinks().stopFunctionInstances(tenant, namespace, sinkName, authParams()); } @POST - @ApiOperation(value = "Start an instance of a Pulsar Sink") + @Operation(summary = "Start an instance of a Pulsar Sink") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid start request"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid start request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to start the Pulsar Sink, failed to authorize, etc.)"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/start") @Consumes(MediaType.APPLICATION_JSON) - public void startSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void startSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName, - @ApiParam(value = "The instanceId of a Pulsar Sink") + @Parameter(description = "The instanceId of a Pulsar Sink") final @PathParam("instanceId") String instanceId) { sinks().startFunctionInstance(tenant, namespace, sinkName, instanceId, uri.getRequestUri(), authParams()); } @POST - @ApiOperation(value = "Start all instances of a Pulsar Sink") + @Operation(summary = "Start all instances of a Pulsar Sink") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid start request"), - @ApiResponse(code = 404, message = "The Pulsar Sink does not exist"), - @ApiResponse(code = 500, message = + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid start request"), + @ApiResponse(responseCode = "404", description = "The Pulsar Sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error (failed to start the Pulsar Sink, failed to authorize, etc.)"), - @ApiResponse(code = 401, message = "The client is not authorized to perform this operation"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "The client is not authorized to perform this operation"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sinkName}/start") @Consumes(MediaType.APPLICATION_JSON) - public void startSink(@ApiParam(value = "The tenant of a Pulsar Sink") + public void startSink(@Parameter(description = "The tenant of a Pulsar Sink") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Sink") + @Parameter(description = "The namespace of a Pulsar Sink") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Sink") + @Parameter(description = "The name of a Pulsar Sink") final @PathParam("sinkName") String sinkName) { sinks().startFunctionInstances(tenant, namespace, sinkName, authParams()); } @GET - @ApiOperation( - value = "Fetches the list of built-in Pulsar IO sinks", - response = ConnectorDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches the list of built-in Pulsar IO sinks" ) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Get builtin sinks successfully.") + @ApiResponse(responseCode = "200", description = "Get builtin sinks successfully.", + content = @Content(array = + @ArraySchema(schema = @Schema(implementation = ConnectorDefinition.class)))) }) @Path("/builtinsinks") public List getSinkList() { @@ -546,34 +573,40 @@ public List getSinkList() { } @GET - @ApiOperation( - value = "Fetches information about config fields associated with the specified builtin sink", - response = ConfigFieldDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches information about config fields associated with the specified builtin sink" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "builtin sink does not exist"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Fetches information about config fields associated with the specified builtin sink", + content = @Content(array = + @ArraySchema(schema = @Schema(implementation = ConfigFieldDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "builtin sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/builtinsinks/{name}/configdefinition") public List getSinkConfigDefinition( - @ApiParam(value = "The name of the builtin sink") + @Parameter(description = "The name of the builtin sink") final @PathParam("name") String name) throws IOException { return sinks().getSinkConfigDefinition(name); } @POST - @ApiOperation( - value = "Reload the built-in connectors, including Sources and Sinks", - response = Void.class + @Operation( + summary = "Reload the built-in connectors, including Sources and Sinks" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Reload the built-in connectors, including Sources and Sinks", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/reloadBuiltInSinks") public void reloadSinks() { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java index 1295ea0cb6bd5..0961d256c18f0 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java @@ -18,12 +18,13 @@ */ package org.apache.pulsar.broker.admin.impl; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -54,29 +55,30 @@ Sources sources() { } @POST - @ApiOperation(value = "Creates a new Pulsar Source in cluster mode") + @Operation(summary = "Creates a new Pulsar Source in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Pulsar Function successfully created"), - @ApiResponse(code = 400, message = + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully created"), + @ApiResponse(responseCode = "400", description = "Invalid request (Function already exists or Tenant, Namespace or Name is not provided, etc.)"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 500, message = "Internal Server Error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}") @Consumes(MediaType.MULTIPART_FORM_DATA) public void registerSource( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, final @FormDataParam("data") InputStream uploadedInputStream, final @FormDataParam("data") FormDataContentDisposition fileDetail, final @FormDataParam("url") String sourcePkgUrl, - @ApiParam(value = + @Parameter(description = "You can submit a source (in any languages that you are familiar with) to a Pulsar cluster. " + "Follow the steps below.\n" + "1. Create a JSON object using some of the following parameters.\n" @@ -115,62 +117,39 @@ public void registerSource( + " from which worker can download the package.\n" + "- **runtimeFlags**\n" + " Any flags that you want to pass to the runtime.\n" - + "2. Encapsulate the JSON object to a multipart object.", - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.TEXT_PLAIN, - value = """ - Example - 1. Create a JSON object. - { - "tenant": "public", - "namespace": "default", - "name": "pulsar-io-mysql", - "className": "TestSourceMysql", - "topicName": "pulsar-io-mysql", - "parallelism": "1", - "archive": "/connectors/pulsar-io-mysql-0.0.1.nar", - "schemaType": "avro" - } - 2. Encapsulate the JSON object to a multipart object (in Python). - from requests_toolbelt.multipart.encoder import MultipartEncoder - mp_encoder = MultipartEncoder([('sourceConfig', \ - (None, json.dumps(config), 'application/json'))]) - """ - ) - ) - ) + + "2. Encapsulate the JSON object to a multipart object.") final @FormDataParam("sourceConfig") SourceConfig sourceConfig) { sources().registerSource(tenant, namespace, sourceName, uploadedInputStream, fileDetail, sourcePkgUrl, sourceConfig, authParams()); } @PUT - @ApiOperation(value = "Updates a Pulsar Source currently running in cluster mode") + @Operation(summary = "Updates a Pulsar Source currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request (Function already exists or Tenant, Namespace or Name is not provided, etc.)"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 200, message = "Pulsar Function successfully updated"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal Server Error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}") @Consumes(MediaType.MULTIPART_FORM_DATA) public void updateSource( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, final @FormDataParam("data") InputStream uploadedInputStream, final @FormDataParam("data") FormDataContentDisposition fileDetail, final @FormDataParam("url") String sourcePkgUrl, - @ApiParam( - value = "A JSON value presenting configuration payload of a Pulsar Source." + @Parameter( + description = "A JSON value presenting configuration payload of a Pulsar Source." + " An example of the expected functions can be found here.\n" + "- **classname**\n" + " The class name of a Pulsar Source if archive is file-url-path (file://).\n" @@ -204,27 +183,9 @@ public void updateSource( + " [http/https/file (file protocol assumes that file already exists on worker host)] " + " from which worker can download the package.\n" + "- **runtimeFlags**\n" - + " Any flags that you want to pass to the runtime.\n", - examples = @Example( - value = @ExampleProperty( - mediaType = MediaType.APPLICATION_JSON, - value = """ - { - "tenant": "public", - "namespace": "default", - "name": "pulsar-io-mysql", - "className": "TestSourceMysql", - "topicName": "pulsar-io-mysql", - "parallelism": 1, - "archive": "/connectors/pulsar-io-mysql-0.0.1.nar", - "schemaType": "avro" - } - """ - ) - ) - ) + + " Any flags that you want to pass to the runtime.\n") final @FormDataParam("sourceConfig") SourceConfig sourceConfig, - @ApiParam(value = "Update options for Pulsar Source") + @Parameter(description = "Update options for Pulsar Source") final @FormDataParam("updateOptions") UpdateOptionsImpl updateOptions) { sources().updateSource(tenant, namespace, sourceName, uploadedInputStream, fileDetail, sourcePkgUrl, sourceConfig, authParams(), updateOptions); @@ -232,65 +193,74 @@ public void updateSource( @DELETE - @ApiOperation(value = "Deletes a Pulsar Source currently running in cluster mode") + @Operation(summary = "Deletes a Pulsar Source currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "The function was successfully deleted"), - @ApiResponse(code = 500, message = "Internal Server Error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "The function was successfully deleted"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}") public void deregisterSource( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName) { sources().deregisterFunction(tenant, namespace, sourceName, authParams()); } @GET - @ApiOperation( - value = "Fetches information about a Pulsar Source currently running in cluster mode", - response = SourceConfig.class + @Operation( + summary = "Fetches information about a Pulsar Source currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Fetches information about a Pulsar Source currently running in cluster mode", + content = @Content(schema = @Schema(implementation = SourceConfig.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}") public SourceConfig getSourceInfo( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName) throws IOException { return sources().getSourceInfo(tenant, namespace, sourceName, authParams()); } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Source instance", - response = SourceStatus.SourceInstanceStatus.SourceInstanceStatusData.class + @Operation( + summary = "Displays the status of a Pulsar Source instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this source"), - @ApiResponse(code = 500, message = "Internal Server Error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Source instance", + content = @Content(schema = @Schema( + implementation = SourceStatus.SourceInstanceStatus.SourceInstanceStatusData.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this source"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/status") public SourceStatus.SourceInstanceStatus.SourceInstanceStatusData getSourceInstanceStatus( - @ApiParam(value = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, - @ApiParam(value = "The instanceId of a Pulsar Source" + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, + @Parameter(description = "The instanceId of a Pulsar Source" + " (if instance-id is not provided, the stats of all instances is returned).") final @PathParam( "instanceId") String instanceId) throws IOException { return sources().getSourceInstanceStatus( @@ -298,67 +268,75 @@ public SourceStatus.SourceInstanceStatus.SourceInstanceStatusData getSourceInsta } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Source running in cluster mode", - response = SourceStatus.class + @Operation( + summary = "Displays the status of a Pulsar Source running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this source"), - @ApiResponse(code = 500, message = "Internal Server Error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Source running in cluster mode", + content = @Content(schema = @Schema(implementation = SourceStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this source"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sourceName}/status") public SourceStatus getSourceStatus( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName) throws IOException { return sources().getSourceStatus(tenant, namespace, sourceName, uri.getRequestUri(), authParams()); } @GET - @ApiOperation( - value = "Lists all Pulsar Sources currently deployed in a given namespace", - response = String.class, - responseContainer = "List" + @Operation( + summary = "Lists all Pulsar Sources currently deployed in a given namespace" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 500, message = "Internal Server Error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Lists all Pulsar Sources currently deployed in a given namespace", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Consumes(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}") public List listSources( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace) { return sources().listFunctions(tenant, namespace, authParams()); } @POST - @ApiOperation(value = "Restart an instance of a Pulsar Source") + @Operation(summary = "Restart an instance of a Pulsar Source") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this source"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this source"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartSource( - @ApiParam(value = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, - @ApiParam(value = "The instanceId of a Pulsar Source" + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, + @Parameter(description = "The instanceId of a Pulsar Source" + " (if instance-id is not provided, the stats of all instances is returned).") final @PathParam( "instanceId") String instanceId) { sources().restartFunctionInstance(tenant, namespace, sourceName, instanceId, @@ -366,126 +344,134 @@ public void restartSource( } @POST - @ApiOperation(value = "Restart all instances of a Pulsar Source") + @Operation(summary = "Restart all instances of a Pulsar Source") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartSource( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName) { sources().restartFunctionInstances(tenant, namespace, sourceName, authParams()); } @POST - @ApiOperation(value = "Stop instance of a Pulsar Source") + @Operation(summary = "Stop instance of a Pulsar Source") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopSource( - @ApiParam(value = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, - @ApiParam(value = "The instanceId of a Pulsar Source (if instance-id is not provided," + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, + @Parameter(description = "The instanceId of a Pulsar Source (if instance-id is not provided," + " the stats of all instances is returned).") final @PathParam("instanceId") String instanceId) { sources().stopFunctionInstance(tenant, namespace, sourceName, instanceId, uri.getRequestUri(), authParams()); } @POST - @ApiOperation(value = "Stop all instances of a Pulsar Source") + @Operation(summary = "Stop all instances of a Pulsar Source") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopSource( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName) { sources().stopFunctionInstances(tenant, namespace, sourceName, authParams()); } @POST - @ApiOperation(value = "Start an instance of a Pulsar Source") + @Operation(summary = "Start an instance of a Pulsar Source") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/start") @Consumes(MediaType.APPLICATION_JSON) public void startSource( - @ApiParam(value = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, - @ApiParam(value = "The instanceId of a Pulsar Source (if instance-id is not provided," + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName, + @Parameter(description = "The instanceId of a Pulsar Source (if instance-id is not provided," + " the stats of all instances is returned).") final @PathParam("instanceId") String instanceId) { sources().startFunctionInstance(tenant, namespace, sourceName, instanceId, uri.getRequestUri(), authParams()); } @POST - @ApiOperation(value = "Start all instances of a Pulsar Source") + @Operation(summary = "Start all instances of a Pulsar Source") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "Not Found(The Pulsar Source doesn't exist)"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Path("/{tenant}/{namespace}/{sourceName}/start") @Consumes(MediaType.APPLICATION_JSON) public void startSource( - @ApiParam(value = "The tenant of a Pulsar Source") + @Parameter(description = "The tenant of a Pulsar Source") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of a Pulsar Source") + @Parameter(description = "The namespace of a Pulsar Source") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of a Pulsar Source") + @Parameter(description = "The name of a Pulsar Source") final @PathParam("sourceName") String sourceName) { sources().startFunctionInstances(tenant, namespace, sourceName, authParams()); } @GET - @ApiOperation( - value = "Fetches the list of built-in Pulsar IO sources", - response = ConnectorDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches the list of built-in Pulsar IO sources" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Fetches the list of built-in Pulsar IO sources", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = ConnectorDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/builtinsources") @@ -494,34 +480,41 @@ public List getSourceList() { } @GET - @ApiOperation( - value = "Fetches information about config fields associated with the specified builtin source", - response = ConfigFieldDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches information about config fields associated with the specified builtin source" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "builtin source does not exist"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = + "Fetches information about config fields associated with the specified builtin source", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = ConfigFieldDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "builtin source does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/builtinsources/{name}/configdefinition") public List getSourceConfigDefinition( - @ApiParam(value = "The name of the builtin source") + @Parameter(description = "The name of the builtin source") final @PathParam("name") String name) throws IOException { return sources().getSourceConfigDefinition(name); } @POST - @ApiOperation( - value = "Reload the built-in connectors, including Sources and Sinks", - response = Void.class + @Operation( + summary = "Reload the built-in connectors, including Sources and Sinks" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Reload the built-in connectors, including Sources and Sinks", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/reloadBuiltInSources") public void reloadSources() { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java index 36546c31a9cb1..3121675c435bb 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TenantsBase.java @@ -18,10 +18,14 @@ */ package org.apache.pulsar.broker.admin.impl; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; @@ -52,9 +56,12 @@ public class TenantsBase extends PulsarWebResource { @GET - @ApiOperation(value = "Get the list of existing tenants.", response = String.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "Tenant doesn't exist")}) + @Operation(summary = "Get the list of existing tenants.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the list of existing tenants.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "Tenant doesn't exist")}) public void getTenants(@Suspended final AsyncResponse asyncResponse) { final String clientAppId = clientAppId(); validateBothSuperUserAndTenantOperation(null, TenantOperation.LIST_TENANTS) @@ -73,11 +80,14 @@ public void getTenants(@Suspended final AsyncResponse asyncResponse) { @GET @Path("/{tenant}") - @ApiOperation(value = "Get the admin configuration for a given tenant.", response = TenantInfo.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "Tenant does not exist")}) + @Operation(summary = "Get the admin configuration for a given tenant.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the admin configuration for a given tenant.", + content = @Content(schema = @Schema(implementation = TenantInfo.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "Tenant does not exist")}) public void getTenantAdmin(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "The tenant name") @PathParam("tenant") String tenant) { + @Parameter(description = "The tenant name") @PathParam("tenant") String tenant) { final String clientAppId = clientAppId(); validateBothSuperUserAndTenantOperation(tenant, TenantOperation.GET_TENANT) .thenCompose(__ -> tenantResources().getTenantAsync(tenant)) @@ -97,17 +107,17 @@ public void getTenantAdmin(@Suspended final AsyncResponse asyncResponse, @PUT @Path("/{tenant}") - @ApiOperation(value = "Create a new tenant.", notes = "This operation requires Pulsar super-user privileges.") + @Operation(summary = "Create a new tenant.", description = "This operation requires Pulsar super-user privileges.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 409, message = "Tenant already exists"), - @ApiResponse(code = 412, message = "Tenant name is not valid"), - @ApiResponse(code = 412, message = "Clusters can not be empty"), - @ApiResponse(code = 412, message = "Clusters do not exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "409", description = "Tenant already exists"), + @ApiResponse(responseCode = "412", description = "Tenant name is not valid"), + @ApiResponse(responseCode = "412", description = "Clusters can not be empty"), + @ApiResponse(responseCode = "412", description = "Clusters do not exist")}) public void createTenant(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "The tenant name") @PathParam("tenant") String tenant, - @ApiParam(value = "TenantInfo") TenantInfoImpl tenantInfo) { + @Parameter(description = "The tenant name") @PathParam("tenant") String tenant, + @RequestBody(description = "TenantInfo") TenantInfoImpl tenantInfo) { final String clientAppId = clientAppId(); try { NamedEntity.checkName(tenant); @@ -157,18 +167,18 @@ public void createTenant(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}") - @ApiOperation(value = "Update the admins for a tenant.", - notes = "This operation requires Pulsar super-user privileges.") + @Operation(summary = "Update the admins for a tenant.", + description = "This operation requires Pulsar super-user privileges.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "Tenant does not exist"), - @ApiResponse(code = 409, message = "Tenant already exists"), - @ApiResponse(code = 412, message = "Clusters can not be empty"), - @ApiResponse(code = 412, message = "Clusters do not exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "Tenant does not exist"), + @ApiResponse(responseCode = "409", description = "Tenant already exists"), + @ApiResponse(responseCode = "412", description = "Clusters can not be empty"), + @ApiResponse(responseCode = "412", description = "Clusters do not exist")}) public void updateTenant(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "The tenant name") @PathParam("tenant") String tenant, - @ApiParam(value = "TenantInfo") TenantInfoImpl newTenantAdmin) { + @Parameter(description = "The tenant name") @PathParam("tenant") String tenant, + @RequestBody(description = "TenantInfo") TenantInfoImpl newTenantAdmin) { final String clientAppId = clientAppId(); validateBothSuperUserAndTenantOperation(tenant, TenantOperation.UPDATE_TENANT) .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync()) @@ -201,15 +211,15 @@ public void updateTenant(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}") - @ApiOperation(value = "Delete a tenant and all namespaces and topics under it.") + @Operation(summary = "Delete a tenant and all namespaces and topics under it.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "Tenant does not exist"), - @ApiResponse(code = 405, message = "Broker doesn't allow forced deletion of tenants"), - @ApiResponse(code = 409, message = "The tenant still has active namespaces")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "Tenant does not exist"), + @ApiResponse(responseCode = "405", description = "Broker doesn't allow forced deletion of tenants"), + @ApiResponse(responseCode = "409", description = "The tenant still has active namespaces")}) public void deleteTenant(@Suspended final AsyncResponse asyncResponse, - @PathParam("tenant") @ApiParam(value = "The tenant name") String tenant, + @PathParam("tenant") @Parameter(description = "The tenant name") String tenant, @QueryParam("force") @DefaultValue("false") boolean force) { final String clientAppId = clientAppId(); validateBothSuperUserAndTenantOperation(tenant, TenantOperation.DELETE_TENANT) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Bookies.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Bookies.java index 1a5512abf8abd..68fd237ec9492 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Bookies.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Bookies.java @@ -18,11 +18,14 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; @@ -52,7 +55,7 @@ import org.apache.pulsar.common.policies.data.RawBookieInfo; @Path("/bookies") -@Api(value = "/bookies", description = "Configure bookies rack placement", tags = "bookies") +@Tag(name = "bookies", description = "Configure bookies rack placement") @Produces(MediaType.APPLICATION_JSON) @SuppressWarnings("deprecation") public class Bookies extends AdminResource { @@ -60,9 +63,12 @@ public class Bookies extends AdminResource { @GET @Path("/racks-info") - @ApiOperation(value = "Gets the rack placement information for all the bookies in the cluster", - response = BookiesRackConfiguration.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission")}) + @Operation(summary = "Gets the rack placement information for all the bookies in the cluster") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Gets the rack placement information for all the bookies in the cluster", + content = @Content(schema = @Schema(implementation = BookiesRackConfiguration.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void getBookiesRackInfo(@Suspended final AsyncResponse asyncResponse) { validateSuperUserAccess(); @@ -77,9 +83,12 @@ public void getBookiesRackInfo(@Suspended final AsyncResponse asyncResponse) { @GET @Path("/all") - @ApiOperation(value = "Gets raw information for all the bookies in the cluster", - response = BookiesClusterInfo.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission")}) + @Operation(summary = "Gets raw information for all the bookies in the cluster") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Gets raw information for all the bookies in the cluster", + content = @Content(schema = @Schema(implementation = BookiesClusterInfo.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public BookiesClusterInfo getAllBookies() throws Exception { validateSuperUserAccess(); @@ -98,9 +107,12 @@ public BookiesClusterInfo getAllBookies() throws Exception { @GET @Path("/racks-info/{bookie}") - @ApiOperation(value = "Gets the rack placement information for a specific bookie in the cluster", - response = BookieInfo.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission")}) + @Operation(summary = "Gets the rack placement information for a specific bookie in the cluster") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Gets the rack placement information for a specific bookie in the cluster", + content = @Content(schema = @Schema(implementation = BookieInfo.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void getBookieRackInfo(@Suspended final AsyncResponse asyncResponse, @PathParam("bookie") String bookieAddress) throws Exception { validateSuperUserAccess(); @@ -123,10 +135,10 @@ public void getBookieRackInfo(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/racks-info/{bookie}") - @ApiOperation(value = "Removed the rack placement information for a specific bookie in the cluster") + @Operation(summary = "Removed the rack placement information for a specific bookie in the cluster") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void deleteBookieRackInfo(@Suspended final AsyncResponse asyncResponse, @PathParam("bookie") String bookieAddress) throws Exception { @@ -154,18 +166,18 @@ public void deleteBookieRackInfo(@Suspended final AsyncResponse asyncResponse, @POST @Path("/racks-info/{bookie}") - @ApiOperation(value = "Updates the rack placement information for a specific bookie in the cluster (note." + @Operation(summary = "Updates the rack placement information for a specific bookie in the cluster (note." + " bookie address format:`address:port`)") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission")} + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")} ) public void updateBookieRackInfo(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "The bookie address", required = true) + @Parameter(description = "The bookie address", required = true) @PathParam("bookie") String bookieAddress, - @ApiParam(value = "The group", required = true) + @Parameter(description = "The group", required = true) @QueryParam("group") String group, - @ApiParam(value = "The bookie info", required = true) + @RequestBody(description = "The bookie info", required = true) BookieInfo bookieInfo) throws Exception { validateSuperUserAccess(); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java index e0b148a0c7fe4..c54530b23448b 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java @@ -18,57 +18,59 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.StreamingOutput; -import java.io.OutputStream; import java.util.Collection; import java.util.Map; import org.apache.pulsar.broker.admin.impl.BrokerStatsBase; import org.apache.pulsar.broker.loadbalance.ResourceUnit; @Path("/broker-stats") -@Api(value = "/broker-stats", description = "Stats for broker", tags = "broker-stats") +@Tag(name = "broker-stats", description = "Stats for broker") @Produces(MediaType.APPLICATION_JSON) @SuppressWarnings("deprecation") public class BrokerStats extends BrokerStatsBase { @GET @Path("/topics") - @ApiOperation( - value = "Get all the topic stats by namespace", - response = OutputStream.class, - responseContainer = "OutputStream") - // https://github.com/swagger-api/swagger-ui/issues/558 - // map - // support - // missing - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation( + summary = "Get all the topic stats by namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get all the topic stats by namespace", + content = @Content(mediaType = "application/json", + schema = @Schema(type = "object", description = "Nested JSON object:" + + " namespace -> bundle range -> persistent/non-persistent -> topic -> stats"))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public StreamingOutput getTopics2() throws Exception { return super.getTopics2(); } @GET @Path("/broker-resource-availability/{tenant}/{namespace}") - @ApiOperation(value = "Broker availability report", notes = "This API gives the current broker availability in " + @Operation(summary = "Broker availability report", + description = "This API gives the current broker availability in " + "percent, each resource percentage usage is calculated and then" + "sum of all of the resource usage percent is called broker-resource-availability" - + "

THIS API IS ONLY FOR USE BY TESTING FOR CONFIRMING NAMESPACE ALLOCATION ALGORITHM", - response = ResourceUnit.class, responseContainer = "Map") + + "

THIS API IS ONLY FOR USE BY TESTING FOR CONFIRMING NAMESPACE ALLOCATION ALGORITHM") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Returns broker resource availability as Map>." + @ApiResponse(responseCode = "200", + description = "Returns broker resource availability as Map>." + "Since `ResourceUnit` is an interface, its specific content is not determinable via class " + "reflection. Refer to the source code or interface tests for detailed type definitions.", - response = Map.class), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 409, message = "Load-manager doesn't support operation") }) + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = ResourceUnit.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "409", description = "Load-manager doesn't support operation") }) public Map> getBrokerResourceAvailability(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java index 0390f20e4baa9..12bcd008648a5 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java @@ -18,15 +18,14 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import org.apache.pulsar.broker.admin.impl.BrokersBase; @Path("/brokers") -@Api(value = "/brokers", description = "BrokersBase admin apis", tags = "brokers") +@Tag(name = "brokers", description = "BrokersBase admin apis") @Produces(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class Brokers extends BrokersBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Clusters.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Clusters.java index 5b2b4f66a2f66..5cb1766ccb972 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Clusters.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Clusters.java @@ -18,15 +18,14 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import org.apache.pulsar.broker.admin.impl.ClustersBase; @Path("/clusters") -@Api(value = "/clusters", description = "Cluster admin apis", tags = "clusters") +@Tag(name = "clusters", description = "Cluster admin apis") @Produces(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class Clusters extends ClustersBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java index c9f30ceb194c4..c261bb7e99db8 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java @@ -19,11 +19,12 @@ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -44,38 +45,40 @@ */ @Path("/non-persistent") @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/non-persistent", description = "Non-Persistent topic admin apis", tags = "non-persistent topic") +@Tag(name = "non-persistent topic", description = "Non-Persistent topic admin apis") @SuppressWarnings("deprecation") public class ExtNonPersistentTopics extends PersistentTopicsBase { @PUT @Consumes(PartitionedTopicMetadata.MEDIA_TYPE) @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Create a partitioned topic.", - notes = "It needs to be called before creating a producer on a partitioned topic.") + @Operation(summary = "Create a partitioned topic.", + description = "It needs to be called before creating a producer on a partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 406, message = "The number of partitions should be more than 0 and" + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(code = 409, message = "Partitioned topic already exist"), - @ApiResponse(code = 412, - message = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "412", + description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void createPartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "The metadata for the topic", - required = true, type = "PartitionedTopicMetadata") PartitionedTopicMetadata metadata, + @RequestBody(description = "The metadata for the topic", + required = true) PartitionedTopicMetadata metadata, @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { try { validateNamespaceName(tenant, namespace); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java index 888c8e47270a8..8e463b89a3408 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java @@ -19,11 +19,12 @@ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -46,38 +47,40 @@ */ @Path("/persistent") @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/persistent", description = "Persistent topic admin apis", tags = "persistent topic") +@Tag(name = "persistent topic", description = "Persistent topic admin apis") @SuppressWarnings("deprecation") public class ExtPersistentTopics extends PersistentTopicsBase { @PUT @Consumes(PartitionedTopicMetadata.MEDIA_TYPE) @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Create a partitioned topic.", - notes = "It needs to be called before creating a producer on a partitioned topic.") + @Operation(summary = "Create a partitioned topic.", + description = "It needs to be called before creating a producer on a partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 406, message = "The number of partitions should be more than 0 and" + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(code = 409, message = "Partitioned topic already exist"), - @ApiResponse(code = 412, - message = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "412", + description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void createPartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "The metadata for the topic", - required = true, type = "PartitionedTopicMetadata") PartitionedTopicMetadata metadata, + @RequestBody(description = "The metadata for the topic", + required = true) PartitionedTopicMetadata metadata, @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { try { validateNamespaceName(tenant, namespace); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Functions.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Functions.java index 9f510eef0dbc6..ce17321f1061e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Functions.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Functions.java @@ -18,10 +18,14 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -39,15 +43,14 @@ import org.apache.pulsar.broker.admin.AdminResource; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.common.io.ConnectorDefinition; -import org.apache.pulsar.functions.proto.FunctionMetaData; -import org.apache.pulsar.functions.proto.FunctionStatus; import org.apache.pulsar.functions.worker.WorkerService; import org.apache.pulsar.functions.worker.service.api.FunctionsV2; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; @Path("/functions") -@Api(value = "/functions", description = "Functions admin apis", tags = "functions", hidden = true) +@Tag(name = "functions", description = "Functions admin apis") +@Hidden @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @SuppressWarnings("deprecation") @@ -58,12 +61,12 @@ FunctionsV2 functions() { } @POST - @ApiOperation(value = "Creates a new Pulsar Function in cluster mode") + @Operation(summary = "Creates a new Pulsar Function in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request (function already exists, etc.)"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "Pulsar Function successfully created") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request (function already exists, etc.)"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully created") }) @Path("/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -80,11 +83,11 @@ public Response registerFunction(final @PathParam("tenant") String tenant, } @PUT - @ApiOperation(value = "Updates a Pulsar Function currently running in cluster mode") + @Operation(summary = "Updates a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request (function doesn't exist, etc.)"), - @ApiResponse(code = 200, message = "Pulsar Function successfully updated") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request (function doesn't exist, etc.)"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated") }) @Path("/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -102,13 +105,13 @@ public Response updateFunction(final @PathParam("tenant") String tenant, @DELETE - @ApiOperation(value = "Deletes a Pulsar Function currently running in cluster mode") + @Operation(summary = "Deletes a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function doesn't exist"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "The function was successfully deleted") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "The function was successfully deleted") }) @Path("/{tenant}/{namespace}/{functionName}") public Response deregisterFunction(final @PathParam("tenant") String tenant, @@ -118,15 +121,16 @@ public Response deregisterFunction(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Fetches information about a Pulsar Function currently running in cluster mode", - response = FunctionMetaData.class - ) + @Operation(summary = "Fetches information about a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "200", + description = "Fetches information about a Pulsar Function currently running in cluster mode", + content = @Content(schema = @Schema(type = "object", + description = "FunctionMetaData (protobuf JSON format)"))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist") }) @Path("/{tenant}/{namespace}/{functionName}") public Response getFunctionInfo(final @PathParam("tenant") String tenant, @@ -137,15 +141,16 @@ public Response getFunctionInfo(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function instance", - response = FunctionStatus.class - ) + @Operation(summary = "Displays the status of a Pulsar Function instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Function instance", + content = @Content(schema = @Schema(type = "object", + description = "InstanceCommunication.FunctionStatus (protobuf JSON format)"))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/status") public Response getFunctionInstanceStatus(final @PathParam("tenant") String tenant, @@ -158,14 +163,16 @@ public Response getFunctionInstanceStatus(final @PathParam("tenant") String tena } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function running in cluster mode", - response = FunctionStatus.class - ) + @Operation(summary = "Displays the status of a Pulsar Function running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions") + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Function running in cluster mode", + content = @Content(schema = @Schema(type = "object", + description = "InstanceCommunication.FunctionStatus (protobuf JSON format)"))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions") }) @Path("/{tenant}/{namespace}/{functionName}/status") public Response getFunctionStatus(final @PathParam("tenant") String tenant, @@ -176,14 +183,13 @@ public Response getFunctionStatus(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Lists all Pulsar Functions currently deployed in a given namespace", - response = String.class, - responseContainer = "Collection" - ) + @Operation(summary = "Lists all Pulsar Functions currently deployed in a given namespace") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions") + @ApiResponse(responseCode = "200", + description = "Lists all Pulsar Functions currently deployed in a given namespace", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions") }) @Path("/{tenant}/{namespace}") public Response listFunctions(final @PathParam("tenant") String tenant, @@ -192,15 +198,15 @@ public Response listFunctions(final @PathParam("tenant") String tenant, } @POST - @ApiOperation( - value = "Triggers a Pulsar Function with a user-specified value or file data", - response = Message.class - ) + @Operation(summary = "Triggers a Pulsar Function with a user-specified value or file data") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Triggers a Pulsar Function with a user-specified value or file data", + content = @Content(schema = @Schema(implementation = Message.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/trigger") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -215,15 +221,15 @@ public Response triggerFunction(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Fetch the current state associated with a Pulsar Function", - response = String.class - ) + @Operation(summary = "Fetch the current state associated with a Pulsar Function") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The key does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Fetch the current state associated with a Pulsar Function", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The key does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/state/{key}") public Response getFunctionState(final @PathParam("tenant") String tenant, @@ -234,12 +240,15 @@ public Response getFunctionState(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart function instance", response = Void.class) + @Operation(summary = "Restart function instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "200", description = "Restart function instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) public Response restartFunction(final @PathParam("tenant") String tenant, @@ -251,10 +260,13 @@ public Response restartFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart all function instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Restart all function instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Restart all function instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{functionName}/restart") @Consumes(MediaType.APPLICATION_JSON) public Response restartFunction(final @PathParam("tenant") String tenant, @@ -264,10 +276,13 @@ public Response restartFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop function instance", response = Void.class) - @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") }) + @Operation(summary = "Stop function instance") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Stop function instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) public Response stopFunction(final @PathParam("tenant") String tenant, @@ -279,10 +294,13 @@ public Response stopFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop all function instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Stop all function instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Stop all function instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{functionName}/stop") @Consumes(MediaType.APPLICATION_JSON) public Response stopFunction(final @PathParam("tenant") String tenant, @@ -292,10 +310,7 @@ public Response stopFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation( - value = "Uploads Pulsar Function file data (admin only)", - hidden = true - ) + @Operation(summary = "Uploads Pulsar Function file data (admin only)", hidden = true) @Path("/upload") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFunction(final @FormDataParam("data") InputStream uploadedInputStream, @@ -304,24 +319,21 @@ public Response uploadFunction(final @FormDataParam("data") InputStream uploaded } @GET - @ApiOperation( - value = "Downloads Pulsar Function file data", - hidden = true - ) + @Operation(summary = "Downloads Pulsar Function file data", hidden = true) @Path("/download") public Response downloadFunction(final @QueryParam("path") String path) { return functions().downloadFunction(path, authParams()); } @GET - @ApiOperation( - value = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", - response = List.class - ) + @Operation(summary = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", + description = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", + content = @Content(schema = @Schema(implementation = List.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/connectors") public List getConnectorsList() throws IOException { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/MetadataMigration.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/MetadataMigration.java index 53bf8b84371ac..3e13e4ef91aba 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/MetadataMigration.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/MetadataMigration.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @@ -28,8 +28,7 @@ * REST API for metadata store migration operations. */ @Path("/metadata/migration") -@Api(value = "/metadata/migration", description = "Metadata store migration admin APIs", tags = "metadata-migration") +@Tag(name = "metadata-migration", description = "Metadata store migration admin APIs") @Produces(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class MetadataMigration extends MetadataMigrationBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java index 75ac7cf79adcb..9665d8ace1b2b 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java @@ -18,13 +18,16 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; @@ -92,16 +95,19 @@ @Path("/namespaces") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@Api(value = "/namespaces", description = "Namespaces admin apis", tags = "namespaces") +@Tag(name = "namespaces", description = "Namespaces admin apis") @SuppressWarnings("deprecation") public class Namespaces extends NamespacesBase { @GET @Path("/{tenant}") - @ApiOperation(value = "Get the list of all the namespaces for a certain tenant.", - response = String.class, responseContainer = "Set") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant doesn't exist")}) + @Operation(summary = "Get the list of all the namespaces for a certain tenant.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the list of all the namespaces for a certain tenant.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class), + uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant doesn't exist")}) public void getTenantNamespaces(@Suspended final AsyncResponse response, @PathParam("tenant") String tenant) { internalGetTenantNamespaces(tenant) @@ -118,16 +124,19 @@ public void getTenantNamespaces(@Suspended final AsyncResponse response, @GET @Path("/{tenant}/{namespace}/topics") - @ApiOperation(value = "Get the list of all the topics under a certain namespace.", - response = String.class, responseContainer = "Set") - @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist")}) + @Operation(summary = "Get the list of all the topics under a certain namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get the list of all the topics under a certain namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class), + uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist")}) public void getTopics(@Suspended AsyncResponse response, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @QueryParam("mode") @DefaultValue("PERSISTENT") Mode mode, - @ApiParam(value = "Include system topic") + @Parameter(description = "Include system topic") @QueryParam("includeSystemTopic") boolean includeSystemTopic) { validateNamespaceName(tenant, namespace); validateNamespaceOperationAsync(NamespaceName.get(tenant, namespace), NamespaceOperation.GET_TOPICS) @@ -148,9 +157,12 @@ public void getTopics(@Suspended AsyncResponse response, @GET @Path("/{tenant}/{namespace}") - @ApiOperation(value = "Get the dump all the policies specified for a namespace.", response = Policies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get the dump all the policies specified for a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the dump all the policies specified for a namespace.", + content = @Content(schema = @Schema(implementation = Policies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getPolicies(@Suspended AsyncResponse response, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -178,17 +190,17 @@ public void getPolicies(@Suspended AsyncResponse response, @PUT @Path("/{tenant}/{namespace}") - @ApiOperation(value = "Creates a new namespace with the specified policies") + @Operation(summary = "Creates a new namespace with the specified policies") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster doesn't exist"), - @ApiResponse(code = 409, message = "Namespace already exists"), - @ApiResponse(code = 412, message = "Namespace name is not valid") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster doesn't exist"), + @ApiResponse(responseCode = "409", description = "Namespace already exists"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid") }) public void createNamespace(@Suspended AsyncResponse response, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Policies for the namespace") Policies policies) { + @RequestBody(description = "Policies for the namespace") Policies policies) { validateNamespaceName(tenant, namespace); policies = getDefaultPolicesIfNull(policies); internalCreateNamespace(policies) @@ -210,14 +222,14 @@ public void createNamespace(@Suspended AsyncResponse response, @DELETE @Path("/{tenant}/{namespace}") - @ApiOperation(value = "Delete a namespace and all the topics under it.") - @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 405, message = "Broker doesn't allow forced deletion of namespaces"), - @ApiResponse(code = 409, message = "Namespace is not empty") }) + @Operation(summary = "Delete a namespace and all the topics under it.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "405", description = "Broker doesn't allow forced deletion of namespaces"), + @ApiResponse(responseCode = "409", description = "Namespace is not empty") }) public void deleteNamespace(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @QueryParam("force") @DefaultValue("false") boolean force, @@ -244,13 +256,13 @@ public void deleteNamespace(@Suspended final AsyncResponse asyncResponse, @PathP @DELETE @Path("/{tenant}/{namespace}/{bundle}") - @ApiOperation(value = "Delete a namespace bundle and all the topics under it.") + @Operation(summary = "Delete a namespace bundle and all the topics under it.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Namespace bundle is not empty")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Namespace bundle is not empty")}) public void deleteNamespaceBundle(@Suspended AsyncResponse response, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("bundle") String bundleRange, @@ -273,13 +285,16 @@ public void deleteNamespaceBundle(@Suspended AsyncResponse response, @PathParam( @GET @Path("/{tenant}/{namespace}/permissions") - @ApiOperation(value = "Retrieve the permissions for a namespace.", - notes = "Returns a nested map structure which Swagger does not fully support for display. " - + "Structure: Map>. Please refer to this structure for details.", - response = AuthAction.class, responseContainer = "Map") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Namespace is not empty") }) + @Operation(summary = "Retrieve the permissions for a namespace.", + description = "Returns a map structure: Map>.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Retrieve the permissions for a namespace.", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesArraySchema = @ArraySchema( + schema = @Schema(implementation = AuthAction.class), uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Namespace is not empty") }) public void getPermissions(@Suspended AsyncResponse response, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -299,13 +314,16 @@ public void getPermissions(@Suspended AsyncResponse response, @GET @Path("/{tenant}/{namespace}/permissions/subscription") - @ApiOperation(value = "Retrieve the permissions for a subscription.", - notes = "Returns a nested map structure which Swagger does not fully support for display. " - + "Structure: Map>. Please refer to this structure for details.", - response = String.class, responseContainer = "Map") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Namespace is not empty")}) + @Operation(summary = "Retrieve the permissions for a subscription.", + description = "Returns a map structure: Map>.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Retrieve the permissions for a subscription.", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesArraySchema = @ArraySchema( + schema = @Schema(implementation = String.class), uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Namespace is not empty")}) public void getPermissionOnSubscription(@Suspended AsyncResponse response, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -326,18 +344,18 @@ public void getPermissionOnSubscription(@Suspended AsyncResponse response, @POST @Path("/{tenant}/{namespace}/permissions/{role}") - @ApiOperation(value = "Grant a new permission to a role on a namespace.") + @Operation(summary = "Grant a new permission to a role on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 501, message = "Authorization is not enabled")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "501", description = "Authorization is not enabled")}) public void grantPermissionOnNamespace(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("role") String role, - @ApiParam(value = "List of permissions for the specified role") Set actions) { + @RequestBody(description = "List of permissions for the specified role") Set actions) { validateNamespaceName(tenant, namespace); internalGrantPermissionOnNamespaceAsync(role, actions) .thenAccept(__ -> asyncResponse.resume(Response.noContent().build())) @@ -354,13 +372,14 @@ public void grantPermissionOnNamespace(@Suspended AsyncResponse asyncResponse, @POST @Path("/grantPermissionsOnTopics") - @ApiOperation(value = "Grant new permissions to a role on multi-topics.") - @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 500, message = "Internal server error") }) + @Operation(summary = "Grant new permissions to a role on multi-topics.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void grantPermissionsOnTopics(@Suspended final AsyncResponse asyncResponse, List options) { internalGrantPermissionOnTopicsAsync(options) @@ -377,13 +396,14 @@ public void grantPermissionsOnTopics(@Suspended final AsyncResponse asyncRespons @POST @Path("/revokePermissionsOnTopics") - @ApiOperation(value = "Revoke new permissions to a role on multi-topics.") - @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 500, message = "Internal server error") }) + @Operation(summary = "Revoke new permissions to a role on multi-topics.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void revokePermissionsOnTopics(@Suspended final AsyncResponse asyncResponse, List options) { internalRevokePermissionOnTopicsAsync(options) @@ -400,19 +420,19 @@ public void revokePermissionsOnTopics(@Suspended final AsyncResponse asyncRespon @POST @Path("/{tenant}/{namespace}/permissions/subscription/{subscription}") - @ApiOperation(hidden = true, value = "Grant a new permission to roles for a subscription." + @Operation(hidden = true, summary = "Grant a new permission to roles for a subscription." + "[Tenant admin is allowed to perform this operation]") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 501, message = "Authorization is not enabled") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "501", description = "Authorization is not enabled") }) public void grantPermissionOnSubscription(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("subscription") String subscription, - @ApiParam(value = "List of roles for the specified subscription") Set roles) { + @RequestBody(description = "List of roles for the specified subscription") Set roles) { validateNamespaceName(tenant, namespace); internalGrantPermissionOnSubscriptionAsync(subscription, roles) .thenAccept(__ -> asyncResponse.resume(Response.noContent().build())) @@ -430,11 +450,11 @@ public void grantPermissionOnSubscription(@Suspended AsyncResponse asyncResponse @DELETE @Path("/{tenant}/{namespace}/permissions/{role}") - @ApiOperation(value = "Revoke all permissions to a role on a namespace.") + @Operation(summary = "Revoke all permissions to a role on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void revokePermissionsOnNamespace(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("role") String role) { @@ -455,11 +475,11 @@ public void revokePermissionsOnNamespace(@Suspended AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/permissions/{subscription}/{role}") - @ApiOperation(hidden = true, value = "Revoke subscription admin-api access permission for a role.") + @Operation(hidden = true, summary = "Revoke subscription admin-api access permission for a role.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist") }) public void revokePermissionOnSubscription(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("subscription") String subscription, @@ -482,11 +502,14 @@ public void revokePermissionOnSubscription(@Suspended AsyncResponse asyncRespons @GET @Path("/{tenant}/{namespace}/replication") - @ApiOperation(value = "Get the replication clusters for a namespace.", - response = String.class, responseContainer = "Set") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Namespace is not global")}) + @Operation(summary = "Get the replication clusters for a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the replication clusters for a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class), + uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Namespace is not global")}) public void getNamespaceReplicationClusters(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -505,20 +528,20 @@ public void getNamespaceReplicationClusters(@Suspended AsyncResponse asyncRespon @POST @Path("/{tenant}/{namespace}/replication") - @ApiOperation(value = "Set the replication clusters for a namespace. " + @Operation(summary = "Set the replication clusters for a namespace. " + "When removing a cluster: " + "with shared configuration store, data will be deleted from the removed cluster; " + "with separate configuration store, only replication stops but data is preserved.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Peer-cluster can't be part of replication-cluster"), - @ApiResponse(code = 412, message = "Namespace is not global or invalid cluster ids") }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Peer-cluster can't be part of replication-cluster"), + @ApiResponse(responseCode = "412", description = "Namespace is not global or invalid cluster ids") }) public void setNamespaceReplicationClusters(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "List of replication clusters", required = true) List clusterIds, + @RequestBody(description = "List of replication clusters", required = true) List clusterIds, @QueryParam(value = "compareTopicPartitions") boolean compareTopicPartitions) { validateNamespaceName(tenant, namespace); internalSetNamespaceReplicationClusters(clusterIds, compareTopicPartitions) @@ -535,9 +558,12 @@ public void setNamespaceReplicationClusters(@Suspended AsyncResponse asyncRespon @GET @Path("/{tenant}/{namespace}/messageTTL") - @ApiOperation(value = "Get the message TTL for the namespace", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get the message TTL for the namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the message TTL for the namespace", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getNamespaceMessageTTL(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -557,15 +583,16 @@ public void getNamespaceMessageTTL(@Suspended AsyncResponse asyncResponse, @Path @POST @Path("/{tenant}/{namespace}/messageTTL") - @ApiOperation(value = "Set message TTL in seconds for namespace") + @Operation(summary = "Set message TTL in seconds for namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid TTL") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid TTL") }) public void setNamespaceMessageTTL(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "TTL in seconds for the specified namespace", required = true) + @RequestBody(description = "TTL in seconds for the specified namespace", + required = true) int messageTTL) { validateNamespaceName(tenant, namespace); internalSetNamespaceMessageTTLAsync(messageTTL) @@ -582,12 +609,12 @@ public void setNamespaceMessageTTL(@Suspended AsyncResponse asyncResponse, @Path @DELETE @Path("/{tenant}/{namespace}/messageTTL") - @ApiOperation(value = "Remove message TTL in seconds for namespace") + @Operation(summary = "Remove message TTL in seconds for namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid TTL")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid TTL")}) public void removeNamespaceMessageTTL(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -606,9 +633,12 @@ public void removeNamespaceMessageTTL(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/subscriptionExpirationTime") - @ApiOperation(value = "Get the subscription expiration time for the namespace", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get the subscription expiration time for the namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the subscription expiration time for the namespace", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getSubscriptionExpirationTime(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -630,16 +660,16 @@ public void getSubscriptionExpirationTime(@Suspended AsyncResponse asyncResponse @POST @Path("/{tenant}/{namespace}/subscriptionExpirationTime") - @ApiOperation(value = "Set subscription expiration time in minutes for namespace") + @Operation(summary = "Set subscription expiration time in minutes for namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid expiration time")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid expiration time")}) public void setSubscriptionExpirationTime(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = + @RequestBody(description = "Expiration time in minutes for the specified namespace", required = true) int expirationTime) { validateNamespaceName(tenant, namespace); @@ -658,11 +688,11 @@ public void setSubscriptionExpirationTime(@Suspended AsyncResponse asyncResponse @DELETE @Path("/{tenant}/{namespace}/subscriptionExpirationTime") - @ApiOperation(value = "Remove subscription expiration time for namespace") + @Operation(summary = "Remove subscription expiration time for namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist")}) public void removeSubscriptionExpirationTime(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -682,9 +712,13 @@ public void removeSubscriptionExpirationTime(@Suspended AsyncResponse asyncRespo @GET @Path("/{tenant}/{namespace}/deduplication") - @ApiOperation(value = "Get broker side deduplication for all topics in a namespace", response = Boolean.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get broker side deduplication for all topics in a namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get broker side deduplication for all topics in a namespace", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getDeduplication(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -702,15 +736,16 @@ public void getDeduplication(@Suspended AsyncResponse asyncResponse, @PathParam( @POST @Path("/{tenant}/{namespace}/deduplication") - @ApiOperation(value = "Enable or disable broker side deduplication for all topics in a namespace") + @Operation(summary = "Enable or disable broker side deduplication for all topics in a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void modifyDeduplication(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Flag for disabling or enabling broker side deduplication " - + "for all topics in the specified namespace", required = true) + @RequestBody(description = "Flag for disabling or enabling broker side " + + "deduplication for all topics in the specified namespace", + required = true) boolean enableDeduplication) { validateNamespaceName(tenant, namespace); internalModifyDeduplicationAsync(enableDeduplication) @@ -727,11 +762,11 @@ public void modifyDeduplication(@Suspended AsyncResponse asyncResponse, @PathPar @DELETE @Path("/{tenant}/{namespace}/deduplication") - @ApiOperation(value = "Remove broker side deduplication for all topics in a namespace") + @Operation(summary = "Remove broker side deduplication for all topics in a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void removeDeduplication(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -750,9 +785,12 @@ public void removeDeduplication(@Suspended AsyncResponse asyncResponse, @PathPar @GET @Path("/{tenant}/{namespace}/autoTopicCreation") - @ApiOperation(value = "Get autoTopicCreation info in a namespace", response = AutoTopicCreationOverrideImpl.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist")}) + @Operation(summary = "Get autoTopicCreation info in a namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get autoTopicCreation info in a namespace", + content = @Content(schema = @Schema(implementation = AutoTopicCreationOverrideImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist")}) public void getAutoTopicCreation(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -771,18 +809,18 @@ public void getAutoTopicCreation(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/autoTopicCreation") - @ApiOperation(value = "Override broker's allowAutoTopicCreation setting for a namespace") + @Operation(summary = "Override broker's allowAutoTopicCreation setting for a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 406, message = "The number of partitions should be less than or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "406", description = "The number of partitions should be less than or" + " equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(code = 400, message = "Invalid autoTopicCreation override")}) + @ApiResponse(responseCode = "400", description = "Invalid autoTopicCreation override")}) public void setAutoTopicCreation( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Settings for automatic topic creation", required = true) + @RequestBody(description = "Settings for automatic topic creation", required = true) AutoTopicCreationOverride autoTopicCreationOverride) { validateNamespaceName(tenant, namespace); internalSetAutoTopicCreationAsync(autoTopicCreationOverride) @@ -812,11 +850,11 @@ public void setAutoTopicCreation( @DELETE @Path("/{tenant}/{namespace}/autoTopicCreation") - @ApiOperation(value = "Remove override of broker's allowAutoTopicCreation in a namespace") + @Operation(summary = "Remove override of broker's allowAutoTopicCreation in a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void removeAutoTopicCreation(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -844,16 +882,16 @@ public void removeAutoTopicCreation(@Suspended final AsyncResponse asyncResponse @POST @Path("/{tenant}/{namespace}/autoSubscriptionCreation") - @ApiOperation(value = "Override broker's allowAutoSubscriptionCreation setting for a namespace") + @Operation(summary = "Override broker's allowAutoSubscriptionCreation setting for a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 400, message = "Invalid autoSubscriptionCreation override")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "400", description = "Invalid autoSubscriptionCreation override")}) public void setAutoSubscriptionCreation( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Settings for automatic subscription creation") + @RequestBody(description = "Settings for automatic subscription creation") AutoSubscriptionCreationOverride autoSubscriptionCreationOverride) { validateNamespaceName(tenant, namespace); internalSetAutoSubscriptionCreationAsync(autoSubscriptionCreationOverride) @@ -880,10 +918,13 @@ public void setAutoSubscriptionCreation( @GET @Path("/{tenant}/{namespace}/autoSubscriptionCreation") - @ApiOperation(value = "Get autoSubscriptionCreation info in a namespace", - response = AutoSubscriptionCreationOverrideImpl.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist")}) + @Operation(summary = "Get autoSubscriptionCreation info in a namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get autoSubscriptionCreation info in a namespace", + content = @Content(schema = + @Schema(implementation = AutoSubscriptionCreationOverrideImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist")}) public void getAutoSubscriptionCreation(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -902,11 +943,11 @@ public void getAutoSubscriptionCreation(@Suspended final AsyncResponse asyncResp @DELETE @Path("/{tenant}/{namespace}/autoSubscriptionCreation") - @ApiOperation(value = "Remove override of broker's allowAutoSubscriptionCreation in a namespace") + @Operation(summary = "Remove override of broker's allowAutoSubscriptionCreation in a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void removeAutoSubscriptionCreation(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -934,10 +975,13 @@ public void removeAutoSubscriptionCreation(@Suspended final AsyncResponse asyncR @GET @Path("/{tenant}/{namespace}/bundles") - @ApiOperation(value = "Get the bundles split data.", response = BundlesDataImpl.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Namespace is not setup to split in bundles") }) + @Operation(summary = "Get the bundles split data.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the bundles split data.", + content = @Content(schema = @Schema(implementation = BundlesDataImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Namespace is not setup to split in bundles") }) public void getBundlesData(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -959,20 +1003,21 @@ public void getBundlesData(@Suspended final AsyncResponse asyncResponse, @PUT @Path("/{tenant}/{namespace}/unload") - @ApiOperation(value = "Unload namespace", - notes = "Unload an active namespace from the current broker serving it. Performing this operation will" - + " let the brokerremoves all producers, consumers, and connections using this namespace," + @Operation(summary = "Unload namespace", + description = "Unload an active namespace from the current broker serving it. Performing this operation" + + " will let the brokerremoves all producers, consumers, and connections using this namespace," + " and close all topics (includingtheir persistent store). During that operation," + " the namespace is marked as tentatively unavailable until thebroker completes " + "the unloading action. This operation requires strictly super user privileges," + " since it wouldresult in non-persistent message loss and" + " unexpected connection closure to the clients.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Namespace is already unloaded or Namespace has bundles activated")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "412", + description = "Namespace is already unloaded or Namespace has bundles activated")}) public void unloadNamespace(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1003,12 +1048,12 @@ public void unloadNamespace(@Suspended final AsyncResponse asyncResponse, @PUT @Path("/{tenant}/{namespace}/{bundle}/unload") - @ApiOperation(value = "Unload a namespace bundle") + @Operation(summary = "Unload a namespace bundle") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void unloadNamespaceBundle(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("bundle") String bundleRange, @@ -1037,12 +1082,12 @@ public void unloadNamespaceBundle(@Suspended final AsyncResponse asyncResponse, @PUT @Path("/{tenant}/{namespace}/{bundle}/split") - @ApiOperation(value = "Split a namespace bundle") + @Operation(summary = "Split a namespace bundle") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void splitNamespaceBundle( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -1051,7 +1096,7 @@ public void splitNamespaceBundle( @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("unload") @DefaultValue("false") boolean unload, @QueryParam("splitAlgorithmName") String splitAlgorithmName, - @ApiParam("splitBoundaries") List splitBoundaries) { + @RequestBody(description = "splitBoundaries") List splitBoundaries) { validateNamespaceName(tenant, namespace); internalSplitNamespaceBundleAsync(bundleRange, authoritative, unload, splitAlgorithmName, splitBoundaries) .thenAccept(__ -> { @@ -1081,10 +1126,12 @@ public void splitNamespaceBundle( @GET @Path("/{tenant}/{namespace}/{bundle}/topicHashPositions") - @ApiOperation(value = "Get hash positions for topics", response = TopicHashPositions.class) + @Operation(summary = "Get hash positions for topics") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist")}) + @ApiResponse(responseCode = "200", description = "Get hash positions for topics", + content = @Content(schema = @Schema(implementation = TopicHashPositions.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist")}) public void getTopicHashPositions( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @@ -1108,13 +1155,14 @@ public void getTopicHashPositions( @POST @Path("/{tenant}/{namespace}/publishRate") - @ApiOperation(hidden = true, value = "Set publish-rate throttling for all topics of the namespace") + @Operation(hidden = true, summary = "Set publish-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void setPublishRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Publish rate for all topics of the specified namespace") PublishRate publishRate) { + @RequestBody(description = "Publish rate for all topics of the specified namespace") + PublishRate publishRate) { validateNamespaceName(tenant, namespace); internalSetPublishRateAsync(publishRate) .thenAccept(__ -> asyncResponse.resume(Response.noContent().build())) @@ -1126,10 +1174,10 @@ public void setPublishRate(@Suspended AsyncResponse asyncResponse, @PathParam("t @DELETE @Path("/{tenant}/{namespace}/publishRate") - @ApiOperation(hidden = true, value = "Set publish-rate throttling for all topics of the namespace") + @Operation(hidden = true, summary = "Set publish-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void removePublishRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1147,12 +1195,17 @@ public void removePublishRate(@Suspended AsyncResponse asyncResponse, @PathParam @GET @Path("/{tenant}/{namespace}/publishRate") - @ApiOperation(hidden = true, - value = "Get publish-rate configured for the namespace, null means publish-rate not configured, " - + "-1 means msg-publish-rate or byte-publish-rate not configured in publish-rate yet", - response = PublishRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist")}) + @Operation(hidden = true, + summary = "Get publish-rate configured for the namespace, null means publish-rate not configured, " + + "-1 means msg-publish-rate or byte-publish-rate not configured in publish-rate yet") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get publish-rate configured for the namespace, null means publish-rate " + + "not configured, -1 means msg-publish-rate or byte-publish-rate not configured " + + "in publish-rate yet", + content = @Content(schema = @Schema(implementation = PublishRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist")}) public void getPublishRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1171,13 +1224,13 @@ public void getPublishRate(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/dispatchRate") - @ApiOperation(value = "Set dispatch-rate throttling for all topics of the namespace") + @Operation(summary = "Set dispatch-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void setDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Dispatch rate for all topics of the specified namespace") + @RequestBody(description = "Dispatch rate for all topics of the specified namespace") DispatchRateImpl dispatchRate) { validateNamespaceName(tenant, namespace); internalSetTopicDispatchRateAsync(dispatchRate) @@ -1194,10 +1247,10 @@ public void setDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam(" @DELETE @Path("/{tenant}/{namespace}/dispatchRate") - @ApiOperation(value = "Delete dispatch-rate throttling for all topics of the namespace") + @Operation(summary = "Delete dispatch-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void deleteDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1215,11 +1268,16 @@ public void deleteDispatchRate(@Suspended AsyncResponse asyncResponse, @PathPara @GET @Path("/{tenant}/{namespace}/dispatchRate") - @ApiOperation(value = "Get dispatch-rate configured for the namespace, null means dispatch-rate not configured, " - + "-1 means msg-dispatch-rate or byte-dispatch-rate not configured in dispatch-rate yet", - response = DispatchRate.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get dispatch-rate configured for the namespace, null means dispatch-rate not configured, " + + "-1 means msg-dispatch-rate or byte-dispatch-rate not configured in dispatch-rate yet") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get dispatch-rate configured for the namespace, null means dispatch-rate " + + "not configured, -1 means msg-dispatch-rate or byte-dispatch-rate not configured " + + "in dispatch-rate yet", + content = @Content(schema = @Schema(implementation = DispatchRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1233,14 +1291,14 @@ public void getDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam(" @POST @Path("/{tenant}/{namespace}/subscriptionDispatchRate") - @ApiOperation(value = "Set Subscription dispatch-rate throttling for all topics of the namespace") + @Operation(summary = "Set Subscription dispatch-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void setSubscriptionDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = + @RequestBody(description = "Subscription dispatch rate for all topics of the specified namespace") DispatchRateImpl dispatchRate) { validateNamespaceName(tenant, namespace); @@ -1258,11 +1316,17 @@ public void setSubscriptionDispatchRate(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/subscriptionDispatchRate") - @ApiOperation(value = "Get subscription dispatch-rate configured for the namespace, null means subscription " + @Operation(summary = "Get subscription dispatch-rate configured for the namespace, null means subscription " + "dispatch-rate not configured, -1 means msg-dispatch-rate or byte-dispatch-rate not configured " - + "in dispatch-rate yet", response = DispatchRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist")}) + + "in dispatch-rate yet") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get subscription dispatch-rate configured for the namespace, null means " + + "subscription dispatch-rate not configured, -1 means msg-dispatch-rate or " + + "byte-dispatch-rate not configured in dispatch-rate yet", + content = @Content(schema = @Schema(implementation = DispatchRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist")}) public void getSubscriptionDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1281,10 +1345,10 @@ public void getSubscriptionDispatchRate(@Suspended AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/subscriptionDispatchRate") - @ApiOperation(value = "Delete Subscription dispatch-rate throttling for all topics of the namespace") + @Operation(summary = "Delete Subscription dispatch-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void deleteSubscriptionDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1303,10 +1367,10 @@ public void deleteSubscriptionDispatchRate(@Suspended AsyncResponse asyncRespons @DELETE @Path("/{tenant}/{namespace}/subscribeRate") - @ApiOperation(value = "Delete subscribe-rate throttling for all topics of the namespace") + @Operation(summary = "Delete subscribe-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void deleteSubscribeRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1324,13 +1388,13 @@ public void deleteSubscribeRate(@Suspended AsyncResponse asyncResponse, @PathPar @POST @Path("/{tenant}/{namespace}/subscribeRate") - @ApiOperation(value = "Set subscribe-rate throttling for all topics of the namespace") + @Operation(summary = "Set subscribe-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void setSubscribeRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Subscribe rate for all topics of the specified namespace") + @RequestBody(description = "Subscribe rate for all topics of the specified namespace") SubscribeRate subscribeRate) { validateNamespaceName(tenant, namespace); internalSetSubscribeRateAsync(subscribeRate) @@ -1347,9 +1411,12 @@ public void setSubscribeRate(@Suspended AsyncResponse asyncResponse, @PathParam( @GET @Path("/{tenant}/{namespace}/subscribeRate") - @ApiOperation(value = "Get subscribe-rate configured for the namespace", response = SubscribeRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist")}) + @Operation(summary = "Get subscribe-rate configured for the namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get subscribe-rate configured for the namespace", + content = @Content(schema = @Schema(implementation = SubscribeRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist")}) public void getSubscribeRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1367,10 +1434,10 @@ public void getSubscribeRate(@Suspended AsyncResponse asyncResponse, @PathParam( @DELETE @Path("/{tenant}/{namespace}/replicatorDispatchRate") - @ApiOperation(value = "Remove replicator dispatch-rate throttling for all topics of the namespace") + @Operation(summary = "Remove replicator dispatch-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void removeReplicatorDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1380,14 +1447,14 @@ public void removeReplicatorDispatchRate(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/replicatorDispatchRate") - @ApiOperation(value = "Set replicator dispatch-rate throttling for all topics of the namespace") + @Operation(summary = "Set replicator dispatch-rate throttling for all topics of the namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public void setReplicatorDispatchRate(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = + @RequestBody(description = "Replicator dispatch rate for all topics of the specified namespace") DispatchRateImpl dispatchRate) { validateNamespaceName(tenant, namespace); internalSetReplicatorDispatchRate(asyncResponse, dispatchRate); @@ -1395,11 +1462,17 @@ public void setReplicatorDispatchRate(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/replicatorDispatchRate") - @ApiOperation(value = "Get replicator dispatch-rate configured for the namespace, null means replicator " + @Operation(summary = "Get replicator dispatch-rate configured for the namespace, null means replicator " + "dispatch-rate not configured, -1 means msg-dispatch-rate or byte-dispatch-rate not configured " - + "in dispatch-rate yet", response = DispatchRateImpl.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + + "in dispatch-rate yet") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get replicator dispatch-rate configured for the namespace, null means " + + "replicator dispatch-rate not configured, -1 means msg-dispatch-rate or " + + "byte-dispatch-rate not configured in dispatch-rate yet", + content = @Content(schema = @Schema(implementation = DispatchRateImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getReplicatorDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1409,10 +1482,13 @@ public void getReplicatorDispatchRate(@Suspended final AsyncResponse asyncRespon @GET @Path("/{tenant}/{namespace}/backlogQuotaMap") - @ApiOperation(value = "Get backlog quota map on a namespace.", - response = BacklogQuotaImpl.class, responseContainer = "Map") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get backlog quota map on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get backlog quota map on a namespace.", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = BacklogQuotaImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getBacklogQuotaMap( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -1423,32 +1499,33 @@ public void getBacklogQuotaMap( @POST @Path("/{tenant}/{namespace}/backlogQuota") - @ApiOperation(value = " Set a backlog quota for all the topics on a namespace.") - @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, - message = "Specified backlog quota exceeds retention quota." + @Operation(summary = " Set a backlog quota for all the topics on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", + description = "Specified backlog quota exceeds retention quota." + " Increase retention quota and retry request")}) public void setBacklogQuota( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @QueryParam("backlogQuotaType") BacklogQuotaType backlogQuotaType, - @ApiParam(value = "Backlog quota for all topics of the specified namespace") BacklogQuota backlogQuota) { + @RequestBody(description = "Backlog quota for all topics of the specified namespace") + BacklogQuota backlogQuota) { validateNamespaceName(tenant, namespace); internalSetBacklogQuota(asyncResponse, backlogQuotaType, backlogQuota); } @DELETE @Path("/{tenant}/{namespace}/backlogQuota") - @ApiOperation(value = "Remove a backlog quota policy from a namespace.") + @Operation(summary = "Remove a backlog quota policy from a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void removeBacklogQuota( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @@ -1459,9 +1536,12 @@ public void removeBacklogQuota( @GET @Path("/{tenant}/{namespace}/retention") - @ApiOperation(value = "Get retention config on a namespace.", response = RetentionPolicies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get retention config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get retention config on a namespace.", + content = @Content(schema = @Schema(implementation = RetentionPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getRetention(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1481,46 +1561,47 @@ public void getRetention(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/retention") - @ApiOperation(value = " Set retention configuration on a namespace.") + @Operation(summary = " Set retention configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Retention Quota must exceed backlog quota") }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Retention Quota must exceed backlog quota") }) public void setRetention(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Retention policies for the specified namespace") RetentionPolicies retention) { + @RequestBody(description = "Retention policies for the specified namespace") RetentionPolicies retention) { validateNamespaceName(tenant, namespace); internalSetRetention(retention); } @DELETE @Path("/{tenant}/{namespace}/retention") - @ApiOperation(value = " Remove retention configuration on a namespace.") + @Operation(summary = " Remove retention configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Retention Quota must exceed backlog quota") }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Retention Quota must exceed backlog quota") }) public void removeRetention(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Retention policies for the specified namespace") RetentionPolicies retention) { + @RequestBody(description = "Retention policies for the specified namespace") RetentionPolicies retention) { validateNamespaceName(tenant, namespace); internalSetRetention(null); } @POST @Path("/{tenant}/{namespace}/persistence") - @ApiOperation(value = "Set the persistence configuration for all the topics on a namespace.") + @Operation(summary = "Set the persistence configuration for all the topics on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 400, message = "Invalid persistence policies")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "400", description = "Invalid persistence policies")}) public void setPersistence(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Persistence policies for the specified namespace", required = true) + @RequestBody(description = "Persistence policies for the specified namespace", + required = true) PersistencePolicies persistence) { validateNamespaceName(tenant, namespace); internalSetPersistenceAsync(persistence) @@ -1537,10 +1618,10 @@ public void setPersistence(@Suspended final AsyncResponse asyncResponse, @PathPa @DELETE @Path("/{tenant}/{namespace}/persistence") - @ApiOperation(value = "Delete the persistence configuration for all topics on a namespace") + @Operation(summary = "Delete the persistence configuration for all topics on a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void deletePersistence(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1558,16 +1639,16 @@ public void deletePersistence(@Suspended final AsyncResponse asyncResponse, @Pat @POST @Path("/{tenant}/{namespace}/persistence/bookieAffinity") - @ApiOperation(value = "Set the bookie-affinity-group to namespace-persistent policy.") + @Operation(summary = "Set the bookie-affinity-group to namespace-persistent policy.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setBookieAffinityGroup(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Bookie affinity group for the specified namespace") + @RequestBody(description = "Bookie affinity group for the specified namespace") BookieAffinityGroupData bookieAffinityGroup) { validateNamespaceName(tenant, namespace); internalSetBookieAffinityGroupAsync(bookieAffinityGroup) @@ -1584,13 +1665,15 @@ public void setBookieAffinityGroup(@Suspended AsyncResponse asyncResponse, @Path @GET @Path("/{tenant}/{namespace}/persistence/bookieAffinity") - @ApiOperation(value = "Get the bookie-affinity-group from namespace-local policy.", - response = BookieAffinityGroupDataImpl.class) - @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @Operation(summary = "Get the bookie-affinity-group from namespace-local policy.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get the bookie-affinity-group from namespace-local policy.", + content = @Content(schema = @Schema(implementation = BookieAffinityGroupDataImpl.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getBookieAffinityGroup(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1608,12 +1691,12 @@ public void getBookieAffinityGroup(@Suspended AsyncResponse asyncResponse, @Path @DELETE @Path("/{tenant}/{namespace}/persistence/bookieAffinity") - @ApiOperation(value = "Delete the bookie-affinity-group from namespace-local policy.") + @Operation(summary = "Delete the bookie-affinity-group from namespace-local policy.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void deleteBookieAffinityGroup(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1632,10 +1715,13 @@ public void deleteBookieAffinityGroup(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/persistence") - @ApiOperation(value = "Get the persistence configuration for a namespace.", response = PersistencePolicies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @Operation(summary = "Get the persistence configuration for a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the persistence configuration for a namespace.", + content = @Content(schema = @Schema(implementation = PersistencePolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getPersistence( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -1656,11 +1742,11 @@ public void getPersistence( @POST @Path("/{tenant}/{namespace}/clearBacklog") - @ApiOperation(value = "Clear backlog for all topics on a namespace.") + @Operation(summary = "Clear backlog for all topics on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void clearNamespaceBacklog(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { @@ -1679,12 +1765,12 @@ public void clearNamespaceBacklog(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{bundle}/clearBacklog") - @ApiOperation(value = "Clear backlog for all topics on a namespace bundle.") + @Operation(summary = "Clear backlog for all topics on a namespace bundle.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void clearNamespaceBundleBacklog(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("bundle") String bundleRange, @@ -1705,11 +1791,11 @@ public void clearNamespaceBundleBacklog(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/clearBacklog/{subscription}") - @ApiOperation(value = "Clear backlog for a given subscription on all topics on a namespace.") + @Operation(summary = "Clear backlog for a given subscription on all topics on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void clearNamespaceBacklogForSubscription(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("subscription") String subscription, @@ -1730,12 +1816,12 @@ public void clearNamespaceBacklogForSubscription(@Suspended final AsyncResponse @POST @Path("/{tenant}/{namespace}/{bundle}/clearBacklog/{subscription}") - @ApiOperation(value = "Clear backlog for a given subscription on all topics on a namespace bundle.") + @Operation(summary = "Clear backlog for a given subscription on all topics on a namespace bundle.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void clearNamespaceBundleBacklogForSubscription(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("subscription") String subscription, @@ -1758,11 +1844,12 @@ public void clearNamespaceBundleBacklogForSubscription(@Suspended final AsyncRes @POST @Path("/{tenant}/{namespace}/unsubscribe/{subscription}") - @ApiOperation(value = "Unsubscribes the given subscription on all topics on a namespace.") + @Operation(summary = "Unsubscribes the given subscription on all topics on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespacen"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", + description = "Don't have admin or operate permission on the namespacen"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void unsubscribeNamespace(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("subscription") String subscription, @@ -1783,11 +1870,11 @@ public void unsubscribeNamespace(@Suspended final AsyncResponse asyncResponse, @ @POST @Path("/{tenant}/{namespace}/{bundle}/unsubscribe/{subscription}") - @ApiOperation(value = "Unsubscribes the given subscription on all topics on a namespace bundle.") + @Operation(summary = "Unsubscribes the given subscription on all topics on a namespace bundle.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void unsubscribeNamespaceBundle(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("subscription") String subscription, @@ -1810,14 +1897,14 @@ public void unsubscribeNamespaceBundle(@Suspended final AsyncResponse asyncRespo @POST @Path("/{tenant}/{namespace}/subscriptionAuthMode") - @ApiOperation(value = " Set a subscription auth mode for all the topics on a namespace.") + @Operation(summary = " Set a subscription auth mode for all the topics on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSubscriptionAuthMode(@PathParam("tenant") String tenant, - @PathParam("namespace") String namespace, @ApiParam(value = + @PathParam("namespace") String namespace, @RequestBody(description = "Subscription auth mode for all topics of the specified namespace") SubscriptionAuthMode subscriptionAuthMode) { validateNamespaceName(tenant, namespace); @@ -1826,9 +1913,12 @@ public void setSubscriptionAuthMode(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/subscriptionAuthMode") - @ApiOperation(value = "Get subscription auth mode in a namespace", response = SubscriptionAuthMode.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist")}) + @Operation(summary = "Get subscription auth mode in a namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get subscription auth mode in a namespace", + content = @Content(schema = @Schema(implementation = SubscriptionAuthMode.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist")}) public void getSubscriptionAuthMode( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -1849,16 +1939,16 @@ public void getSubscriptionAuthMode( @POST @Path("/{tenant}/{namespace}/encryptionRequired") - @ApiOperation(value = "Message encryption is required or not for all topics in a namespace") + @Operation(summary = "Message encryption is required or not for all topics in a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), }) public void modifyEncryptionRequired( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Flag defining if message encryption is required", required = true) + @RequestBody(description = "Flag defining if message encryption is required", required = true) boolean encryptionRequired) { validateNamespaceName(tenant, namespace); internalModifyEncryptionRequired(encryptionRequired); @@ -1866,9 +1956,12 @@ public void modifyEncryptionRequired( @GET @Path("/{tenant}/{namespace}/encryptionRequired") - @ApiOperation(value = "Get message encryption required status in a namespace", response = Boolean.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist")}) + @Operation(summary = "Get message encryption required status in a namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get message encryption required status in a namespace", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist")}) public void getEncryptionRequired(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1888,11 +1981,13 @@ public void getEncryptionRequired(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/delayedDelivery") - @ApiOperation(value = "Get delayed delivery messages config on a namespace.", - response = DelayedDeliveryPolicies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), }) + @Operation(summary = "Get delayed delivery messages config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get delayed delivery messages config on a namespace.", + content = @Content(schema = @Schema(implementation = DelayedDeliveryPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), }) public void getDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1912,14 +2007,15 @@ public void getDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncRespo @POST @Path("/{tenant}/{namespace}/delayedDelivery") - @ApiOperation(value = "Set delayed delivery messages config on a namespace.") + @Operation(summary = "Set delayed delivery messages config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), }) public void setDelayedDeliveryPolicies(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Delayed delivery policies for the specified namespace") + @RequestBody(description = "Delayed delivery policies for the specified " + + "namespace") DelayedDeliveryPolicies deliveryPolicies) { validateNamespaceName(tenant, namespace); internalSetDelayedDelivery(deliveryPolicies); @@ -1927,11 +2023,11 @@ public void setDelayedDeliveryPolicies(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/delayedDelivery") - @ApiOperation(value = "Delete delayed delivery messages config on a namespace.") + @Operation(summary = "Delete delayed delivery messages config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), }) public void removeDelayedDeliveryPolicies(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1940,10 +2036,13 @@ public void removeDelayedDeliveryPolicies(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/inactiveTopicPolicies") - @ApiOperation(value = "Get inactive topic policies config on a namespace.", response = InactiveTopicPolicies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), }) + @Operation(summary = "Get inactive topic policies config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get inactive topic policies config on a namespace.", + content = @Content(schema = @Schema(implementation = InactiveTopicPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), }) public void getInactiveTopicPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -1963,12 +2062,12 @@ public void getInactiveTopicPolicies(@Suspended final AsyncResponse asyncRespons @DELETE @Path("/{tenant}/{namespace}/inactiveTopicPolicies") - @ApiOperation(value = "Remove inactive topic policies from a namespace.") + @Operation(summary = "Remove inactive topic policies from a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeInactiveTopicPolicies(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -1977,14 +2076,15 @@ public void removeInactiveTopicPolicies(@PathParam("tenant") String tenant, @POST @Path("/{tenant}/{namespace}/inactiveTopicPolicies") - @ApiOperation(value = "Set inactive topic policies config on a namespace.") + @Operation(summary = "Set inactive topic policies config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), }) public void setInactiveTopicPolicies(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Inactive topic policies for the specified namespace") + @RequestBody(description = "Inactive topic policies for the specified " + + "namespace") InactiveTopicPolicies inactiveTopicPolicies) { validateNamespaceName(tenant, namespace); internalSetInactiveTopic(inactiveTopicPolicies); @@ -1992,9 +2092,12 @@ public void setInactiveTopicPolicies(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/maxProducersPerTopic") - @ApiOperation(value = "Get maxProducersPerTopic config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxProducersPerTopic config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxProducersPerTopic config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getMaxProducersPerTopic( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2015,27 +2118,28 @@ public void getMaxProducersPerTopic( @POST @Path("/{tenant}/{namespace}/maxProducersPerTopic") - @ApiOperation(value = " Set maxProducersPerTopic configuration on a namespace.") + @Operation(summary = " Set maxProducersPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxProducersPerTopic value is not valid") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxProducersPerTopic value is not valid") }) public void setMaxProducersPerTopic(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum producers per topic", required = true) int maxProducersPerTopic) { + @RequestBody(description = "Number of maximum producers per topic", required = true) + int maxProducersPerTopic) { validateNamespaceName(tenant, namespace); internalSetMaxProducersPerTopic(maxProducersPerTopic); } @DELETE @Path("/{tenant}/{namespace}/maxProducersPerTopic") - @ApiOperation(value = "Remove maxProducersPerTopic configuration on a namespace.") + @Operation(summary = "Remove maxProducersPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void removeMaxProducersPerTopic(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2044,9 +2148,12 @@ public void removeMaxProducersPerTopic(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/deduplicationSnapshotInterval") - @ApiOperation(value = "Get deduplicationSnapshotInterval config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get deduplicationSnapshotInterval config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get deduplicationSnapshotInterval config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getDeduplicationSnapshotInterval( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2067,14 +2174,14 @@ public void getDeduplicationSnapshotInterval( @POST @Path("/{tenant}/{namespace}/deduplicationSnapshotInterval") - @ApiOperation(value = "Set deduplicationSnapshotInterval config on a namespace.") + @Operation(summary = "Set deduplicationSnapshotInterval config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist")}) public void setDeduplicationSnapshotInterval(@PathParam("tenant") String tenant , @PathParam("namespace") String namespace - , @ApiParam(value = "Interval to take deduplication snapshot per topic", required = true) + , @RequestBody(description = "Interval to take deduplication snapshot per topic", required = true) Integer interval) { validateNamespaceName(tenant, namespace); internalSetDeduplicationSnapshotInterval(interval); @@ -2082,9 +2189,12 @@ public void setDeduplicationSnapshotInterval(@PathParam("tenant") String tenant @GET @Path("/{tenant}/{namespace}/maxConsumersPerTopic") - @ApiOperation(value = "Get maxConsumersPerTopic config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxConsumersPerTopic config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxConsumersPerTopic config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getMaxConsumersPerTopic( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2105,27 +2215,28 @@ public void getMaxConsumersPerTopic( @POST @Path("/{tenant}/{namespace}/maxConsumersPerTopic") - @ApiOperation(value = " Set maxConsumersPerTopic configuration on a namespace.") + @Operation(summary = " Set maxConsumersPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxConsumersPerTopic value is not valid") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxConsumersPerTopic value is not valid") }) public void setMaxConsumersPerTopic(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum consumers per topic", required = true) int maxConsumersPerTopic) { + @RequestBody(description = "Number of maximum consumers per topic", required = true) + int maxConsumersPerTopic) { validateNamespaceName(tenant, namespace); internalSetMaxConsumersPerTopic(maxConsumersPerTopic); } @DELETE @Path("/{tenant}/{namespace}/maxConsumersPerTopic") - @ApiOperation(value = "Remove maxConsumersPerTopic configuration on a namespace.") + @Operation(summary = "Remove maxConsumersPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void removeMaxConsumersPerTopic(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2134,9 +2245,12 @@ public void removeMaxConsumersPerTopic(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/maxConsumersPerSubscription") - @ApiOperation(value = "Get maxConsumersPerSubscription config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxConsumersPerSubscription config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxConsumersPerSubscription config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getMaxConsumersPerSubscription( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2158,17 +2272,17 @@ public void getMaxConsumersPerSubscription( @POST @Path("/{tenant}/{namespace}/maxConsumersPerSubscription") - @ApiOperation(value = " Set maxConsumersPerSubscription configuration on a namespace.") + @Operation(summary = " Set maxConsumersPerSubscription configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxConsumersPerSubscription value is not valid")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxConsumersPerSubscription value is not valid")}) public void setMaxConsumersPerSubscription(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum consumers per subscription", - required = true) + @RequestBody(description = "Number of maximum consumers per " + + "subscription", required = true) int maxConsumersPerSubscription) { validateNamespaceName(tenant, namespace); internalSetMaxConsumersPerSubscription(maxConsumersPerSubscription); @@ -2176,13 +2290,13 @@ public void setMaxConsumersPerSubscription(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/maxConsumersPerSubscription") - @ApiOperation(value = " Set maxConsumersPerSubscription configuration on a namespace.") + @Operation(summary = " Set maxConsumersPerSubscription configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxConsumersPerSubscription value is not valid")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxConsumersPerSubscription value is not valid")}) public void removeMaxConsumersPerSubscription(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2191,9 +2305,12 @@ public void removeMaxConsumersPerSubscription(@PathParam("tenant") String tenant @GET @Path("/{tenant}/{namespace}/maxUnackedMessagesPerConsumer") - @ApiOperation(value = "Get maxUnackedMessagesPerConsumer config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxUnackedMessagesPerConsumer config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxUnackedMessagesPerConsumer config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getMaxUnackedMessagesPerConsumer(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -2213,17 +2330,17 @@ public void getMaxUnackedMessagesPerConsumer(@Suspended final AsyncResponse asyn @POST @Path("/{tenant}/{namespace}/maxUnackedMessagesPerConsumer") - @ApiOperation(value = " Set maxConsumersPerTopic configuration on a namespace.") + @Operation(summary = " Set maxConsumersPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxUnackedMessagesPerConsumer value is not valid")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxUnackedMessagesPerConsumer value is not valid")}) public void setMaxUnackedMessagesPerConsumer(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum unacked messages per consumer", - required = true) + @RequestBody(description = "Number of maximum unacked messages " + + "per consumer", required = true) int maxUnackedMessagesPerConsumer) { validateNamespaceName(tenant, namespace); internalSetMaxUnackedMessagesPerConsumer(maxUnackedMessagesPerConsumer); @@ -2231,11 +2348,11 @@ public void setMaxUnackedMessagesPerConsumer(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/maxUnackedMessagesPerConsumer") - @ApiOperation(value = "Remove maxUnackedMessagesPerConsumer config on a namespace.") + @Operation(summary = "Remove maxUnackedMessagesPerConsumer config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void removeMaxUnackedmessagesPerConsumer(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2244,9 +2361,13 @@ public void removeMaxUnackedmessagesPerConsumer(@PathParam("tenant") String tena @GET @Path("/{tenant}/{namespace}/maxUnackedMessagesPerSubscription") - @ApiOperation(value = "Get maxUnackedMessagesPerSubscription config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxUnackedMessagesPerSubscription config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get maxUnackedMessagesPerSubscription config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getMaxUnackedmessagesPerSubscription( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2267,16 +2388,16 @@ public void getMaxUnackedmessagesPerSubscription( @POST @Path("/{tenant}/{namespace}/maxUnackedMessagesPerSubscription") - @ApiOperation(value = " Set maxUnackedMessagesPerSubscription configuration on a namespace.") + @Operation(summary = " Set maxUnackedMessagesPerSubscription configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxUnackedMessagesPerSubscription value is not valid")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxUnackedMessagesPerSubscription value is not valid")}) public void setMaxUnackedMessagesPerSubscription( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum unacked messages per subscription", required = true) + @RequestBody(description = "Number of maximum unacked messages per subscription", required = true) int maxUnackedMessagesPerSubscription) { validateNamespaceName(tenant, namespace); internalSetMaxUnackedMessagesPerSubscription(maxUnackedMessagesPerSubscription); @@ -2284,11 +2405,11 @@ public void setMaxUnackedMessagesPerSubscription( @DELETE @Path("/{tenant}/{namespace}/maxUnackedMessagesPerSubscription") - @ApiOperation(value = "Remove maxUnackedMessagesPerSubscription config on a namespace.") + @Operation(summary = "Remove maxUnackedMessagesPerSubscription config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void removeMaxUnackedmessagesPerSubscription(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2297,9 +2418,12 @@ public void removeMaxUnackedmessagesPerSubscription(@PathParam("tenant") String @GET @Path("/{tenant}/{namespace}/maxSubscriptionsPerTopic") - @ApiOperation(value = "Get maxSubscriptionsPerTopic config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxSubscriptionsPerTopic config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxSubscriptionsPerTopic config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -2319,16 +2443,16 @@ public void getMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/maxSubscriptionsPerTopic") - @ApiOperation(value = " Set maxSubscriptionsPerTopic configuration on a namespace.") + @Operation(summary = " Set maxSubscriptionsPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "maxUnackedMessagesPerSubscription value is not valid")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "maxUnackedMessagesPerSubscription value is not valid")}) public void setMaxSubscriptionsPerTopic( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum subscriptions per topic", required = true) + @RequestBody(description = "Number of maximum subscriptions per topic", required = true) int maxSubscriptionsPerTopic) { validateNamespaceName(tenant, namespace); internalSetMaxSubscriptionsPerTopic(maxSubscriptionsPerTopic); @@ -2336,12 +2460,12 @@ public void setMaxSubscriptionsPerTopic( @DELETE @Path("/{tenant}/{namespace}/maxSubscriptionsPerTopic") - @ApiOperation(value = "Remove maxSubscriptionsPerTopic configuration on a namespace.") + @Operation(summary = "Remove maxSubscriptionsPerTopic configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void removeMaxSubscriptionsPerTopic(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2350,17 +2474,17 @@ public void removeMaxSubscriptionsPerTopic(@PathParam("tenant") String tenant, @POST @Path("/{tenant}/{namespace}/antiAffinity") - @ApiOperation(value = "Set anti-affinity group for a namespace") + @Operation(summary = "Set anti-affinity group for a namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid antiAffinityGroup")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid antiAffinityGroup")}) public void setNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Anti-affinity group for the specified namespace", - required = true) + @RequestBody(description = "Anti-affinity group for the specified " + + "namespace", required = true) String antiAffinityGroup) { validateNamespaceName(tenant, namespace); internalSetNamespaceAntiAffinityGroupAsync(antiAffinityGroup) @@ -2379,9 +2503,12 @@ public void setNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncResponse @GET @Path("/{tenant}/{namespace}/antiAffinity") - @ApiOperation(value = "Get anti-affinity group of a namespace.", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get anti-affinity group of a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get anti-affinity group of a namespace.", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -2401,12 +2528,12 @@ public void getNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncResponse @DELETE @Path("/{tenant}/{namespace}/antiAffinity") - @ApiOperation(value = "Remove anti-affinity group of a namespace.") + @Operation(summary = "Remove anti-affinity group of a namespace.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void removeNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -2426,11 +2553,15 @@ public void removeNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncRespo @GET @Path("{cluster}/antiAffinity/{group}") - @ApiOperation(value = "Get all namespaces that are grouped by given anti-affinity group in a given cluster." - + " api can be only accessed by admin of any of the existing tenant", - response = String.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 412, message = "Cluster not exist/Anti-affinity group can't be empty.")}) + @Operation(summary = "Get all namespaces that are grouped by given anti-affinity group in a given cluster." + + " api can be only accessed by admin of any of the existing tenant") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get all namespaces that are grouped by given anti-affinity group in a given cluster." + + " api can be only accessed by admin of any of the existing tenant", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "412", description = "Cluster not exist/Anti-affinity group can't be empty.")}) public void getAntiAffinityNamespaces(@Suspended AsyncResponse asyncResponse, @PathParam("cluster") String cluster, @PathParam("group") String antiAffinityGroup, @@ -2451,11 +2582,15 @@ public void getAntiAffinityNamespaces(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/compactionThreshold") - @ApiOperation(value = "Maximum number of uncompacted bytes in topics before compaction is triggered.", - notes = "The backlog size is compared to the threshold periodically. " - + "A threshold of 0 disabled automatic compaction", response = Long.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist") }) + @Operation(summary = "Maximum number of uncompacted bytes in topics before compaction is triggered.", + description = "The backlog size is compared to the threshold periodically. " + + "A threshold of 0 disabled automatic compaction") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Maximum number of uncompacted bytes in topics before compaction is triggered.", + content = @Content(schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist") }) public void getCompactionThreshold( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2476,18 +2611,18 @@ public void getCompactionThreshold( @PUT @Path("/{tenant}/{namespace}/compactionThreshold") - @ApiOperation(value = "Set maximum number of uncompacted bytes in a topic before compaction is triggered.", - notes = "The backlog size is compared to the threshold periodically. " + @Operation(summary = "Set maximum number of uncompacted bytes in a topic before compaction is triggered.", + description = "The backlog size is compared to the threshold periodically. " + "A threshold of 0 disabled automatic compaction") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "compactionThreshold value is not valid")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "compactionThreshold value is not valid")}) public void setCompactionThreshold(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Maximum number of uncompacted bytes" + @RequestBody(description = "Maximum number of uncompacted bytes" + " in a topic of the specified namespace", required = true) long newThreshold) { validateNamespaceName(tenant, namespace); @@ -2496,14 +2631,14 @@ public void setCompactionThreshold(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/compactionThreshold") - @ApiOperation(value = "Delete maximum number of uncompacted bytes in a topic before compaction is triggered.", - notes = "The backlog size is compared to the threshold periodically. " + @Operation(summary = "Delete maximum number of uncompacted bytes in a topic before compaction is triggered.", + description = "The backlog size is compared to the threshold periodically. " + "A threshold of 0 disabled automatic compaction") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void deleteCompactionThreshold(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2512,11 +2647,16 @@ public void deleteCompactionThreshold(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/offloadThreshold") - @ApiOperation(value = "Maximum number of bytes stored on the pulsar cluster for a topic," + @Operation(summary = "Maximum number of bytes stored on the pulsar cluster for a topic," + " before the broker will start offloading to longterm storage", - notes = "A negative value disables automatic offloading", response = Long.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist") }) + description = "A negative value disables automatic offloading") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Maximum number of bytes stored on the pulsar cluster for a topic," + + " before the broker will start offloading to longterm storage", + content = @Content(schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist") }) public void getOffloadThreshold( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2544,19 +2684,19 @@ public void getOffloadThreshold( @PUT @Path("/{tenant}/{namespace}/offloadThreshold") - @ApiOperation(value = "Set maximum number of bytes stored on the pulsar cluster for a topic," + @Operation(summary = "Set maximum number of bytes stored on the pulsar cluster for a topic," + " before the broker will start offloading to longterm storage", - notes = "-1 will revert to using the cluster default." + description = "-1 will revert to using the cluster default." + " A negative value disables automatic offloading. ") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "offloadThreshold value is not valid")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "offloadThreshold value is not valid")}) public void setOffloadThreshold(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = + @RequestBody(description = "Maximum number of bytes stored on the pulsar cluster" + " for a topic of the specified namespace", required = true) long newThreshold) { @@ -2566,11 +2706,16 @@ public void setOffloadThreshold(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/offloadThresholdInSeconds") - @ApiOperation(value = "Maximum number of bytes stored on the pulsar cluster for a topic," + @Operation(summary = "Maximum number of bytes stored on the pulsar cluster for a topic," + " before the broker will start offloading to longterm storage", - notes = "A negative value disables automatic offloading", response = Long.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist") }) + description = "A negative value disables automatic offloading") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Maximum number of bytes stored on the pulsar cluster for a topic," + + " before the broker will start offloading to longterm storage", + content = @Content(schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist") }) public void getOffloadThresholdInSeconds( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2598,15 +2743,15 @@ public void getOffloadThresholdInSeconds( @PUT @Path("/{tenant}/{namespace}/offloadThresholdInSeconds") - @ApiOperation(value = "Set maximum number of seconds stored on the pulsar cluster for a topic," + @Operation(summary = "Set maximum number of seconds stored on the pulsar cluster for a topic," + " before the broker will start offloading to longterm storage", - notes = "A negative value disables automatic offloading") + description = "A negative value disables automatic offloading") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "offloadThresholdInSeconds value is not valid") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "offloadThresholdInSeconds value is not valid") }) public void setOffloadThresholdInSeconds( @Suspended final AsyncResponse response, @PathParam("tenant") String tenant, @@ -2623,13 +2768,18 @@ public void setOffloadThresholdInSeconds( @GET @Path("/{tenant}/{namespace}/offloadDeletionLagMs") - @ApiOperation(value = "Number of milliseconds to wait before deleting a ledger segment which has been offloaded" + @Operation(summary = "Number of milliseconds to wait before deleting a ledger segment which has been offloaded" + " from the Pulsar cluster's local storage (i.e. BookKeeper)", - notes = "A negative value denotes that deletion has been completely disabled." + description = "A negative value denotes that deletion has been completely disabled." + " 'null' denotes that the topics in the namespace will fall back to the" - + " broker default for deletion lag.", response = Long.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist") }) + + " broker default for deletion lag.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Number of milliseconds to wait before deleting a ledger segment which has been " + + "offloaded from the Pulsar cluster's local storage (i.e. BookKeeper)", + content = @Content(schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist") }) public void getOffloadDeletionLag( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2656,18 +2806,18 @@ public void getOffloadDeletionLag( @PUT @Path("/{tenant}/{namespace}/offloadDeletionLagMs") - @ApiOperation(value = "Set number of milliseconds to wait before deleting a ledger segment which has been offloaded" + @Operation(summary = "Set number of milliseconds to wait before deleting a ledger segment which has been offloaded" + " from the Pulsar cluster's local storage (i.e. BookKeeper)", - notes = "A negative value disables the deletion completely.") + description = "A negative value disables the deletion completely.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "offloadDeletionLagMs value is not valid")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "offloadDeletionLagMs value is not valid")}) public void setOffloadDeletionLag(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = + @RequestBody(description = "New number of milliseconds to wait before deleting a ledger segment" + " which has been offloaded", required = true) long newDeletionLagMs) { @@ -2677,12 +2827,13 @@ public void setOffloadDeletionLag(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/offloadDeletionLagMs") - @ApiOperation(value = "Clear the namespace configured offload deletion lag. The topics in the namespace" + @Operation(summary = "Clear the namespace configured offload deletion lag. The topics in the namespace" + " will fallback to using the default configured deletion lag for the broker") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponses(value = { + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void clearOffloadDeletionLag(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2691,14 +2842,19 @@ public void clearOffloadDeletionLag(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/schemaAutoUpdateCompatibilityStrategy") - @ApiOperation(value = "The strategy used to check the compatibility of new schemas," + @Operation(summary = "The strategy used to check the compatibility of new schemas," + " provided by producers, before automatically updating the schema", - notes = "The value AutoUpdateDisabled prevents producers from updating the schema. " - + " If set to AutoUpdateDisabled, schemas must be updated through the REST api", - response = SchemaAutoUpdateCompatibilityStrategy.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + description = "The value AutoUpdateDisabled prevents producers from updating the schema. " + + " If set to AutoUpdateDisabled, schemas must be updated through the REST api") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "The strategy used to check the compatibility of new schemas," + + " provided by producers, before automatically updating the schema", + content = @Content(schema = + @Schema(implementation = SchemaAutoUpdateCompatibilityStrategy.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) @SuppressWarnings("deprecation") public SchemaAutoUpdateCompatibilityStrategy getSchemaAutoUpdateCompatibilityStrategy( @PathParam("tenant") String tenant, @@ -2709,20 +2865,20 @@ public SchemaAutoUpdateCompatibilityStrategy getSchemaAutoUpdateCompatibilityStr @PUT @Path("/{tenant}/{namespace}/schemaAutoUpdateCompatibilityStrategy") - @ApiOperation(value = "Update the strategy used to check the compatibility of new schemas," + @Operation(summary = "Update the strategy used to check the compatibility of new schemas," + " provided by producers, before automatically updating the schema", - notes = "The value AutoUpdateDisabled prevents producers from updating the schema. " + description = "The value AutoUpdateDisabled prevents producers from updating the schema. " + " If set to AutoUpdateDisabled, schemas must be updated through the REST api") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) @SuppressWarnings("deprecation") public void setSchemaAutoUpdateCompatibilityStrategy( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Strategy used to check the compatibility of new schemas") + @RequestBody(description = "Strategy used to check the compatibility of new schemas") SchemaAutoUpdateCompatibilityStrategy strategy) { validateNamespaceName(tenant, namespace); internalSetSchemaAutoUpdateCompatibilityStrategy(strategy); @@ -2730,11 +2886,13 @@ public void setSchemaAutoUpdateCompatibilityStrategy( @GET @Path("/{tenant}/{namespace}/schemaCompatibilityStrategy") - @ApiOperation(value = "The strategy of the namespace schema compatibility ", - response = SchemaCompatibilityStrategy.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @Operation(summary = "The strategy of the namespace schema compatibility ") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "The strategy of the namespace schema compatibility ", + content = @Content(schema = @Schema(implementation = SchemaCompatibilityStrategy.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getSchemaCompatibilityStrategy( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2756,16 +2914,16 @@ public void getSchemaCompatibilityStrategy( @PUT @Path("/{tenant}/{namespace}/schemaCompatibilityStrategy") - @ApiOperation(value = "Update the strategy used to check the compatibility of new schema") + @Operation(summary = "Update the strategy used to check the compatibility of new schema") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSchemaCompatibilityStrategy( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Strategy used to check the compatibility of new schema") + @RequestBody(description = "Strategy used to check the compatibility of new schema") SchemaCompatibilityStrategy strategy) { validateNamespaceName(tenant, namespace); internalSetSchemaCompatibilityStrategy(strategy); @@ -2773,10 +2931,13 @@ public void setSchemaCompatibilityStrategy( @GET @Path("/{tenant}/{namespace}/isAllowAutoUpdateSchema") - @ApiOperation(value = "The flag of whether allow auto update schema", response = Boolean.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @Operation(summary = "The flag of whether allow auto update schema") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "The flag of whether allow auto update schema", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getIsAllowAutoUpdateSchema( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2804,19 +2965,19 @@ public void getIsAllowAutoUpdateSchema( @POST @Path("/{tenant}/{namespace}/isAllowAutoUpdateSchema") - @ApiOperation(value = "Update flag of whether allow auto update schema") + @Operation(summary = "Update flag of whether allow auto update schema") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setIsAllowAutoUpdateSchema( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @QueryParam("allowAutoUpdateSchemaWithReplicator") - @ApiParam(value = "Allow replicator to auto update schema") + @Parameter(description = "Allow replicator to auto update schema") Boolean allowAutoUpdateSchemaWithReplicator, - @ApiParam(value = "Flag of whether to allow auto update schema", required = true) + @RequestBody(description = "Flag of whether to allow auto update schema", required = true) boolean isAllowAutoUpdateSchema) { validateNamespaceName(tenant, namespace); if (isAllowAutoUpdateSchema && allowAutoUpdateSchemaWithReplicator != null @@ -2829,11 +2990,14 @@ public void setIsAllowAutoUpdateSchema( @GET @Path("/{tenant}/{namespace}/subscriptionTypesEnabled") - @ApiOperation(value = "The set of whether allow subscription types", - response = SubscriptionType.class, responseContainer = "Set") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @Operation(summary = "The set of whether allow subscription types") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "The set of whether allow subscription types", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = SubscriptionType.class), + uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getSubscriptionTypesEnabled( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2859,16 +3023,16 @@ public void getSubscriptionTypesEnabled( @POST @Path("/{tenant}/{namespace}/subscriptionTypesEnabled") - @ApiOperation(value = "Update set of whether allow share sub type") + @Operation(summary = "Update set of whether allow share sub type") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSubscriptionTypesEnabled( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Set of whether allow subscription types", required = true) + @RequestBody(description = "Set of whether allow subscription types", required = true) Set subscriptionTypesEnabled) { validateNamespaceName(tenant, namespace); internalSetSubscriptionTypesEnabled(subscriptionTypesEnabled); @@ -2876,11 +3040,11 @@ public void setSubscriptionTypesEnabled( @DELETE @Path("/{tenant}/{namespace}/subscriptionTypesEnabled") - @ApiOperation(value = " Remove subscription types enabled on a namespace.") + @Operation(summary = " Remove subscription types enabled on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeSubscriptionTypesEnabled(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -2889,11 +3053,15 @@ public void removeSubscriptionTypesEnabled(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/allowedTopicPropertyKeysForMetrics") - @ApiOperation(value = "Get allowed topic property keys for metrics for a namespace.", - response = String.class, responseContainer = "Set") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @Operation(summary = "Get allowed topic property keys for metrics for a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get allowed topic property keys for metrics for a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class), + uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getAllowedTopicPropertyKeysForMetrics( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2915,17 +3083,17 @@ public void getAllowedTopicPropertyKeysForMetrics( @POST @Path("/{tenant}/{namespace}/allowedTopicPropertyKeysForMetrics") - @ApiOperation(value = "Set allowed topic property keys for metrics for a namespace") + @Operation(summary = "Set allowed topic property keys for metrics for a namespace") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setAllowedTopicPropertyKeysForMetrics( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Set of allowed topic property keys for metrics", required = true) + @RequestBody(description = "Set of allowed topic property keys for metrics", required = true) Set allowedKeys) { validateNamespaceName(tenant, namespace); internalSetAllowedTopicPropertyKeysForMetricsAsync(allowedKeys) @@ -2942,11 +3110,11 @@ public void setAllowedTopicPropertyKeysForMetrics( @DELETE @Path("/{tenant}/{namespace}/allowedTopicPropertyKeysForMetrics") - @ApiOperation(value = "Remove allowed topic property keys for metrics on a namespace.") + @Operation(summary = "Remove allowed topic property keys for metrics on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeAllowedTopicPropertyKeysForMetrics( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2966,14 +3134,16 @@ public void removeAllowedTopicPropertyKeysForMetrics( @GET @Path("/{tenant}/{namespace}/schemaValidationEnforced") - @ApiOperation(value = "Get schema validation enforced flag for namespace.", - notes = "If the flag is set to true, when a producer without a schema attempts to produce to a topic" - + " with schema in this namespace, the producer will be failed to connect. PLEASE be" - + " carefully on using this, since non-java clients don't support schema.if you enable" - + " this setting, it will cause non-java clients failed to produce.", - response = Boolean.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenants or Namespace doesn't exist") }) + @Operation(summary = "Get schema validation enforced flag for namespace.", + description = "If the flag is set to true, when a producer without a schema attempts to produce " + + "to a topic with schema in this namespace, the producer will be failed to connect. " + + "PLEASE be carefully on using this, since non-java clients don't support schema.if you " + + "enable this setting, it will cause non-java clients failed to produce.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get schema validation enforced flag for namespace.", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenants or Namespace doesn't exist") }) public void getSchemaValidtionEnforced( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3003,19 +3173,19 @@ public void getSchemaValidtionEnforced( @POST @Path("/{tenant}/{namespace}/schemaValidationEnforced") - @ApiOperation(value = "Set schema validation enforced flag on namespace.", - notes = "If the flag is set to true, when a producer without a schema attempts to produce to a topic" + @Operation(summary = "Set schema validation enforced flag on namespace.", + description = "If the flag is set to true, when a producer without a schema attempts to produce to a topic" + " with schema in this namespace, the producer will be failed to connect. PLEASE be" + " carefully on using this, since non-java clients don't support schema.if you enable" + " this setting, it will cause non-java clients failed to produce.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or Namespace doesn't exist"), - @ApiResponse(code = 412, message = "schemaValidationEnforced value is not valid")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "schemaValidationEnforced value is not valid")}) public void setSchemaValidationEnforced(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = + @RequestBody(description = "Flag of whether validation is enforced on the specified namespace", required = true) boolean schemaValidationEnforced) { @@ -3025,16 +3195,17 @@ public void setSchemaValidationEnforced(@PathParam("tenant") String tenant, @POST @Path("/{tenant}/{namespace}/offloadPolicies") - @ApiOperation(value = "Set offload configuration on a namespace.") - @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, - message = "OffloadPolicies is empty or driver is not supported or bucket is not valid")}) + @Operation(summary = "Set offload configuration on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", + description = "OffloadPolicies is empty or driver is not supported or bucket is not valid")}) public void setOffloadPolicies(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Offload policies for the specified namespace", required = true) + @RequestBody(description = "Offload policies for the specified namespace", + required = true) OffloadPoliciesImpl offload, @Suspended final AsyncResponse asyncResponse) { try { @@ -3049,14 +3220,14 @@ public void setOffloadPolicies(@PathParam("tenant") String tenant, @PathParam("n @DELETE @Path("/{tenant}/{namespace}/removeOffloadPolicies") - @ApiOperation(value = " Set offload configuration on a namespace.") - @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, - message = "OffloadPolicies is empty or driver is not supported or bucket is not valid")}) + @Operation(summary = " Set offload configuration on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", + description = "OffloadPolicies is empty or driver is not supported or bucket is not valid")}) public void removeOffloadPolicies(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @Suspended final AsyncResponse asyncResponse) { try { @@ -3071,10 +3242,12 @@ public void removeOffloadPolicies(@PathParam("tenant") String tenant, @PathParam @GET @Path("/{tenant}/{namespace}/offloadPolicies") - @ApiOperation(value = "Get offload configuration on a namespace.", response = OffloadPolicies.class) + @Operation(summary = "Get offload configuration on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist")}) + @ApiResponse(responseCode = "200", description = "Get offload configuration on a namespace.", + content = @Content(schema = @Schema(implementation = OffloadPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist")}) public void getOffloadPolicies( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3095,9 +3268,12 @@ public void getOffloadPolicies( @GET @Path("/{tenant}/{namespace}/maxTopicsPerNamespace") - @ApiOperation(value = "Get maxTopicsPerNamespace config on a namespace.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace does not exist") }) + @Operation(summary = "Get maxTopicsPerNamespace config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxTopicsPerNamespace config on a namespace.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace does not exist") }) public void getMaxTopicsPerNamespace(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -3121,14 +3297,14 @@ public void getMaxTopicsPerNamespace(@Suspended final AsyncResponse asyncRespons @POST @Path("/{tenant}/{namespace}/maxTopicsPerNamespace") - @ApiOperation(value = "Set maxTopicsPerNamespace config on a namespace.") + @Operation(summary = "Set maxTopicsPerNamespace config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void setMaxTopicsPerNamespace(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Number of maximum topics for specific namespace", + @RequestBody(description = "Number of maximum topics for specific namespace", required = true) int maxTopicsPerNamespace) { validateNamespaceName(tenant, namespace); internalSetMaxTopicsPerNamespace(maxTopicsPerNamespace); @@ -3136,11 +3312,11 @@ public void setMaxTopicsPerNamespace(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/maxTopicsPerNamespace") - @ApiOperation(value = "Remove maxTopicsPerNamespace config on a namespace.") + @Operation(summary = "Remove maxTopicsPerNamespace config on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void removeMaxTopicsPerNamespace(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -3149,11 +3325,11 @@ public void removeMaxTopicsPerNamespace(@PathParam("tenant") String tenant, @PUT @Path("/{tenant}/{namespace}/property/{key}/{value}") - @ApiOperation(value = "Put a key value pair property on a namespace.") + @Operation(summary = "Put a key value pair property on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void setProperty( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3166,9 +3342,12 @@ public void setProperty( @GET @Path("/{tenant}/{namespace}/property/{key}") - @ApiOperation(value = "Get property value for a given key on a namespace.", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @Operation(summary = "Get property value for a given key on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get property value for a given key on a namespace.", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void getProperty( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3180,11 +3359,11 @@ public void getProperty( @DELETE @Path("/{tenant}/{namespace}/property/{key}") - @ApiOperation(value = "Remove property value for a given key on a namespace.") + @Operation(summary = "Remove property value for a given key on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void removeProperty( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3196,16 +3375,16 @@ public void removeProperty( @PUT @Path("/{tenant}/{namespace}/properties") - @ApiOperation(value = "Put key value pairs property on a namespace.") + @Operation(summary = "Put key value pairs property on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void setProperties( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "Key value pair properties for the namespace", required = true) + @RequestBody(description = "Key value pair properties for the namespace", required = true) Map properties) { validateNamespaceName(tenant, namespace); internalSetProperties(properties, asyncResponse); @@ -3213,10 +3392,12 @@ public void setProperties( @GET @Path("/{tenant}/{namespace}/properties") - @ApiOperation(value = "Get key value pair properties for a given namespace.", - response = String.class, responseContainer = "Map") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @Operation(summary = "Get key value pair properties for a given namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get key value pair properties for a given namespace.", + content = @Content(schema = @Schema(type = "object", additionalPropertiesSchema = String.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void getProperties( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3227,11 +3408,11 @@ public void getProperties( @DELETE @Path("/{tenant}/{namespace}/properties") - @ApiOperation(value = "Clear properties on a given namespace.") + @Operation(summary = "Clear properties on a given namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), }) public void clearProperties( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3242,9 +3423,12 @@ public void clearProperties( @GET @Path("/{tenant}/{namespace}/resourcegroup") - @ApiOperation(value = "Get the resource group attached to the namespace", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get the resource group attached to the namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the resource group attached to the namespace", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getNamespaceResourceGroup( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3266,12 +3450,12 @@ public void getNamespaceResourceGroup( @POST @Path("/{tenant}/{namespace}/resourcegroup/{resourcegroup}") - @ApiOperation(value = "Set resourcegroup for a namespace") + @Operation(summary = "Set resourcegroup for a namespace") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid resourcegroup") }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid resourcegroup") }) public void setNamespaceResourceGroup(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("resourcegroup") String rgName) { validateNamespaceName(tenant, namespace); @@ -3280,12 +3464,12 @@ public void setNamespaceResourceGroup(@PathParam("tenant") String tenant, @PathP @DELETE @Path("/{tenant}/{namespace}/resourcegroup") - @ApiOperation(value = "Delete resourcegroup for a namespace") + @Operation(summary = "Delete resourcegroup for a namespace") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid resourcegroup")}) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid resourcegroup")}) public void removeNamespaceResourceGroup(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -3294,15 +3478,16 @@ public void removeNamespaceResourceGroup(@PathParam("tenant") String tenant, @GET @Path("/{tenant}/{namespace}/scanOffloadedLedgers") - @ApiOperation(value = "Trigger the scan of offloaded Ledgers on the LedgerOffloader for the given namespace") - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Successful get of offloaded ledger data", response = String.class, - examples = @Example(value = { @ExampleProperty(mediaType = "application/json", - value = "{\"objects\":[{\"key1\":\"value1\",\"key2\":\"value2\"}]," - + "\"total\":100,\"errors\":5,\"unknown\":3}") - })), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist") }) + @Operation(summary = "Trigger the scan of offloaded Ledgers on the LedgerOffloader for the given namespace") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successful get of offloaded ledger data", + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = String.class), + examples = @ExampleObject( + value = "{\"objects\":[{\"key1\":\"value1\",\"key2\":\"value2\"}]," + + "\"total\":100,\"errors\":5,\"unknown\":3}"))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist") }) public Response scanOffloadedLedgers(@PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { validateNamespaceName(tenant, namespace); @@ -3353,9 +3538,12 @@ public void finished(int total, int errors, int unknown) throws Exception { @GET @Path("/{tenant}/{namespace}/entryFilters") - @ApiOperation(value = "Get maxConsumersPerSubscription config on a namespace.", response = EntryFilters.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @Operation(summary = "Get maxConsumersPerSubscription config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get maxConsumersPerSubscription config on a namespace.", + content = @Content(schema = @Schema(implementation = EntryFilters.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getEntryFiltersPerTopic( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -3377,16 +3565,16 @@ public void getEntryFiltersPerTopic( @POST @Path("/{tenant}/{namespace}/entryFilters") - @ApiOperation(value = "Set entry filters for namespace") + @Operation(summary = "Set entry filters for namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 400, message = "Specified entry filters are not valid"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Specified entry filters are not valid"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void setEntryFiltersPerTopic(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "entry filters", required = true) + @RequestBody(description = "entry filters", required = true) EntryFilters entryFilters) { validateNamespaceName(tenant, namespace); internalSetEntryFiltersPerTopicAsync(entryFilters) @@ -3403,12 +3591,12 @@ public void setEntryFiltersPerTopic(@Suspended AsyncResponse asyncResponse, @Pat @DELETE @Path("/{tenant}/{namespace}/entryFilters") - @ApiOperation(value = "Remove entry filters for namespace") + @Operation(summary = "Remove entry filters for namespace") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Invalid TTL")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Invalid TTL")}) public void removeNamespaceEntryFilters(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -3427,11 +3615,11 @@ public void removeNamespaceEntryFilters(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/migration") - @ApiOperation(hidden = true, value = "Update migration for all topics in a namespace") + @Operation(hidden = true, summary = "Update migration for all topics in a namespace") @ApiResponses(value = { - @ApiResponse(code = 200, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Property or cluster or namespace doesn't exist") }) + @ApiResponse(responseCode = "200", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Property or cluster or namespace doesn't exist") }) public void enableMigration(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @@ -3452,12 +3640,12 @@ public void enableMigration(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/dispatcherPauseOnAckStatePersistent") - @ApiOperation(value = "Set dispatcher pause on ack state persistent configuration for specified namespace.") + @Operation(summary = "Set dispatcher pause on ack state persistent configuration for specified namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -3477,12 +3665,12 @@ public void setDispatcherPauseOnAckStatePersistent(@Suspended final AsyncRespons @DELETE @Path("/{tenant}/{namespace}/dispatcherPauseOnAckStatePersistent") - @ApiOperation(value = "Remove dispatcher pause on ack state persistent configuration for specified namespace.") + @Operation(summary = "Remove dispatcher pause on ack state persistent configuration for specified namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -3502,10 +3690,13 @@ public void removeDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResp @GET @Path("/{tenant}/{namespace}/dispatcherPauseOnAckStatePersistent") - @ApiOperation(value = "Get dispatcher pause on ack state persistent config on a namespace.", - response = Boolean.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist") }) + @Operation(summary = "Get dispatcher pause on ack state persistent config on a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get dispatcher pause on ack state persistent config on a namespace.", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist") }) public void getDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { @@ -3520,17 +3711,20 @@ public void getDispatcherPauseOnAckStatePersistent(@Suspended final AsyncRespons @POST @Path("/{tenant}/{namespace}/allowedClusters") - @ApiOperation(value = "Set the allowed clusters for a namespace.") - @ApiResponses(value = { - @ApiResponse(code = 400, message = "The list of allowed clusters should include all replication clusters."), - @ApiResponse(code = 403, message = "The requester does not have admin permissions."), - @ApiResponse(code = 404, message = "The specified tenant, cluster, or namespace does not exist."), - @ApiResponse(code = 409, message = "A peer-cluster cannot be part of an allowed-cluster."), - @ApiResponse(code = 412, message = "The namespace is not global or the provided cluster IDs are invalid.")}) + @Operation(summary = "Set the allowed clusters for a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "400", + description = "The list of allowed clusters should include all replication clusters."), + @ApiResponse(responseCode = "403", description = "The requester does not have admin permissions."), + @ApiResponse(responseCode = "404", + description = "The specified tenant, cluster, or namespace does not exist."), + @ApiResponse(responseCode = "409", description = "A peer-cluster cannot be part of an allowed-cluster."), + @ApiResponse(responseCode = "412", + description = "The namespace is not global or the provided cluster IDs are invalid.")}) public void setNamespaceAllowedClusters(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @ApiParam(value = "List of allowed clusters", required = true) + @RequestBody(description = "List of allowed clusters", required = true) List clusterIds) { validateNamespaceName(tenant, namespace); internalSetNamespaceAllowedClusters(clusterIds) @@ -3547,11 +3741,13 @@ public void setNamespaceAllowedClusters(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/allowedClusters") - @ApiOperation(value = "Get the allowed clusters for a namespace.", - response = String.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace doesn't exist"), - @ApiResponse(code = 412, message = "Namespace is not global")}) + @Operation(summary = "Get the allowed clusters for a namespace.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the allowed clusters for a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Namespace is not global")}) public void getNamespaceAllowedClusters(@Suspended AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java index d54a3698342c8..0856d481ced9f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java @@ -18,11 +18,15 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -67,32 +71,36 @@ */ @Path("/non-persistent") @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/non-persistent", description = "Non-Persistent topic admin apis", tags = "non-persistent topic") +@Tag(name = "non-persistent topic", description = "Non-Persistent topic admin apis") @SuppressWarnings("deprecation") public class NonPersistentTopics extends PersistentTopics { @GET @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Get partitioned topic metadata.", response = PartitionedTopicMetadata.class) + @Operation(summary = "Get partitioned topic metadata.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to manage resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "The tenant/namespace/topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate cluster configuration") + @ApiResponse(responseCode = "200", description = "Get partitioned topic metadata.", + content = @Content(schema = @Schema(implementation = PartitionedTopicMetadata.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to manage resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "The tenant/namespace/topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate cluster configuration") }) public void getPartitionedMetadata( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Is check configuration required to automatically create topic") + @Parameter(description = "Is check configuration required to automatically create topic") @QueryParam("checkAllowAutoCreation") @DefaultValue("false") boolean checkAllowAutoCreation) { validateTopicName(tenant, namespace, encodedTopic); validateTopicOwnershipAsync(topicName, authoritative).whenComplete((__, ex) -> { @@ -115,24 +123,28 @@ public void getPartitionedMetadata( @GET @Path("{tenant}/{namespace}/{topic}/internalStats") - @ApiOperation(value = "Get the internal stats for the topic.", response = PersistentTopicInternalStats.class) + @Operation(summary = "Get the internal stats for the topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to manage resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "The tenant/namespace/topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), + @ApiResponse(responseCode = "200", description = "Get the internal stats for the topic.", + content = @Content(schema = @Schema(implementation = PersistentTopicInternalStats.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to manage resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "The tenant/namespace/topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getInternalStats( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("metadata") @DefaultValue("false") boolean metadata) { validateTopicName(tenant, namespace, encodedTopic); @@ -158,32 +170,35 @@ public void getInternalStats( @PUT @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Create a partitioned topic.", - notes = "It needs to be called before creating a producer on a partitioned topic.") + @Operation(summary = "Create a partitioned topic.", + description = "It needs to be called before creating a producer on a partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to manage resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "The tenant/namespace does not exist"), - @ApiResponse(code = 406, message = "The number of partitions should be more than 0 and less than" - + " or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(code = 409, message = "Partitioned topic already exists"), - @ApiResponse(code = 412, message = "Failed Reason : Name is invalid or " + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to manage resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "The tenant/namespace does not exist"), + @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and less" + + " than or equal to maxNumPartitionsPerPartitionedTopic"), + @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), + @ApiResponse(responseCode = "412", description = "Failed Reason : Name is invalid or " + "Namespace does not have any clusters configured"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration"), }) public void createPartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "The number of partitions for the topic", - required = true, type = "int", defaultValue = "0") + @RequestBody(description = "The number of partitions for the topic", + required = true, + content = @Content(schema = @Schema(type = "integer", defaultValue = "0"))) int numPartitions, @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { try { @@ -202,41 +217,45 @@ public void createPartitionedTopic( @GET @Path("{tenant}/{namespace}/{topic}/partitioned-stats") - @ApiOperation( - value = "Get the stats for the partitioned topic.", - response = NonPersistentPartitionedTopicStatsImpl.class + @Operation( + summary = "Get the stats for the partitioned topic." ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "200", description = "Get the stats for the partitioned topic.", + content = @Content(schema = + @Schema(implementation = NonPersistentPartitionedTopicStatsImpl.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getPartitionedStats( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Get per partition stats") + @Parameter(description = "Get per partition stats") @QueryParam("perPartition") @DefaultValue("true") boolean perPartition, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "If return precise backlog or imprecise backlog") + @Parameter(description = "If return precise backlog or imprecise backlog") @QueryParam("getPreciseBacklog") @DefaultValue("false") boolean getPreciseBacklog, - @ApiParam(value = "If return backlog size for each subscription, require locking on ledger so be careful " - + "not to use when there's heavy traffic.") + @Parameter(description = "If return backlog size for each subscription, require locking on ledger so be " + + "careful not to use when there's heavy traffic.") @QueryParam("subscriptionBacklogSize") @DefaultValue("false") boolean subscriptionBacklogSize, - @ApiParam(value = "If return the earliest time in backlog") + @Parameter(description = "If return the earliest time in backlog") @QueryParam("getEarliestTimeInBacklog") @DefaultValue("false") boolean getEarliestTimeInBacklog, - @ApiParam(value = "If exclude the publishers") + @Parameter(description = "If exclude the publishers") @QueryParam("excludePublishers") @DefaultValue("false") boolean excludePublishers, - @ApiParam(value = "If exclude the consumers") + @Parameter(description = "If exclude the consumers") @QueryParam("excludeConsumers") @DefaultValue("false") boolean excludeConsumers) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -337,26 +356,27 @@ public void getPartitionedStats( @PUT @Path("/{tenant}/{namespace}/{topic}/unload") - @ApiOperation(value = "Unload a topic") + @Operation(summary = "Unload a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "The tenant/namespace/topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration"), + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "The tenant/namespace/topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration"), }) public void unloadTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -370,26 +390,28 @@ public void unloadTopic( @GET @Path("/{tenant}/{namespace}") - @ApiOperation(value = "Get the list of non-persistent topics under a namespace.", - response = String.class, responseContainer = "List") + @Operation(summary = "Get the list of non-persistent topics under a namespace.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to manage resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "The tenant/namespace does not exist"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration"), + @ApiResponse(responseCode = "200", description = "Get the list of non-persistent topics under a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to manage resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "The tenant/namespace does not exist"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration"), }) @SuppressWarnings("deprecation") public void getList( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the bundle name", required = false) + @Parameter(description = "Specify the bundle name", required = false) @QueryParam("bundle") String nsBundle, - @ApiParam(value = "Include system topic") + @Parameter(description = "Include system topic") @QueryParam("includeSystemTopic") boolean includeSystemTopic, @QueryParam("properties") String propertiesStr) { Policies policies = null; @@ -453,24 +475,27 @@ public void getList( @GET @Path("/{tenant}/{namespace}/{bundle}") - @ApiOperation(value = "Get the list of non-persistent topics under a namespace bundle.", - response = String.class, responseContainer = "List") + @Operation(summary = "Get the list of non-persistent topics under a namespace bundle.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to manage resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace doesn't exist"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration"), + @ApiResponse(responseCode = "200", + description = "Get the list of non-persistent topics under a namespace bundle.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to manage resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration"), }) @SuppressWarnings("deprecation") public void getListFromBundle( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Bundle range of a topic", required = true) + @Parameter(description = "Bundle range of a topic", required = true) @PathParam("bundle") String bundleRange) { validateNamespaceName(tenant, namespace); log.debug() @@ -534,21 +559,21 @@ public void getListFromBundle( @DELETE @Path("/{tenant}/{namespace}/{topic}/truncate") - @ApiOperation(value = "Truncate a topic.", - notes = "NonPersistentTopic does not support truncate.") + @Operation(summary = "Truncate a topic.", + description = "NonPersistentTopic does not support truncate.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 412, message = "NonPersistentTopic does not support truncate.") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "412", description = "NonPersistentTopic does not support truncate.") }) public void truncateTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative){ asyncResponse.resume(new RestException(Status.PRECONDITION_FAILED.getStatusCode(), "unsupport truncate")); @@ -561,19 +586,22 @@ protected void validateAdminOperationOnTopic(TopicName topicName, boolean author @GET @Path("/{tenant}/{namespace}/{topic}/entryFilters") - @ApiOperation(value = "Get entry filters for a topic.", response = EntryFilters.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenants or Namespace doesn't exist") }) + @Operation(summary = "Get entry filters for a topic.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get entry filters for a topic.", + content = @Content(schema = @Schema(implementation = EntryFilters.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenants or Namespace doesn't exist") }) public void getEntryFilters(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this " + @Parameter(description = "Whether leader broker redirected this call to this " + "broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -588,23 +616,23 @@ public void getEntryFilters(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/entryFilters") - @ApiOperation(value = "Set entry filters for specified topic") + @Operation(summary = "Set entry filters for specified topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this " + @Parameter(description = "Whether leader broker redirected this " + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Enable sub types for the specified topic") + @RequestBody(description = "Enable sub types for the specified topic") EntryFilters entryFilters) { validateTopicName(tenant, namespace, encodedTopic); preValidation(authoritative) @@ -618,20 +646,20 @@ public void setEntryFilters(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/entryFilters") - @ApiOperation(value = "Remove entry filters for specified topic.") + @Operation(summary = "Remove entry filters for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this" + @Parameter(description = "Whether leader broker redirected this" + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java index 5903ceab3803a..1249e7315c51d 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java @@ -20,11 +20,15 @@ import static org.apache.pulsar.common.util.Codec.decode; import com.fasterxml.jackson.core.JsonProcessingException; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -99,31 +103,35 @@ */ @Path("/persistent") @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/persistent", description = "Persistent topic admin apis", tags = "persistent topic") +@Tag(name = "persistent topic", description = "Persistent topic admin apis") @SuppressWarnings("deprecation") public class PersistentTopics extends PersistentTopicsBase { @GET @Path("/{tenant}/{namespace}") - @ApiOperation(value = "Get the list of topics under a namespace.", - response = String.class, responseContainer = "List") + @Operation(summary = "Get the list of topics under a namespace.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse( + responseCode = "200", + description = "Get the list of topics under a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getList( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the bundle name", required = false) + @Parameter(description = "Specify the bundle name", required = false) @QueryParam("bundle") String bundle, - @ApiParam(value = "Include system topic") + @Parameter(description = "Include system topic") @QueryParam("includeSystemTopic") boolean includeSystemTopic, - @ApiParam(value = "properties for customized topic listing plugin, format: k1=v1,k2=v2") + @Parameter(description = "properties for customized topic listing plugin, format: k1=v1,k2=v2") @QueryParam("properties") String propertiesStr) { validateNamespaceName(tenant, namespace); internalGetListAsync(Optional.ofNullable(bundle), parseProperties(propertiesStr)) @@ -142,21 +150,25 @@ public void getList( @GET @Path("/{tenant}/{namespace}/partitioned") - @ApiOperation(value = "Get the list of partitioned topics under a namespace.", - response = String.class, responseContainer = "List") + @Operation(summary = "Get the list of partitioned topics under a namespace.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin or operate permission on the namespace"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse( + responseCode = "200", + description = "Get the list of partitioned topics under a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getPartitionedTopicList( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Include system topic") + @Parameter(description = "Include system topic") @QueryParam("includeSystemTopic") boolean includeSystemTopic) { validateNamespaceName(tenant, namespace); internalGetPartitionedTopicListAsync() @@ -176,26 +188,31 @@ public void getPartitionedTopicList( @GET @Path("/{tenant}/{namespace}/{topic}/permissions") - @ApiOperation(value = "Get permissions on a topic.", - notes = "Retrieve the effective permissions for a topic." + @Operation(summary = "Get permissions on a topic.", + description = "Retrieve the effective permissions for a topic." + " These permissions are defined by the permissions set at the" + "namespace level combined (union) with any eventual specific permission set on the topic." - + "Returns a nested map structure which Swagger does not fully support for display. " - + "Structure: Map>. Please refer to this structure for details.", - response = AuthAction.class, responseContainer = "Map") + + " Returns a map structure: Map>.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse( + responseCode = "200", + description = "Get permissions on a topic.", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesArraySchema = @ArraySchema( + schema = @Schema(implementation = AuthAction.class), uniqueItems = true))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getPermissionsOnTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -219,28 +236,30 @@ public void getPermissionsOnTopic( @POST @Path("/{tenant}/{namespace}/{topic}/permissions/{role}") - @ApiOperation(value = "Grant a new permission to a role on a single topic.") + @Operation(summary = "Grant a new permission to a role on a single topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void grantPermissionsOnTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Client role to which grant permissions", required = true) + @Parameter(description = "Client role to which grant permissions", required = true) @PathParam("role") String role, - @ApiParam(value = "Actions to be granted (produce,functions,consume)", - allowableValues = "produce,functions,consume") + @RequestBody(description = "Actions to be granted (produce,functions,consume)", + content = @Content(schema = @Schema(allowableValues = {"produce", "functions", "consume"}))) Set actions) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -254,27 +273,29 @@ public void grantPermissionsOnTopic( @DELETE @Path("/{tenant}/{namespace}/{topic}/permissions/{role}") - @ApiOperation(value = "Revoke permissions on a topic.", - notes = "Revoke permissions to a role on a single topic. If the permission was not set at the topic" + @Operation(summary = "Revoke permissions on a topic.", + description = "Revoke permissions to a role on a single topic. If the permission was not set at the topic" + "level, but rather at the namespace level," + " this operation will return an error (HTTP status code 412).") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Permissions are not set at the topic level"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Permissions are not set at the topic level"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void revokePermissionsOnTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Client role to which grant permissions", required = true) + @Parameter(description = "Client role to which grant permissions", required = true) @PathParam("role") String role) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -288,32 +309,34 @@ public void revokePermissionsOnTopic( @PUT @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Create a partitioned topic.", - notes = "It needs to be called before creating a producer on a partitioned topic.") + @Operation(summary = "Create a partitioned topic.", + description = "It needs to be called before creating a producer on a partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 406, message = "The number of partitions should be more than 0 and" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(code = 409, message = "Partitioned topic already exist"), - @ApiResponse(code = 412, - message = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "412", + description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void createPartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "The number of partitions for the topic", - required = true, type = "int", defaultValue = "0") + @RequestBody(description = "The number of partitions for the topic", + required = true, content = @Content(schema = @Schema(type = "integer", defaultValue = "0"))) int numPartitions, @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { try { @@ -334,31 +357,33 @@ public void createPartitionedTopic( @PUT @Path("/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Create a non-partitioned topic.", - notes = "This is the only REST endpoint from which non-partitioned topics could be created.") + @Operation(summary = "Create a non-partitioned topic.", + description = "This is the only REST endpoint from which non-partitioned topics could be created.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 409, message = "Partitioned topic already exist"), - @ApiResponse(code = 412, - message = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "412", + description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void createNonPartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Key value pair properties for the topic metadata") + @RequestBody(description = "Key value pair properties for the topic metadata") Map properties) { validateNamespaceName(tenant, namespace); validateGlobalNamespaceOwnership(); @@ -380,17 +405,21 @@ public void createNonPartitionedTopic( @GET @Path("/{tenant}/{namespace}/{topic}/offloadPolicies") - @ApiOperation(value = "Get offload policies on a topic.", response = OffloadPoliciesImpl.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get offload policies on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get offload policies on a topic.", + content = @Content(schema = @Schema(implementation = OffloadPoliciesImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getOffloadPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.OFFLOAD, PolicyOperation.READ) @@ -405,19 +434,21 @@ public void getOffloadPolicies(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/offloadPolicies") - @ApiOperation(value = "Set offload policies on a topic.") + @Operation(summary = "Set offload policies on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void setOffloadPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Offload policies for the specified topic") OffloadPoliciesImpl offloadPolicies) { + @RequestBody(description = "Offload policies for the specified topic") + OffloadPoliciesImpl offloadPolicies) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.OFFLOAD, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -432,17 +463,18 @@ public void setOffloadPolicies(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/offloadPolicies") - @ApiOperation(value = "Delete offload policies on a topic.") + @Operation(summary = "Delete offload policies on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void removeOffloadPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.OFFLOAD, PolicyOperation.WRITE) @@ -457,17 +489,21 @@ public void removeOffloadPolicies(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/maxUnackedMessagesOnConsumer") - @ApiOperation(value = "Get max unacked messages per consumer config on a topic.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get max unacked messages per consumer config on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get max unacked messages per consumer config on a topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getMaxUnackedMessagesOnConsumer(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_UNACKED, PolicyOperation.READ) @@ -481,20 +517,21 @@ public void getMaxUnackedMessagesOnConsumer(@Suspended final AsyncResponse async @POST @Path("/{tenant}/{namespace}/{topic}/maxUnackedMessagesOnConsumer") - @ApiOperation(value = "Set max unacked messages per consumer config on a topic.") + @Operation(summary = "Set max unacked messages per consumer config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void setMaxUnackedMessagesOnConsumer( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Max unacked messages on consumer policies for the specified topic") + @RequestBody(description = "Max unacked messages on consumer policies for the specified topic") Integer maxUnackedNum) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_UNACKED, PolicyOperation.WRITE) @@ -509,17 +546,18 @@ public void setMaxUnackedMessagesOnConsumer( @DELETE @Path("/{tenant}/{namespace}/{topic}/maxUnackedMessagesOnConsumer") - @ApiOperation(value = "Delete max unacked messages per consumer config on a topic.") + @Operation(summary = "Delete max unacked messages per consumer config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void deleteMaxUnackedMessagesOnConsumer(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_UNACKED, PolicyOperation.WRITE) @@ -534,16 +572,20 @@ public void deleteMaxUnackedMessagesOnConsumer(@Suspended final AsyncResponse as @GET @Path("/{tenant}/{namespace}/{topic}/deduplicationSnapshotInterval") - @ApiOperation(value = "Get deduplicationSnapshotInterval config on a topic.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get deduplicationSnapshotInterval config on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get deduplicationSnapshotInterval config on a topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getDeduplicationSnapshotInterval(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.DEDUPLICATION_SNAPSHOT, PolicyOperation.READ) @@ -561,20 +603,21 @@ public void getDeduplicationSnapshotInterval(@Suspended final AsyncResponse asyn @POST @Path("/{tenant}/{namespace}/{topic}/deduplicationSnapshotInterval") - @ApiOperation(value = "Set deduplicationSnapshotInterval config on a topic.") + @Operation(summary = "Set deduplicationSnapshotInterval config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void setDeduplicationSnapshotInterval( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Interval to take deduplication snapshot for the specified topic") + @RequestBody(description = "Interval to take deduplication snapshot for the specified topic") Integer interval, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.DEDUPLICATION_SNAPSHOT, PolicyOperation.WRITE) @@ -589,17 +632,18 @@ public void setDeduplicationSnapshotInterval( @DELETE @Path("/{tenant}/{namespace}/{topic}/deduplicationSnapshotInterval") - @ApiOperation(value = "Delete deduplicationSnapshotInterval config on a topic.") + @Operation(summary = "Delete deduplicationSnapshotInterval config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void deleteDeduplicationSnapshotInterval(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.DEDUPLICATION_SNAPSHOT, PolicyOperation.WRITE) @@ -614,17 +658,21 @@ public void deleteDeduplicationSnapshotInterval(@Suspended final AsyncResponse a @GET @Path("/{tenant}/{namespace}/{topic}/inactiveTopicPolicies") - @ApiOperation(value = "Get inactive topic policies on a topic.", response = InactiveTopicPolicies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get inactive topic policies on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get inactive topic policies on a topic.", + content = @Content(schema = @Schema(implementation = InactiveTopicPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getInactiveTopicPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.INACTIVE_TOPIC, PolicyOperation.READ) @@ -638,19 +686,20 @@ public void getInactiveTopicPolicies(@Suspended final AsyncResponse asyncRespons @POST @Path("/{tenant}/{namespace}/{topic}/inactiveTopicPolicies") - @ApiOperation(value = "Set inactive topic policies on a topic.") + @Operation(summary = "Set inactive topic policies on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void setInactiveTopicPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "inactive topic policies for the specified topic") + @RequestBody(description = "inactive topic policies for the specified topic") InactiveTopicPolicies inactiveTopicPolicies) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.INACTIVE_TOPIC, PolicyOperation.WRITE) @@ -665,17 +714,18 @@ public void setInactiveTopicPolicies(@Suspended final AsyncResponse asyncRespons @DELETE @Path("/{tenant}/{namespace}/{topic}/inactiveTopicPolicies") - @ApiOperation(value = "Delete inactive topic policies on a topic.") + @Operation(summary = "Delete inactive topic policies on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void deleteInactiveTopicPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.INACTIVE_TOPIC, PolicyOperation.WRITE) @@ -690,17 +740,21 @@ public void deleteInactiveTopicPolicies(@Suspended final AsyncResponse asyncResp @GET @Path("/{tenant}/{namespace}/{topic}/maxUnackedMessagesOnSubscription") - @ApiOperation(value = "Get max unacked messages per subscription config on a topic.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get max unacked messages per subscription config on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get max unacked messages per subscription config on a topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getMaxUnackedMessagesOnSubscription(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_UNACKED, PolicyOperation.READ) @@ -715,20 +769,21 @@ public void getMaxUnackedMessagesOnSubscription(@Suspended final AsyncResponse a @POST @Path("/{tenant}/{namespace}/{topic}/maxUnackedMessagesOnSubscription") - @ApiOperation(value = "Set max unacked messages per subscription config on a topic.") + @Operation(summary = "Set max unacked messages per subscription config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void setMaxUnackedMessagesOnSubscription( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Max unacked messages on subscription policies for the specified topic") + @RequestBody(description = "Max unacked messages on subscription policies for the specified topic") Integer maxUnackedNum) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperation(topicName, PolicyName.MAX_UNACKED, PolicyOperation.WRITE); @@ -743,17 +798,18 @@ public void setMaxUnackedMessagesOnSubscription( @DELETE @Path("/{tenant}/{namespace}/{topic}/maxUnackedMessagesOnSubscription") - @ApiOperation(value = "Delete max unacked messages per subscription config on a topic.") + @Operation(summary = "Delete max unacked messages per subscription config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void deleteMaxUnackedMessagesOnSubscription(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperation(topicName, PolicyName.MAX_UNACKED, PolicyOperation.WRITE); @@ -768,17 +824,21 @@ public void deleteMaxUnackedMessagesOnSubscription(@Suspended final AsyncRespons @GET @Path("/{tenant}/{namespace}/{topic}/delayedDelivery") - @ApiOperation(value = "Get delayed delivery messages config on a topic.", response = DelayedDeliveryPolicies.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get delayed delivery messages config on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get delayed delivery messages config on a topic.", + content = @Content(schema = @Schema(implementation = DelayedDeliveryPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.DELAYED_DELIVERY, PolicyOperation.READ) @@ -793,20 +853,21 @@ public void getDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncRespo @POST @Path("/{tenant}/{namespace}/{topic}/delayedDelivery") - @ApiOperation(value = "Set delayed delivery messages config on a topic.") + @Operation(summary = "Set delayed delivery messages config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void setDelayedDeliveryPolicies( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Delayed delivery policies for the specified topic") + @RequestBody(description = "Delayed delivery policies for the specified topic") DelayedDeliveryPolicies deliveryPolicies) { validateTopicName(tenant, namespace, encodedTopic); validatePoliciesReadOnlyAccess(); @@ -822,17 +883,18 @@ public void setDelayedDeliveryPolicies( @DELETE @Path("/{tenant}/{namespace}/{topic}/delayedDelivery") - @ApiOperation(value = "Set delayed delivery messages config on a topic.") + @Operation(summary = "Set delayed delivery messages config on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic doesn't exist"), }) public void deleteDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validatePoliciesReadOnlyAccess(); @@ -853,34 +915,35 @@ public void deleteDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncRe */ @POST @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Increment partitions of an existing partitioned topic.", - notes = "It increments partitions of existing partitioned-topic") + @Operation(summary = "Increment partitions of an existing partitioned topic.", + description = "It increments partitions of existing partitioned-topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Update topic partition successful."), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Unauthenticated"), - @ApiResponse(code = 403, message = "Forbidden/Unauthorized"), - @ApiResponse(code = 404, message = "Topic does not exist"), - @ApiResponse(code = 422, message = "The number of partitions should be more than 0 and" + @ApiResponse(responseCode = "204", description = "Update topic partition successful."), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", description = "Unauthenticated"), + @ApiResponse(responseCode = "403", description = "Forbidden/Unauthorized"), + @ApiResponse(responseCode = "404", description = "Topic does not exist"), + @ApiResponse(responseCode = "422", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic" + " and number of new partitions must be greater than existing number of partitions"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void updatePartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("updateLocalTopicOnly") @DefaultValue("false") boolean updateLocalTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("force") @DefaultValue("false") boolean force, - @ApiParam(value = "The number of partitions for the topic", - required = true, type = "int", defaultValue = "0") + @RequestBody(description = "The number of partitions for the topic", + required = true, content = @Content(schema = @Schema(type = "integer", defaultValue = "0"))) int numPartitions) { validateTopicName(tenant, namespace, encodedTopic); if (topicName.isPartitioned()) { @@ -911,25 +974,26 @@ public void updatePartitionedTopic( @POST @Path("/{tenant}/{namespace}/{topic}/createMissedPartitions") - @ApiOperation(value = "Create missed partitions of an existing partitioned topic.") + @Operation(summary = "Create missed partitions of an existing partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant does not exist"), - @ApiResponse(code = 409, message = "Partitioned topic does not exist"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant does not exist"), + @ApiResponse(responseCode = "409", description = "Partitioned topic does not exist"), + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void createMissedPartitions( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic) { try { @@ -942,27 +1006,33 @@ public void createMissedPartitions( @GET @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Get partitioned topic metadata.", response = PartitionedTopicMetadata.class) + @Operation(summary = "Get partitioned topic metadata.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Partitioned topic does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse( + responseCode = "200", + description = "Get partitioned topic metadata.", + content = @Content(schema = @Schema(implementation = PartitionedTopicMetadata.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Partitioned topic does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void getPartitionedMetadata( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Is check configuration required to automatically create topic") + @Parameter(description = "Is check configuration required to automatically create topic") @QueryParam("checkAllowAutoCreation") @DefaultValue("false") boolean checkAllowAutoCreation) { validateTopicName(tenant, namespace, encodedTopic); internalGetPartitionedMetadataAsync(authoritative, checkAllowAutoCreation) @@ -989,25 +1059,32 @@ public void getPartitionedMetadata( @GET @Path("/{tenant}/{namespace}/{topic}/properties") - @ApiOperation(value = "Get topic properties.", response = String.class, responseContainer = "Map") + @Operation(summary = "Get topic properties.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse( + responseCode = "200", + description = "Get topic properties.", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesSchema = @Schema(type = "string"))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void getProperties( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validatePersistentTopicName(tenant, namespace, encodedTopic); internalGetPropertiesAsync(authoritative) @@ -1026,29 +1103,30 @@ public void getProperties( @PUT @Path("/{tenant}/{namespace}/{topic}/properties") - @ApiOperation(value = "Update the properties on the given topic.") + @Operation(summary = "Update the properties on the given topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Method Not Allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void updateProperties( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Key value pair properties for the topic metadata") Map properties){ + @RequestBody(description = "Key value pair properties for the topic metadata") Map properties){ validatePersistentTopicName(tenant, namespace, encodedTopic); internalUpdatePropertiesAsync(authoritative, properties) .thenAccept(__ -> asyncResponse.resume(Response.noContent().build())) @@ -1066,24 +1144,26 @@ public void updateProperties( @DELETE @Path("/{tenant}/{namespace}/{topic}/properties") - @ApiOperation(value = "Remove the key in properties on the given topic.") + @Operation(summary = "Remove the key in properties on the given topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Partitioned topic does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Partitioned topic does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void removeProperties( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("key") String key, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { @@ -1105,30 +1185,32 @@ public void removeProperties( @DELETE @Path("/{tenant}/{namespace}/{topic}/partitions") - @ApiOperation(value = "Delete a partitioned topic.", - notes = "It will also delete all the partitions of the topic if it exists.") + @Operation(summary = "Delete a partitioned topic.", + description = "It will also delete all the partitions of the topic if it exists.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Partitioned topic does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Partitioned topic does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void deletePartitionedTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Stop all producer/consumer/replicator and delete topic forcefully", - defaultValue = "false", type = "boolean") + @Parameter(description = "Stop all producer/consumer/replicator and delete topic forcefully", + schema = @Schema(defaultValue = "false")) @QueryParam("force") @DefaultValue("false") boolean force, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1147,25 +1229,26 @@ public void deletePartitionedTopic( @PUT @Path("/{tenant}/{namespace}/{topic}/unload") - @ApiOperation(value = "Unload a topic") + @Operation(summary = "Unload a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Topic name is not valid or can't find owner for topic"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid or can't find owner for topic"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void unloadTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1179,30 +1262,32 @@ public void unloadTopic( @DELETE @Path("/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Delete a topic.", - notes = "The topic cannot be deleted if delete is not forcefully and there's any active " + @Operation(summary = "Delete a topic.", + description = "The topic cannot be deleted if delete is not forcefully and there's any active " + "subscription or producer connected to the it. " + "Force delete ignores connected clients and deletes topic by explicitly closing them.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic has active producers/subscriptions"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic has active producers/subscriptions"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void deleteTopic( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Stop all producer/consumer/replicator and delete topic forcefully", - defaultValue = "false", type = "boolean") + @Parameter(description = "Stop all producer/consumer/replicator and delete topic forcefully", + schema = @Schema(defaultValue = "false")) @QueryParam("force") @DefaultValue("false") boolean force, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -1243,23 +1328,25 @@ public void deleteTopic( @DELETE @Path("/{tenant}/{namespace}/{topic}/policies") - @ApiOperation(value = "Delete policies for a topic.") + @Operation(summary = "Delete policies for a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void deleteTopicPolicies( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_PRODUCERS, PolicyOperation.WRITE) @@ -1282,29 +1369,32 @@ public void deleteTopicPolicies( @GET @Path("/{tenant}/{namespace}/{topic}/subscriptions") - @ApiOperation( - value = "Get the list of persistent subscriptions for a given topic.", - response = String.class, - responseContainer = "List" - ) + @Operation( + summary = "Get the list of persistent subscriptions for a given topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration"), + @ApiResponse( + responseCode = "200", + description = "Get the list of persistent subscriptions for a given topic.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration"), }) public void getSubscriptions( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1318,35 +1408,42 @@ public void getSubscriptions( @GET @Path("{tenant}/{namespace}/{topic}/stats") - @ApiOperation(value = "Get the stats for the topic.", response = PersistentTopicStats.class) + @Operation(summary = "Get the stats for the topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") }) + @ApiResponse( + responseCode = "200", + description = "Get the stats for the topic.", + content = @Content(schema = @Schema(implementation = PersistentTopicStats.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getStats( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "If return precise backlog or imprecise backlog") + @Parameter(description = "If return precise backlog or imprecise backlog") @QueryParam("getPreciseBacklog") @DefaultValue("false") boolean getPreciseBacklog, - @ApiParam(value = "If return backlog size for each subscription, require locking on ledger so be careful " + @Parameter(description = "If return backlog size for each subscription, " + + "require locking on ledger so be careful " + "not to use when there's heavy traffic.") @QueryParam("subscriptionBacklogSize") @DefaultValue("true") boolean subscriptionBacklogSize, - @ApiParam(value = "If return time of the earliest message in backlog") + @Parameter(description = "If return time of the earliest message in backlog") @QueryParam("getEarliestTimeInBacklog") @DefaultValue("false") boolean getEarliestTimeInBacklog, - @ApiParam(value = "If exclude the publishers") + @Parameter(description = "If exclude the publishers") @QueryParam("excludePublishers") @DefaultValue("false") boolean excludePublishers, - @ApiParam(value = "If exclude the consumers") + @Parameter(description = "If exclude the consumers") @QueryParam("excludeConsumers") @DefaultValue("false") boolean excludeConsumers) { validateTopicName(tenant, namespace, encodedTopic); GetStatsOptions getStatsOptions = @@ -1369,24 +1466,30 @@ public void getStats( @GET @Path("{tenant}/{namespace}/{topic}/internalStats") - @ApiOperation(value = "Get the internal stats for the topic.", response = PersistentTopicInternalStats.class) + @Operation(summary = "Get the internal stats for the topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") }) + @ApiResponse( + responseCode = "200", + description = "Get the internal stats for the topic.", + content = @Content(schema = @Schema(implementation = PersistentTopicInternalStats.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getInternalStats( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("metadata") @DefaultValue("false") boolean metadata) { validateTopicName(tenant, namespace, encodedTopic); @@ -1406,22 +1509,27 @@ public void getInternalStats( @GET @Path("{tenant}/{namespace}/{topic}/internal-info") - @ApiOperation(value = "Get the stored topic metadata.", response = PartitionedManagedLedgerInfo.class) + @Operation(summary = "Get the stored topic metadata.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse( + responseCode = "200", + description = "Get the stored topic metadata.", + content = @Content(schema = @Schema(implementation = PartitionedManagedLedgerInfo.class))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void getManagedLedgerInfo( - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @Suspended AsyncResponse asyncResponse) { validateTopicName(tenant, namespace, encodedTopic); @@ -1430,38 +1538,45 @@ public void getManagedLedgerInfo( @GET @Path("{tenant}/{namespace}/{topic}/partitioned-stats") - @ApiOperation(value = "Get the stats for the partitioned topic.", response = PartitionedTopicStatsImpl.class) + @Operation(summary = "Get the stats for the partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Partitioned topic name is invalid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse( + responseCode = "200", + description = "Get the stats for the partitioned topic.", + content = @Content(schema = @Schema(implementation = PartitionedTopicStatsImpl.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Partitioned topic name is invalid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getPartitionedStats( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Get per partition stats") + @Parameter(description = "Get per partition stats") @QueryParam("perPartition") @DefaultValue("true") boolean perPartition, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "If return precise backlog or imprecise backlog") + @Parameter(description = "If return precise backlog or imprecise backlog") @QueryParam("getPreciseBacklog") @DefaultValue("false") boolean getPreciseBacklog, - @ApiParam(value = "If return backlog size for each subscription, require locking on ledger so be careful " + @Parameter(description = "If return backlog size for each subscription, " + + "require locking on ledger so be careful " + "not to use when there's heavy traffic.") @QueryParam("subscriptionBacklogSize") @DefaultValue("true") boolean subscriptionBacklogSize, - @ApiParam(value = "If return the earliest time in backlog") + @Parameter(description = "If return the earliest time in backlog") @QueryParam("getEarliestTimeInBacklog") @DefaultValue("false") boolean getEarliestTimeInBacklog, - @ApiParam(value = "If exclude the publishers") + @Parameter(description = "If exclude the publishers") @QueryParam("excludePublishers") @DefaultValue("false") boolean excludePublishers, - @ApiParam(value = "If exclude the consumers") + @Parameter(description = "If exclude the consumers") @QueryParam("excludeConsumers") @DefaultValue("false") boolean excludeConsumers) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1481,27 +1596,31 @@ public void getPartitionedStats( @GET @Path("{tenant}/{namespace}/{topic}/partitioned-internalStats") - @ApiOperation( - value = "Get the stats-internal for the partitioned topic.", - response = PartitionedTopicInternalStats.class - ) + @Operation( + summary = "Get the stats-internal for the partitioned topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") }) + @ApiResponse( + responseCode = "200", + description = "Get the stats-internal for the partitioned topic.", + content = @Content(schema = @Schema(implementation = PartitionedTopicInternalStats.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getPartitionedStatsInternal( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1515,33 +1634,35 @@ public void getPartitionedStatsInternal( @DELETE @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}") - @ApiOperation(value = "Delete a subscription.", - notes = "The subscription cannot be deleted if delete is not forcefully and" + @Operation(summary = "Delete a subscription.", + description = "The subscription cannot be deleted if delete is not forcefully and" + " there are any active consumers attached to it. " + "Force delete ignores connected consumers and deletes subscription by explicitly closing them.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 412, message = "Subscription has active consumers"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "412", description = "Subscription has active consumers"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void deleteSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription to be deleted") + @Parameter(description = "Subscription to be deleted") @PathParam("subName") String encodedSubName, - @ApiParam(value = "Disconnect and close all consumers and delete subscription forcefully", - defaultValue = "false", type = "boolean") + @Parameter(description = "Disconnect and close all consumers and delete subscription forcefully", + schema = @Schema(defaultValue = "false")) @QueryParam("force") @DefaultValue("false") boolean force, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); String subName = decode(encodedSubName); @@ -1573,30 +1694,32 @@ public void deleteSubscription( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/skip_all") - @ApiOperation(value = "Skip all messages on a topic subscription.", - notes = "Completely clears the backlog on the subscription.") + @Operation(summary = "Skip all messages on a topic subscription.", + description = "Completely clears the backlog on the subscription.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Operation not allowed on non-persistent topic"), - @ApiResponse(code = 412, message = "Can't find owner for topic"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Operation not allowed on non-persistent topic"), + @ApiResponse(responseCode = "412", description = "Can't find owner for topic"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void skipAllMessages( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Name of subscription") + @Parameter(description = "Name of subscription") @PathParam("subName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1610,30 +1733,32 @@ public void skipAllMessages( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/skip/{numMessages}") - @ApiOperation(value = "Skipping messages on a topic subscription.") + @Operation(summary = "Skipping messages on a topic subscription.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Skipping messages on a partitioned topic is not allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Skipping messages on a partitioned topic is not allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void skipMessages( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Name of subscription") + @Parameter(description = "Name of subscription") @PathParam("subName") String encodedSubName, - @ApiParam(value = "The number of messages to skip", defaultValue = "0") + @Parameter(description = "The number of messages to skip", schema = @Schema(defaultValue = "0")) @PathParam("numMessages") int numMessages, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1647,30 +1772,34 @@ public void skipMessages( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/expireMessages/{expireTimeInSeconds}") - @ApiOperation(value = "Expiry messages on a topic subscription.") + @Operation(summary = "Expiry messages on a topic subscription.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Expiry messages on a non-persistent topic is not allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", + description = "Expiry messages on a non-persistent topic is not allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void expireTopicMessages( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription to be Expiry messages on") + @Parameter(description = "Subscription to be Expiry messages on") @PathParam("subName") String encodedSubName, - @ApiParam(value = "Expires beyond the specified number of seconds", defaultValue = "0") + @Parameter(description = "Expires beyond the specified number of seconds", + schema = @Schema(defaultValue = "0")) @PathParam("expireTimeInSeconds") int expireTimeInSeconds, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1685,30 +1814,33 @@ public void expireTopicMessages( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/expireMessages") - @ApiOperation(value = "Expiry messages on a topic subscription.") + @Operation(summary = "Expiry messages on a topic subscription.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Expiry messages on a non-persistent topic is not allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", + description = "Expiry messages on a non-persistent topic is not allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void expireTopicMessages( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription to be Expiry messages on") + @Parameter(description = "Subscription to be Expiry messages on") @PathParam("subName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(name = "messageId", value = "messageId to reset back to (ledgerId:entryId)") + @RequestBody(description = "messageId to reset back to (ledgerId:entryId)") ResetCursorData resetCursorData) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1725,29 +1857,33 @@ public void expireTopicMessages( @POST @Path("/{tenant}/{namespace}/{topic}/all_subscription/expireMessages/{expireTimeInSeconds}") - @ApiOperation(value = "Expiry messages on all subscriptions of topic.") + @Operation(summary = "Expiry messages on all subscriptions of topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Expiry messages on a non-persistent topic is not allowed"), - @ApiResponse(code = 412, message = "Can't find owner for topic"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", + description = "Expiry messages on a non-persistent topic is not allowed"), + @ApiResponse(responseCode = "412", description = "Can't find owner for topic"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void expireMessagesForAllSubscriptions( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Expires beyond the specified number of seconds", defaultValue = "0") + @Parameter(description = "Expires beyond the specified number of seconds", + schema = @Schema(defaultValue = "0")) @PathParam("expireTimeInSeconds") int expireTimeInSeconds, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1761,38 +1897,41 @@ public void expireMessagesForAllSubscriptions( @PUT @Path("/{tenant}/{namespace}/{topic}/subscription/{subscriptionName}") - @ApiOperation(value = "Create a subscription on the topic.", - notes = "Creates a subscription on the topic at the specified message id") + @Operation(summary = "Create a subscription on the topic.", + description = "Creates a subscription on the topic at the specified message id") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 400, message = "Create subscription on non persistent topic is not supported"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "400", + description = "Create subscription on non persistent topic is not supported"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Not supported for partitioned topics"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Not supported for partitioned topics"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void createSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String topic, - @ApiParam(value = "Name of subscription to be created", required = true) + @Parameter(description = "Name of subscription to be created", required = true) @PathParam("subscriptionName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(name = "messageId", value = "messageId where to create the subscription. " + @RequestBody(description = "messageId where to create the subscription. " + "It can be 'latest', 'earliest' or (ledgerId:entryId)", - defaultValue = "latest", - allowableValues = "latest, earliest, ledgerId:entryId" - ) + content = @Content(schema = @Schema( + allowableValues = {"latest", "earliest", "ledgerId:entryId"}, + defaultValue = "latest"))) ResetCursorData resetCursorData, - @ApiParam(value = "Is replicated required to perform this operation") + @Parameter(description = "Is replicated required to perform this operation") @QueryParam("replicated") boolean replicated ) { try { @@ -1828,34 +1967,36 @@ public void createSubscription( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor/{timestamp}") - @ApiOperation(value = "Reset subscription to message position closest to absolute timestamp (in ms).", - notes = "It fence cursor and disconnects all active consumers before resetting cursor.") + @Operation(summary = "Reset subscription to message position closest to absolute timestamp (in ms).", + description = "It fence cursor and disconnects all active consumers before resetting cursor.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Method Not Allowed"), - @ApiResponse(code = 412, message = "Failed to reset cursor on subscription or " + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed"), + @ApiResponse(responseCode = "412", description = "Failed to reset cursor on subscription or " + "Unable to find position for timestamp specified"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void resetCursor( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription to reset position on", required = true) + @Parameter(description = "Subscription to reset position on", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "the timestamp to reset back") + @Parameter(description = "the timestamp to reset back") @PathParam("timestamp") long timestamp, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalResetCursorAsync(decode(encodedSubName), timestamp, authoritative) @@ -1884,30 +2025,32 @@ public void resetCursor( @PUT @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/properties") - @ApiOperation(value = "Replace all the properties on the given subscription") + @Operation(summary = "Replace all the properties on the given subscription") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Method Not Allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void updateSubscriptionProperties( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription to update", required = true) + @Parameter(description = "Subscription to update", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "The new properties") Map subscriptionProperties, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @RequestBody(description = "The new properties") Map subscriptionProperties, + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1922,29 +2065,35 @@ public void updateSubscriptionProperties( @GET @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/properties") - @ApiOperation(value = "Return all the properties on the given subscription", - response = String.class, responseContainer = "Map") + @Operation(summary = "Return all the properties on the given subscription") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse( + responseCode = "200", + description = "Return all the properties on the given subscription", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesSchema = @Schema(type = "string"))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Method Not Allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getSubscriptionProperties( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription", required = true) + @Parameter(description = "Subscription", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -1959,31 +2108,33 @@ public void getSubscriptionProperties( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/analyzeBacklog") - @ApiOperation(value = "Analyse a subscription, by scanning all the unprocessed messages") + @Operation(summary = "Analyse a subscription, by scanning all the unprocessed messages") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Method Not Allowed"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Method Not Allowed"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void analyzeSubscriptionBacklog( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription", required = true) + @Parameter(description = "Subscription", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(name = "position", value = "messageId to start the analysis") + @RequestBody(description = "messageId to start the analysis") ResetCursorData position, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { Optional positionImpl; @@ -2005,32 +2156,34 @@ public void analyzeSubscriptionBacklog( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor") - @ApiOperation(value = "Reset subscription to message position closest to given position.", - notes = "It fence cursor and disconnects all active consumers before resetting cursor.") + @Operation(summary = "Reset subscription to message position closest to given position.", + description = "It fence cursor and disconnects all active consumers before resetting cursor.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Not supported for partitioned topics"), - @ApiResponse(code = 412, message = "Unable to find position for position specified"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Not supported for partitioned topics"), + @ApiResponse(responseCode = "412", description = "Unable to find position for position specified"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void resetCursorOnPosition( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(name = "subName", value = "Subscription to reset position on", required = true) + @Parameter(name = "subName", description = "Subscription to reset position on", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(name = "messageId", value = "messageId to reset back to (ledgerId:entryId)") + @RequestBody(description = "messageId to reset back to (ledgerId:entryId)") ResetCursorData resetCursorData) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -2045,38 +2198,42 @@ public void resetCursorOnPosition( @GET @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/position/{messagePosition}") - @ApiOperation(value = "Peek nth message on a topic subscription.") + @Operation(summary = "Peek nth message on a topic subscription.") @ApiResponses(value = { @ApiResponse( - code = 200, - message = "Successfully retrieved the message. The response is a binary byte stream " + responseCode = "200", + description = "Successfully retrieved the message. The response is a binary byte stream " + "containing the message data. Clients need to parse this binary stream based" + " on the message metadata provided in the response headers.", - response = byte[].class + content = @Content(schema = @Schema(implementation = byte[].class)) ), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic, subscription or the message position does not" + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Namespace or topic, subscription or the message position does not" + " exist"), - @ApiResponse(code = 405, message = "Skipping messages on a non-persistent topic is not allowed"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "405", + description = "Skipping messages on a non-persistent topic is not allowed"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void peekNthMessage( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(name = "subName", value = "Subscribed message expired", required = true) + @Parameter(name = "subName", description = "Subscribed message expired", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "The number of messages (default 1)", defaultValue = "1") + @Parameter(description = "The number of messages (default 1)", schema = @Schema(defaultValue = "1")) @PathParam("messagePosition") int messagePosition, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalPeekNthMessageAsync(decode(encodedSubName), messagePosition, authoritative) @@ -2096,39 +2253,38 @@ public void peekNthMessage( @GET @Path("/{tenant}/{namespace}/{topic}/examinemessage") - @ApiOperation(value = + @Operation(summary = "Examine a specific message on a topic by position relative to the earliest or the latest message.") @ApiResponses(value = { @ApiResponse( - code = 200, - message = "Successfully retrieved the message. The response is a binary byte stream " + responseCode = "200", + description = "Successfully retrieved the message. The response is a binary byte stream " + "containing the message data. Clients need to parse this binary stream based" + " on the message metadata provided in the response headers.", - response = byte[].class + content = @Content(schema = @Schema(implementation = byte[].class)) ), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic, the message position does not exist"), - @ApiResponse(code = 405, message = "If given partitioned topic"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic, the message position does not exist"), + @ApiResponse(responseCode = "405", description = "If given partitioned topic"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void examineMessage( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(name = "initialPosition", value = "Relative start position to examine message." + @Parameter(name = "initialPosition", description = "Relative start position to examine message." + "It can be 'latest' or 'earliest'", - defaultValue = "latest", - allowableValues = "latest, earliest" - ) + schema = @Schema(allowableValues = {"latest", "earliest"}, defaultValue = "latest")) @QueryParam("initialPosition") String initialPosition, - @ApiParam(value = "The position of messages (default 1)", defaultValue = "1") + @Parameter(description = "The position of messages (default 1)", schema = @Schema(defaultValue = "1")) @QueryParam("messagePosition") long messagePosition, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalExamineMessageAsync(initialPosition, messagePosition, authoritative) @@ -2147,38 +2303,42 @@ public void examineMessage( @GET @Path("/{tenant}/{namespace}/{topic}/ledger/{ledgerId}/entry/{entryId}") - @ApiOperation(value = "Get message by its messageId.") + @Operation(summary = "Get message by its messageId.") @ApiResponses(value = { @ApiResponse( - code = 200, - message = "Successfully retrieved the message. The response is a binary byte stream " + responseCode = "200", + description = "Successfully retrieved the message. The response is a binary byte stream " + "containing the message data. Clients need to parse this binary stream based" + " on the message metadata provided in the response headers.", - response = byte[].class + content = @Content(schema = @Schema(implementation = byte[].class)) ), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic, subscription or the message position does not" + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Namespace or topic, subscription or the message position does not" + " exist"), - @ApiResponse(code = 405, message = "Skipping messages on a non-persistent topic is not allowed"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "405", + description = "Skipping messages on a non-persistent topic is not allowed"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void getMessageById( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "The ledger id", required = true) + @Parameter(description = "The ledger id", required = true) @PathParam("ledgerId") long ledgerId, - @ApiParam(value = "The entry id", required = true) + @Parameter(description = "The entry id", required = true) @PathParam("entryId") long entryId, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalGetMessageById(ledgerId, entryId, authoritative) @@ -2200,29 +2360,34 @@ public void getMessageById( @GET @Path("/{tenant}/{namespace}/{topic}/messageid/{timestamp}") - @ApiOperation(value = "Get message ID published at or just after this absolute timestamp (in ms).", - response = MessageIdAdv.class) + @Operation(summary = "Get message ID published at or just after this absolute timestamp (in ms).") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse( + responseCode = "200", + description = "Get message ID published at or just after this absolute timestamp (in ms).", + content = @Content(schema = @Schema(implementation = MessageIdAdv.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Topic is not non-partitioned and persistent"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Topic is not non-partitioned and persistent"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void getMessageIdByTimestamp( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Specify the timestamp", required = true) + @Parameter(description = "Specify the timestamp", required = true) @PathParam("timestamp") long timestamp, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalGetMessageIdByTimestampAsync(timestamp, authoritative) @@ -2248,20 +2413,24 @@ public void getMessageIdByTimestamp( @GET @Path("{tenant}/{namespace}/{topic}/backlog") - @ApiOperation(value = "Get estimated backlog for offline topic.", response = PersistentOfflineTopicStats.class) + @Operation(summary = "Get estimated backlog for offline topic.") @ApiResponses(value = { - @ApiResponse(code = 404, message = "Namespace does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse( + responseCode = "200", + description = "Get estimated backlog for offline topic.", + content = @Content(schema = @Schema(implementation = PersistentOfflineTopicStats.class))), + @ApiResponse(responseCode = "404", description = "Namespace does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void getBacklog( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicOperationAsync(topicName, TopicOperation.GET_BACKLOG_SIZE) @@ -2287,22 +2456,26 @@ public void getBacklog( @PUT @Path("/{tenant}/{namespace}/{topic}/backlogSize") - @ApiOperation(value = "Calculate backlog size by a message ID (in bytes).", response = Long.class) + @Operation(summary = "Calculate backlog size by a message ID (in bytes).") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration") }) + @ApiResponse( + responseCode = "200", + description = "Calculate backlog size by a message ID (in bytes).", + content = @Content(schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") }) public void getBacklogSizeByMessageId( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, MessageIdImpl messageId) { validateTopicName(tenant, namespace, encodedTopic); internalGetBacklogSizeByMessageId(asyncResponse, messageId, authoritative); @@ -2310,18 +2483,23 @@ public void getBacklogSizeByMessageId( @GET @Path("/{tenant}/{namespace}/{topic}/backlogQuotaMap") - @ApiOperation(value = "Get backlog quota map on a topic.", response = BacklogQuota.class, responseContainer = "Map") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Topic policy or namespace does not exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry")}) + @Operation(summary = "Get backlog quota map on a topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get backlog quota map on a topic.", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = BacklogQuota.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Topic policy or namespace does not exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry")}) public void getBacklogQuotaMap( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal) { validateTopicName(tenant, namespace, encodedTopic); @@ -2337,25 +2515,26 @@ public void getBacklogQuotaMap( @POST @Path("/{tenant}/{namespace}/{topic}/backlogQuota") - @ApiOperation(value = "Set a backlog quota for a topic.") + @Operation(summary = "Set a backlog quota for a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 412, message = "Specified backlog quota exceeds retention quota." + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "412", description = "Specified backlog quota exceeds retention quota." + " Increase retention quota and retry request")}) public void setBacklogQuota( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("backlogQuotaType") BacklogQuotaType backlogQuotaType, - @ApiParam(value = "backlog quota policies for the specified topic") BacklogQuotaImpl backlogQuota) { + @RequestBody(description = "backlog quota policies for the specified topic") + BacklogQuotaImpl backlogQuota) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.BACKLOG, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -2369,19 +2548,19 @@ public void setBacklogQuota( @DELETE @Path("/{tenant}/{namespace}/{topic}/backlogQuota") - @ApiOperation(value = "Remove a backlog quota policy from a topic.") + @Operation(summary = "Remove a backlog quota policy from a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeBacklogQuota(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("backlogQuotaType") BacklogQuotaType backlogQuotaType, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal) { validateTopicName(tenant, namespace, encodedTopic); @@ -2397,14 +2576,15 @@ public void removeBacklogQuota(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/replication") - @ApiOperation( - value = "Get the replication clusters for a topic", - response = String.class, - responseContainer = "List" - ) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @Operation( + summary = "Get the replication clusters for a topic") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get the replication clusters for a topic", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry")}) public void getReplicationClusters(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2412,7 +2592,7 @@ public void getReplicationClusters(@Suspended final AsyncResponse asyncResponse, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. " + @Parameter(description = "Whether leader broker redirected this call to this broker. " + "For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -2462,26 +2642,26 @@ private CompletableFuture> getAppliedReplicatedClusters() { @POST @Path("/{tenant}/{namespace}/{topic}/replication") - @ApiOperation(value = "Set the replication clusters for a topic. " + @Operation(summary = "Set the replication clusters for a topic. " + "When removing a cluster:" + " with shared configuration store, topic data will be deleted from the removed cluster; " + "with separate configuration store, only replication stops but topic data is preserved.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 412, message = "Topic is not global or invalid cluster ids")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "412", description = "Topic is not global or invalid cluster ids")}) public void setReplicationClusters( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "List of replication clusters", required = true) List clusterIds) { + @RequestBody(description = "List of replication clusters", required = true) List clusterIds) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.REPLICATION, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -2495,19 +2675,19 @@ public void setReplicationClusters( @DELETE @Path("/{tenant}/{namespace}/{topic}/replication") - @ApiOperation(value = "Remove the replication clusters from a topic.") + @Operation(summary = "Remove the replication clusters from a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeReplicationClusters(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.REPLICATION, PolicyOperation.WRITE) @@ -2522,10 +2702,14 @@ public void removeReplicationClusters(@Suspended final AsyncResponse asyncRespon @GET @Path("/{tenant}/{namespace}/{topic}/subscriptionExpirationTime") - @ApiOperation(value = "Get subscription expiration time in minutes for a topic", response = Integer.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @Operation(summary = "Get subscription expiration time in minutes for a topic") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get subscription expiration time in minutes for a topic", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry")}) public void getSubscriptionExpirationTime(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -2533,7 +2717,7 @@ public void getSubscriptionExpirationTime(@Suspended final AsyncResponse asyncRe @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SUBSCRIPTION_EXPIRATION_TIME, PolicyOperation.READ) @@ -2548,22 +2732,22 @@ public void getSubscriptionExpirationTime(@Suspended final AsyncResponse asyncRe @POST @Path("/{tenant}/{namespace}/{topic}/subscriptionExpirationTime") - @ApiOperation(value = "Set subscription expiration time in minutes for a topic") + @Operation(summary = "Set subscription expiration time in minutes for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 412, message = "Invalid subscription expiration time value")}) + @ApiResponse(responseCode = "412", description = "Invalid subscription expiration time value")}) public void setSubscriptionExpirationTime(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription expiration time in minutes", required = true) + @Parameter(description = "Subscription expiration time in minutes", required = true) @QueryParam("subscriptionExpirationTime") Integer subscriptionExpirationTime, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SUBSCRIPTION_EXPIRATION_TIME, PolicyOperation.WRITE) @@ -2578,20 +2762,20 @@ public void setSubscriptionExpirationTime(@Suspended final AsyncResponse asyncRe @DELETE @Path("/{tenant}/{namespace}/{topic}/subscriptionExpirationTime") - @ApiOperation(value = "Remove subscription expiration time for a topic") + @Operation(summary = "Remove subscription expiration time for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 412, message = "Invalid subscription expiration time value")}) + @ApiResponse(responseCode = "412", description = "Invalid subscription expiration time value")}) public void removeSubscriptionExpirationTime(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SUBSCRIPTION_EXPIRATION_TIME, PolicyOperation.WRITE) @@ -2606,10 +2790,14 @@ public void removeSubscriptionExpirationTime(@Suspended final AsyncResponse asyn @GET @Path("/{tenant}/{namespace}/{topic}/messageTTL") - @ApiOperation(value = "Get message TTL in seconds for a topic", response = Integer.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @Operation(summary = "Get message TTL in seconds for a topic") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get message TTL in seconds for a topic", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry")}) @SuppressWarnings("deprecation") public void getMessageTTL(@Suspended final AsyncResponse asyncResponse, @@ -2618,7 +2806,7 @@ public void getMessageTTL(@Suspended final AsyncResponse asyncResponse, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.TTL, PolicyOperation.READ) @@ -2642,23 +2830,23 @@ public void getMessageTTL(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/messageTTL") - @ApiOperation(value = "Set message TTL in seconds for a topic") + @Operation(summary = "Set message TTL in seconds for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Not authenticate to perform the request or policy is read only"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 412, message = "Invalid message TTL value")}) + @ApiResponse(responseCode = "412", description = "Invalid message TTL value")}) public void setMessageTTL(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "TTL in seconds for the specified topic", required = true) + @Parameter(description = "TTL in seconds for the specified topic", required = true) @QueryParam("messageTTL") Integer messageTTL, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.TTL, PolicyOperation.WRITE) @@ -2673,20 +2861,20 @@ public void setMessageTTL(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/messageTTL") - @ApiOperation(value = "Remove message TTL in seconds for a topic") + @Operation(summary = "Remove message TTL in seconds for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, - message = "Not authenticate to perform the request or policy is read only"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 412, message = "Invalid message TTL value")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", + description = "Not authenticate to perform the request or policy is read only"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, enable the topic level policy and retry"), + @ApiResponse(responseCode = "412", description = "Invalid message TTL value")}) public void removeMessageTTL(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -2702,19 +2890,23 @@ public void removeMessageTTL(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/deduplicationEnabled") - @ApiOperation(value = "Get deduplication configuration of a topic.", response = Boolean.class) + @Operation(summary = "Get deduplication configuration of a topic.") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry")}) + @ApiResponse( + responseCode = "200", + description = "Get deduplication configuration of a topic.", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry")}) public void getDeduplication(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.DEDUPLICATION, PolicyOperation.READ) @@ -2729,22 +2921,22 @@ public void getDeduplication(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/deduplicationEnabled") - @ApiOperation(value = "Set deduplication enabled on a topic.") + @Operation(summary = "Set deduplication enabled on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry")}) public void setDeduplication( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "DeduplicationEnabled policies for the specified topic") + @RequestBody(description = "DeduplicationEnabled policies for the specified topic") Boolean enabled) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.DEDUPLICATION, PolicyOperation.WRITE) @@ -2759,19 +2951,19 @@ public void setDeduplication( @DELETE @Path("/{tenant}/{namespace}/{topic}/deduplicationEnabled") - @ApiOperation(value = "Remove deduplication configuration for specified topic.") + @Operation(summary = "Remove deduplication configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeDeduplication(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -2787,19 +2979,23 @@ public void removeDeduplication(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/retention") - @ApiOperation(value = "Get retention configuration for specified topic.", response = RetentionPolicies.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get retention configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get retention configuration for specified topic.", + content = @Content(schema = @Schema(implementation = RetentionPolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getRetention(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RETENTION, PolicyOperation.READ) @@ -2814,23 +3010,23 @@ public void getRetention(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/retention") - @ApiOperation(value = "Set retention configuration for specified topic.") + @Operation(summary = "Set retention configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Retention Quota must exceed backlog quota")}) + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Retention Quota must exceed backlog quota")}) public void setRetention(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Retention policies for the specified topic") RetentionPolicies retention) { + @RequestBody(description = "Retention policies for the specified topic") RetentionPolicies retention) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RETENTION, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -2854,21 +3050,21 @@ public void setRetention(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/retention") - @ApiOperation(value = "Remove retention configuration for specified topic.") + @Operation(summary = "Remove retention configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Retention Quota must exceed backlog quota")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Retention Quota must exceed backlog quota")}) public void removeRetention(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RETENTION, PolicyOperation.WRITE) @@ -2889,19 +3085,19 @@ public void removeRetention(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/dispatcherPauseOnAckStatePersistent") - @ApiOperation(value = "Set dispatcher pause on ack state persistent configuration for specified topic.") + @Operation(summary = "Set dispatcher pause on ack state persistent configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal) { validateTopicName(tenant, namespace, encodedTopic); @@ -2924,20 +3120,20 @@ public void setDispatcherPauseOnAckStatePersistent(@Suspended final AsyncRespons @DELETE @Path("/{tenant}/{namespace}/{topic}/dispatcherPauseOnAckStatePersistent") - @ApiOperation(value = "Remove dispatcher pause on ack state persistent configuration for specified topic.") + @Operation(summary = "Remove dispatcher pause on ack state persistent configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, @@ -2959,17 +3155,22 @@ public void removeDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResp @GET @Path("/{tenant}/{namespace}/{topic}/dispatcherPauseOnAckStatePersistent") - @ApiOperation(value = "Get dispatcher pause on ack state persistent config on a topic.", response = Integer.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error"), }) + @Operation(summary = "Get dispatcher pause on ack state persistent config on a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get dispatcher pause on ack state persistent config on a topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), }) public void getDispatcherPauseOnAckStatePersistent(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. " + + "For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, @@ -2984,22 +3185,24 @@ public void getDispatcherPauseOnAckStatePersistent(@Suspended final AsyncRespons @GET @Path("/{tenant}/{namespace}/{topic}/persistence") - @ApiOperation( - value = "Get configuration of persistence policies for specified topic.", - response = PersistencePolicies.class - ) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation( + summary = "Get configuration of persistence policies for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get configuration of persistence policies for specified topic.", + content = @Content(schema = @Schema(implementation = PersistencePolicies.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPersistence(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.PERSISTENCE, PolicyOperation.READ) @@ -3014,23 +3217,23 @@ public void getPersistence(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/persistence") - @ApiOperation(value = "Set configuration of persistence policies for specified topic.") + @Operation(summary = "Set configuration of persistence policies for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 400, message = "Invalid persistence policies")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "400", description = "Invalid persistence policies")}) public void setPersistence(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Bookkeeper persistence policies for specified topic") + @RequestBody(description = "Bookkeeper persistence policies for specified topic") PersistencePolicies persistencePolicies) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.PERSISTENCE, PolicyOperation.WRITE) @@ -3055,20 +3258,20 @@ public void setPersistence(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/persistence") - @ApiOperation(value = "Remove configuration of persistence policies for specified topic.") + @Operation(summary = "Remove configuration of persistence policies for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removePersistence(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.PERSISTENCE, PolicyOperation.WRITE) @@ -3089,18 +3292,22 @@ public void removePersistence(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/maxSubscriptionsPerTopic") - @ApiOperation(value = "Get maxSubscriptionsPerTopic config for specified topic.", response = Integer.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get maxSubscriptionsPerTopic config for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get maxSubscriptionsPerTopic config for specified topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_SUBSCRIPTIONS, PolicyOperation.READ) @@ -3116,23 +3323,23 @@ public void getMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/{topic}/maxSubscriptionsPerTopic") - @ApiOperation(value = "Set maxSubscriptionsPerTopic config for specified topic.") + @Operation(summary = "Set maxSubscriptionsPerTopic config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Invalid value of maxSubscriptionsPerTopic")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Invalid value of maxSubscriptionsPerTopic")}) public void setMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "The max subscriptions of the topic") int maxSubscriptionsPerTopic) { + @RequestBody(description = "The max subscriptions of the topic") int maxSubscriptionsPerTopic) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_SUBSCRIPTIONS, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -3154,20 +3361,20 @@ public void setMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResp @DELETE @Path("/{tenant}/{namespace}/{topic}/maxSubscriptionsPerTopic") - @ApiOperation(value = "Remove maxSubscriptionsPerTopic config for specified topic.") + @Operation(summary = "Remove maxSubscriptionsPerTopic config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_SUBSCRIPTIONS, PolicyOperation.WRITE) @@ -3188,19 +3395,23 @@ public void removeMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncR @GET @Path("/{tenant}/{namespace}/{topic}/replicatorDispatchRate") - @ApiOperation(value = "Get replicatorDispatchRate config for specified topic.", response = DispatchRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get replicatorDispatchRate config for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get replicatorDispatchRate config for specified topic.", + content = @Content(schema = @Schema(implementation = DispatchRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getReplicatorDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.REPLICATION_RATE, PolicyOperation.READ) @@ -3215,23 +3426,23 @@ public void getReplicatorDispatchRate(@Suspended final AsyncResponse asyncRespon @POST @Path("/{tenant}/{namespace}/{topic}/replicatorDispatchRate") - @ApiOperation(value = "Set replicatorDispatchRate config for specified topic.") + @Operation(summary = "Set replicatorDispatchRate config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Invalid value of replicatorDispatchRate")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Invalid value of replicatorDispatchRate")}) public void setReplicatorDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Replicator dispatch rate of the topic") DispatchRateImpl dispatchRate) { + @RequestBody(description = "Replicator dispatch rate of the topic") DispatchRateImpl dispatchRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.REPLICATION_RATE, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -3253,20 +3464,20 @@ public void setReplicatorDispatchRate(@Suspended final AsyncResponse asyncRespon @DELETE @Path("/{tenant}/{namespace}/{topic}/replicatorDispatchRate") - @ApiOperation(value = "Remove replicatorDispatchRate config for specified topic.") + @Operation(summary = "Remove replicatorDispatchRate config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeReplicatorDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.REPLICATION_RATE, PolicyOperation.WRITE) @@ -3287,19 +3498,23 @@ public void removeReplicatorDispatchRate(@Suspended final AsyncResponse asyncRes @GET @Path("/{tenant}/{namespace}/{topic}/maxProducers") - @ApiOperation(value = "Get maxProducers config for specified topic.", response = Integer.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get maxProducers config for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get maxProducers config for specified topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getMaxProducers(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_PRODUCERS, PolicyOperation.READ) @@ -3314,23 +3529,23 @@ public void getMaxProducers(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/maxProducers") - @ApiOperation(value = "Set maxProducers config for specified topic.") + @Operation(summary = "Set maxProducers config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Invalid value of maxProducers")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Invalid value of maxProducers")}) public void setMaxProducers(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "The max producers of the topic") int maxProducers) { + @RequestBody(description = "The max producers of the topic") int maxProducers) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_PRODUCERS, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -3351,20 +3566,20 @@ public void setMaxProducers(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/maxProducers") - @ApiOperation(value = "Remove maxProducers config for specified topic.") + @Operation(summary = "Remove maxProducers config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeMaxProducers(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_PRODUCERS, PolicyOperation.WRITE) @@ -3385,19 +3600,23 @@ public void removeMaxProducers(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/maxConsumers") - @ApiOperation(value = "Get maxConsumers config for specified topic.", response = Integer.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get maxConsumers config for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get maxConsumers config for specified topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getMaxConsumers(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_CONSUMERS, PolicyOperation.READ) @@ -3412,23 +3631,23 @@ public void getMaxConsumers(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/maxConsumers") - @ApiOperation(value = "Set maxConsumers config for specified topic.") + @Operation(summary = "Set maxConsumers config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Invalid value of maxConsumers")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Invalid value of maxConsumers")}) public void setMaxConsumers(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "The max consumers of the topic") int maxConsumers) { + @RequestBody(description = "The max consumers of the topic") int maxConsumers) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_CONSUMERS, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -3449,20 +3668,20 @@ public void setMaxConsumers(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/maxConsumers") - @ApiOperation(value = "Remove maxConsumers config for specified topic.") + @Operation(summary = "Remove maxConsumers config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeMaxConsumers(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_CONSUMERS, PolicyOperation.WRITE) @@ -3483,18 +3702,22 @@ public void removeMaxConsumers(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/maxMessageSize") - @ApiOperation(value = "Get maxMessageSize config for specified topic.", response = Integer.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get maxMessageSize config for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get maxMessageSize config for specified topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateAdminAccessForTenantAsync(topicName.getTenant()) @@ -3511,23 +3734,23 @@ public void getMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/maxMessageSize") - @ApiOperation(value = "Set maxMessageSize config for specified topic.") + @Operation(summary = "Set maxMessageSize config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 412, message = "Invalid value of maxConsumers")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "412", description = "Invalid value of maxConsumers")}) public void setMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "The max message size of the topic") int maxMessageSize) { + @RequestBody(description = "The max message size of the topic") int maxMessageSize) { validateTopicName(tenant, namespace, encodedTopic); validateAdminAccessForTenantAsync(topicName.getTenant()) .thenCompose(__ -> preValidation(authoritative)) @@ -3549,20 +3772,20 @@ public void setMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/maxMessageSize") - @ApiOperation(value = "Remove maxMessageSize config for specified topic.") + @Operation(summary = "Remove maxMessageSize config for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateAdminAccessForTenantAsync(topicName.getTenant()) @@ -3583,34 +3806,36 @@ public void removeMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/terminate") - @ApiOperation(value = "Terminate a topic. A topic that is terminated will not accept any more " + @Operation(summary = "Terminate a topic. A topic that is terminated will not accept any more " + "messages to be published and will let consumer to drain existing messages in backlog") @ApiResponses(value = { @ApiResponse( - code = 200, - message = "Operation terminated successfully. The response includes the 'lastMessageId'," + responseCode = "200", + description = "Operation terminated successfully. The response includes the 'lastMessageId'," + " which is the identifier of the last message processed.", - response = MessageIdAdv.class + content = @Content(schema = @Schema(implementation = MessageIdAdv.class)) ), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Termination of a partitioned topic is not allowed"), - @ApiResponse(code = 406, message = "Need to provide a persistent topic name"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Termination of a partitioned topic is not allowed"), + @ApiResponse(responseCode = "406", description = "Need to provide a persistent topic name"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void terminate( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validatePersistentTopicName(tenant, namespace, encodedTopic); internalTerminateAsync(authoritative) @@ -3629,27 +3854,28 @@ public void terminate( @POST @Path("/{tenant}/{namespace}/{topic}/terminate/partitions") - @ApiOperation(value = "Terminate all partitioned topic. A topic that is terminated will not accept any more " + @Operation(summary = "Terminate all partitioned topic. A topic that is terminated will not accept any more " + "messages to be published and will let consumer to drain existing messages in backlog") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Termination of a non-partitioned topic is not allowed"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Termination of a non-partitioned topic is not allowed"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void terminatePartitionedTopic(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker." - + " For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this " + + "broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalTerminatePartitionedTopic(asyncResponse, authoritative); @@ -3657,28 +3883,30 @@ public void terminatePartitionedTopic(@Suspended final AsyncResponse asyncRespon @PUT @Path("/{tenant}/{namespace}/{topic}/compaction") - @ApiOperation(value = "Trigger a compaction operation on a topic.") + @Operation(summary = "Trigger a compaction operation on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Operation is not allowed on the persistent topic"), - @ApiResponse(code = 409, message = "Compaction already running"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Operation is not allowed on the persistent topic"), + @ApiResponse(responseCode = "409", description = "Compaction already running"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void compact( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -3692,27 +3920,33 @@ public void compact( @GET @Path("/{tenant}/{namespace}/{topic}/compaction") - @ApiOperation(value = "Get the status of a compaction operation for a topic.", - response = LongRunningProcessStatus.class) + @Operation(summary = "Get the status of a compaction operation for a topic.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse( + responseCode = "200", + description = "Get the status of a compaction operation for a topic.", + content = @Content(schema = @Schema(implementation = LongRunningProcessStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist, or compaction hasn't run"), - @ApiResponse(code = 405, message = "Operation is not allowed on the persistent topic"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Namespace or topic does not exist, or compaction hasn't run"), + @ApiResponse(responseCode = "405", description = "Operation is not allowed on the persistent topic"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void compactionStatus( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalCompactionStatusAsync(authoritative) @@ -3731,29 +3965,31 @@ public void compactionStatus( @PUT @Path("/{tenant}/{namespace}/{topic}/offload") - @ApiOperation(value = "Offload a prefix of a topic to long term storage") + @Operation(summary = "Offload a prefix of a topic to long term storage") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 400, message = "Message ID is null"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "400", description = "Message ID is null"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Operation is not allowed on the persistent topic"), - @ApiResponse(code = 409, message = "Offload already running"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Operation is not allowed on the persistent topic"), + @ApiResponse(responseCode = "409", description = "Offload already running"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void triggerOffload( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, MessageIdImpl messageId) { try { @@ -3771,26 +4007,32 @@ public void triggerOffload( @GET @Path("/{tenant}/{namespace}/{topic}/offload") - @ApiOperation(value = "Offload a prefix of a topic to long term storage", response = OffloadProcessStatus.class) + @Operation(summary = "Offload a prefix of a topic to long term storage") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse( + responseCode = "200", + description = "Offload a prefix of a topic to long term storage", + content = @Content(schema = @Schema(implementation = OffloadProcessStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Operation is not allowed on the persistent topic"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Operation is not allowed on the persistent topic"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void offloadStatus( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -3804,26 +4046,32 @@ public void offloadStatus( @GET @Path("/{tenant}/{namespace}/{topic}/lastMessageId") - @ApiOperation(value = "Return the last commit message id of topic", response = MessageIdAdv.class) + @Operation(summary = "Return the last commit message id of topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse( + responseCode = "200", + description = "Return the last commit message id of topic", + content = @Content(schema = @Schema(implementation = MessageIdAdv.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Operation is not allowed on the persistent topic"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Operation is not allowed on the persistent topic"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void getLastMessageId( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -3835,27 +4083,29 @@ public void getLastMessageId( @POST @Path("/{tenant}/{namespace}/{topic}/trim") - @ApiOperation(value = " Trim a topic") + @Operation(summary = " Trim a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or" + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or" + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 405, message = "Operation is not allowed on the persistent topic"), - @ApiResponse(code = 412, message = "Topic name is not valid"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "405", description = "Operation is not allowed on the persistent topic"), + @ApiResponse(responseCode = "412", description = "Topic name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void trimTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -3877,19 +4127,23 @@ public void trimTopic( @GET @Path("/{tenant}/{namespace}/{topic}/dispatchRate") - @ApiOperation(value = "Get dispatch rate configuration for specified topic.", response = DispatchRateImpl.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get dispatch rate configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get dispatch rate configuration for specified topic.", + content = @Content(schema = @Schema(implementation = DispatchRateImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.READ) @@ -3904,22 +4158,22 @@ public void getDispatchRate(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/dispatchRate") - @ApiOperation(value = "Set message dispatch rate configuration for specified topic.") + @Operation(summary = "Set message dispatch rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Dispatch rate for the specified topic") DispatchRateImpl dispatchRate) { + @RequestBody(description = "Dispatch rate for the specified topic") DispatchRateImpl dispatchRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -3943,20 +4197,20 @@ public void setDispatchRate(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/dispatchRate") - @ApiOperation(value = "Remove message dispatch rate configuration for specified topic.") + @Operation(summary = "Remove message dispatch rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) @@ -3978,22 +4232,24 @@ public void removeDispatchRate(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/subscriptionDispatchRate") - @ApiOperation( - value = "Get subscription message dispatch rate configuration for specified topic.", - response = DispatchRate.class - ) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation( + summary = "Get subscription message dispatch rate configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get subscription message dispatch rate configuration for specified topic.", + content = @Content(schema = @Schema(implementation = DispatchRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getSubscriptionDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.READ) @@ -4008,23 +4264,23 @@ public void getSubscriptionDispatchRate(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/{topic}/subscriptionDispatchRate") - @ApiOperation(value = "Set subscription message dispatch rate configuration for specified topic.") + @Operation(summary = "Set subscription message dispatch rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSubscriptionDispatchRate( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Subscription message dispatch rate for the specified topic") + @RequestBody(description = "Subscription message dispatch rate for the specified topic") DispatchRateImpl dispatchRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) @@ -4049,20 +4305,20 @@ public void setSubscriptionDispatchRate( @DELETE @Path("/{tenant}/{namespace}/{topic}/subscriptionDispatchRate") - @ApiOperation(value = "Remove subscription message dispatch rate configuration for specified topic.") + @Operation(summary = "Remove subscription message dispatch rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeSubscriptionDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) @@ -4084,13 +4340,16 @@ public void removeSubscriptionDispatchRate(@Suspended final AsyncResponse asyncR @GET @Path("/{tenant}/{namespace}/{topic}/{subName}/dispatchRate") - @ApiOperation(value = "Get message dispatch rate configuration for specified subscription.", - response = DispatchRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get message dispatch rate configuration for specified subscription.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get message dispatch rate configuration for specified subscription.", + content = @Content(schema = @Schema(implementation = DispatchRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getSubscriptionLevelDispatchRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @@ -4098,7 +4357,7 @@ public void getSubscriptionLevelDispatchRate(@Suspended final AsyncResponse asyn @PathParam("subName") @Encoded String encodedSubscriptionName, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.READ) @@ -4114,24 +4373,24 @@ public void getSubscriptionLevelDispatchRate(@Suspended final AsyncResponse asyn @POST @Path("/{tenant}/{namespace}/{topic}/{subName}/dispatchRate") - @ApiOperation(value = "Set message dispatch rate configuration for specified subscription.") + @Operation(summary = "Set message dispatch rate configuration for specified subscription.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSubscriptionLevelDispatchRate( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @PathParam("subName") @Encoded String encodedSubscriptionName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Subscription message dispatch rate for the specified topic") + @RequestBody(description = "Subscription message dispatch rate for the specified topic") DispatchRateImpl dispatchRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) @@ -4156,14 +4415,14 @@ public void setSubscriptionLevelDispatchRate( @DELETE @Path("/{tenant}/{namespace}/{topic}/{subName}/dispatchRate") - @ApiOperation(value = "Remove message dispatch rate configuration for specified subscription.") + @Operation(summary = "Remove message dispatch rate configuration for specified subscription.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeSubscriptionLevelDispatchRate( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -4171,7 +4430,7 @@ public void removeSubscriptionLevelDispatchRate( @PathParam("topic") @Encoded String encodedTopic, @PathParam("subName") @Encoded String encodedSubscriptionName, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) @@ -4195,19 +4454,23 @@ public void removeSubscriptionLevelDispatchRate( @GET @Path("/{tenant}/{namespace}/{topic}/compactionThreshold") - @ApiOperation(value = "Get compaction threshold configuration for specified topic.", response = Long.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get compaction threshold configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get compaction threshold configuration for specified topic.", + content = @Content(schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getCompactionThreshold(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.COMPACTION, PolicyOperation.READ) @@ -4222,22 +4485,22 @@ public void getCompactionThreshold(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/compactionThreshold") - @ApiOperation(value = "Set compaction threshold configuration for specified topic.") + @Operation(summary = "Set compaction threshold configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setCompactionThreshold(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Dispatch rate for the specified topic") long compactionThreshold) { + @RequestBody(description = "Dispatch rate for the specified topic") long compactionThreshold) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.COMPACTION, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -4261,20 +4524,20 @@ public void setCompactionThreshold(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/compactionThreshold") - @ApiOperation(value = "Remove compaction threshold configuration for specified topic.") + @Operation(summary = "Remove compaction threshold configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeCompactionThreshold(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.COMPACTION, PolicyOperation.WRITE) @@ -4296,21 +4559,23 @@ public void removeCompactionThreshold(@Suspended final AsyncResponse asyncRespon @GET @Path("/{tenant}/{namespace}/{topic}/maxConsumersPerSubscription") - @ApiOperation( - value = "Get max consumers per subscription configuration for specified topic.", - response = Integer.class - ) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation( + summary = "Get max consumers per subscription configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get max consumers per subscription configuration for specified topic.", + content = @Content(schema = @Schema(implementation = Integer.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getMaxConsumersPerSubscription(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_CONSUMERS, PolicyOperation.READ) @@ -4326,23 +4591,23 @@ public void getMaxConsumersPerSubscription(@Suspended final AsyncResponse asyncR @POST @Path("/{tenant}/{namespace}/{topic}/maxConsumersPerSubscription") - @ApiOperation(value = "Set max consumers per subscription configuration for specified topic.") + @Operation(summary = "Set max consumers per subscription configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setMaxConsumersPerSubscription( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Dispatch rate for the specified topic") int maxConsumersPerSubscription) { + @RequestBody(description = "Dispatch rate for the specified topic") int maxConsumersPerSubscription) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_CONSUMERS, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -4367,20 +4632,20 @@ public void setMaxConsumersPerSubscription( @DELETE @Path("/{tenant}/{namespace}/{topic}/maxConsumersPerSubscription") - @ApiOperation(value = "Remove max consumers per subscription configuration for specified topic.") + @Operation(summary = "Remove max consumers per subscription configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeMaxConsumersPerSubscription(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.MAX_CONSUMERS, PolicyOperation.WRITE) @@ -4402,18 +4667,22 @@ public void removeMaxConsumersPerSubscription(@Suspended final AsyncResponse asy @GET @Path("/{tenant}/{namespace}/{topic}/publishRate") - @ApiOperation(value = "Get publish rate configuration for specified topic.", response = PublishRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get publish rate configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get publish rate configuration for specified topic.", + content = @Content(schema = @Schema(implementation = PublishRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPublishRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.READ) @@ -4429,22 +4698,22 @@ public void getPublishRate(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/publishRate") - @ApiOperation(value = "Set message publish rate configuration for specified topic.") + @Operation(summary = "Set message publish rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setPublishRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Dispatch rate for the specified topic") PublishRate publishRate) { + @RequestBody(description = "Dispatch rate for the specified topic") PublishRate publishRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -4469,20 +4738,20 @@ public void setPublishRate(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/publishRate") - @ApiOperation(value = "Remove message publish rate configuration for specified topic.") + @Operation(summary = "Remove message publish rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removePublishRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) @@ -4505,22 +4774,25 @@ public void removePublishRate(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/subscriptionTypesEnabled") - @ApiOperation( - value = "Get is enable sub type fors specified topic.", - response = CommandSubscribe.SubType.class, - responseContainer = "List" - ) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation( + summary = "Get is enable sub type fors specified topic.") + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "Get is enable sub type fors specified topic.", + content = @Content(array = @ArraySchema(schema = + @Schema(implementation = CommandSubscribe.SubType.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SUBSCRIPTION_AUTH_MODE, PolicyOperation.READ) @@ -4538,22 +4810,22 @@ public void getSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/{topic}/subscriptionTypesEnabled") - @ApiOperation(value = "Set is enable sub types for specified topic") + @Operation(summary = "Set is enable sub types for specified topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Enable sub types for the specified topic") + @RequestBody(description = "Enable sub types for the specified topic") Set subscriptionTypesEnabled) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SUBSCRIPTION_AUTH_MODE, PolicyOperation.WRITE) @@ -4579,20 +4851,20 @@ public void setSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncResp @DELETE @Path("/{tenant}/{namespace}/{topic}/subscriptionTypesEnabled") - @ApiOperation(value = "Remove subscription types enabled for specified topic.") + @Operation(summary = "Remove subscription types enabled for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, to enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, to enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SUBSCRIPTION_AUTH_MODE, PolicyOperation.WRITE) @@ -4613,19 +4885,23 @@ public void removeSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncR @GET @Path("/{tenant}/{namespace}/{topic}/subscribeRate") - @ApiOperation(value = "Get subscribe rate configuration for specified topic.", response = SubscribeRate.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get subscribe rate configuration for specified topic.") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get subscribe rate configuration for specified topic.", + content = @Content(schema = @Schema(implementation = SubscribeRate.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getSubscribeRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.READ) @@ -4639,23 +4915,23 @@ public void getSubscribeRate(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/subscribeRate") - @ApiOperation(value = "Set subscribe rate configuration for specified topic.") + @Operation(summary = "Set subscribe rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setSubscribeRate( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Subscribe rate for the specified topic") SubscribeRate subscribeRate) { + @RequestBody(description = "Subscribe rate for the specified topic") SubscribeRate subscribeRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -4680,22 +4956,22 @@ public void setSubscribeRate( @DELETE @Path("/{tenant}/{namespace}/{topic}/subscribeRate") - @ApiOperation(value = "Remove subscribe rate configuration for specified topic.") + @Operation(summary = "Remove subscribe rate configuration for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeSubscribeRate(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Subscribe rate for the specified topic") SubscribeRate subscribeRate) { + @RequestBody(description = "Subscribe rate for the specified topic") SubscribeRate subscribeRate) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.RATE, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -4717,25 +4993,27 @@ public void removeSubscribeRate(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/truncate") - @ApiOperation(value = "Truncate a topic.", - notes = "The truncate operation will move all cursors to the end of the topic " + @Operation(summary = "Truncate a topic.", + description = "The truncate operation will move all cursors to the end of the topic " + "and delete all inactive ledgers.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void truncateTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative){ validateTopicName(tenant, namespace, encodedTopic); internalTruncateTopicAsync(authoritative) @@ -4758,31 +5036,33 @@ public void truncateTopic( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/replicatedSubscriptionStatus") - @ApiOperation(value = "Enable or disable a replicated subscription on a topic.") + @Operation(summary = "Enable or disable a replicated subscription on a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant or " + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Topic or subscription does not exist"), - @ApiResponse(code = 405, message = "Operation not allowed on this topic"), - @ApiResponse(code = 412, message = "Can't find owner for topic"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Failed to validate global cluster configuration")}) + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Topic or subscription does not exist"), + @ApiResponse(responseCode = "405", description = "Operation not allowed on this topic"), + @ApiResponse(responseCode = "412", description = "Can't find owner for topic"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void setReplicatedSubscriptionStatus( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Name of subscription", required = true) + @Parameter(description = "Name of subscription", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Whether to enable replicated subscription", required = true) + @RequestBody(description = "Whether to enable replicated subscription", required = true) boolean enabled) { try { validateTopicName(tenant, namespace, encodedTopic); @@ -4796,28 +5076,30 @@ public void setReplicatedSubscriptionStatus( @GET @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/replicatedSubscriptionStatus") - @ApiOperation( - value = "Get replicated subscription status on a topic.", - response = Boolean.class, - responseContainer = "Map" - ) + @Operation( + summary = "Get replicated subscription status on a topic.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 412, message = "Can't find owner for topic"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse( + responseCode = "200", + description = "Get replicated subscription status on a topic.", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesSchema = @Schema(type = "boolean"))), + @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "412", description = "Can't find owner for topic"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getReplicatedSubscriptionStatus( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Name of subscription", required = true) + @Parameter(description = "Name of subscription", required = true) @PathParam("subName") String encodedSubName, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); internalGetReplicatedSubscriptionStatus(asyncResponse, decode(encodedSubName), authoritative); @@ -4825,22 +5107,27 @@ public void getReplicatedSubscriptionStatus( @GET @Path("/{tenant}/{namespace}/{topic}/schemaCompatibilityStrategy") - @ApiOperation(value = "Get schema compatibility strategy on a topic", response = SchemaCompatibilityStrategy.class) + @Operation(summary = "Get schema compatibility strategy on a topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 405, message = "Operation not allowed on persistent topic"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist")}) + @ApiResponse( + responseCode = "200", + description = "Get schema compatibility strategy on a topic", + content = @Content(schema = @Schema(implementation = SchemaCompatibilityStrategy.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "405", description = "Operation not allowed on persistent topic"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist")}) public void getSchemaCompatibilityStrategy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the cluster", required = true) + @Parameter(description = "Specify the cluster", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SCHEMA_COMPATIBILITY_STRATEGY, PolicyOperation.READ) @@ -4855,24 +5142,25 @@ public void getSchemaCompatibilityStrategy( @PUT @Path("/{tenant}/{namespace}/{topic}/schemaCompatibilityStrategy") - @ApiOperation(value = "Set schema compatibility strategy on a topic") + @Operation(summary = "Set schema compatibility strategy on a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 405, message = "Operation not allowed on persistent topic"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "405", description = "Operation not allowed on persistent topic"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist")}) public void setSchemaCompatibilityStrategy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Strategy used to check the compatibility of new schema") + @RequestBody(description = "Strategy used to check the compatibility of new schema") SchemaCompatibilityStrategy strategy) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SCHEMA_COMPATIBILITY_STRATEGY, PolicyOperation.WRITE) @@ -4894,24 +5182,25 @@ public void setSchemaCompatibilityStrategy( @DELETE @Path("/{tenant}/{namespace}/{topic}/schemaCompatibilityStrategy") - @ApiOperation(value = "Remove schema compatibility strategy on a topic") + @Operation(summary = "Remove schema compatibility strategy on a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 405, message = "Operation not allowed on persistent topic"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "405", description = "Operation not allowed on persistent topic"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist")}) public void removeSchemaCompatibilityStrategy( @Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Strategy used to check the compatibility of new schema") + @RequestBody(description = "Strategy used to check the compatibility of new schema") SchemaCompatibilityStrategy strategy) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SCHEMA_COMPATIBILITY_STRATEGY, PolicyOperation.WRITE) @@ -4933,19 +5222,23 @@ public void removeSchemaCompatibilityStrategy( @GET @Path("/{tenant}/{namespace}/{topic}/schemaValidationEnforced") - @ApiOperation(value = "Get schema validation enforced flag for topic.", response = Boolean.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenants or Namespace doesn't exist") }) + @Operation(summary = "Get schema validation enforced flag for topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get schema validation enforced flag for topic.", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenants or Namespace doesn't exist") }) public void getSchemaValidationEnforced(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, - @ApiParam(value = "Whether leader broker redirected this call to this " - + "broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call " + + "to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SCHEMA_COMPATIBILITY_STRATEGY, PolicyOperation.READ) @@ -4960,23 +5253,23 @@ public void getSchemaValidationEnforced(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/schemaValidationEnforced") - @ApiOperation(value = "Set schema validation enforced flag on topic.") + @Operation(summary = "Set schema validation enforced flag on topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or Namespace doesn't exist"), - @ApiResponse(code = 412, message = "schemaValidationEnforced value is not valid")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace doesn't exist"), + @ApiResponse(responseCode = "412", description = "schemaValidationEnforced value is not valid")}) public void setSchemaValidationEnforced(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this " - + "broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call " + + "to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(required = true) boolean schemaValidationEnforced) { + @RequestBody(required = true) boolean schemaValidationEnforced) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SCHEMA_COMPATIBILITY_STRATEGY, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -4990,19 +5283,23 @@ public void setSchemaValidationEnforced(@Suspended AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/entryFilters") - @ApiOperation(value = "Get entry filters for a topic.", response = EntryFilters.class) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenants or Namespace doesn't exist") }) + @Operation(summary = "Get entry filters for a topic.") + @ApiResponses(value = { @ApiResponse( + responseCode = "200", + description = "Get entry filters for a topic.", + content = @Content(schema = @Schema(implementation = EntryFilters.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenants or Namespace doesn't exist") }) public void getEntryFilters(@Suspended AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("applied") @DefaultValue("false") boolean applied, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this " + @Parameter(description = "Whether leader broker redirected this call to this " + "broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -5018,23 +5315,23 @@ public void getEntryFilters(@Suspended AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/{topic}/entryFilters") - @ApiOperation(value = "Set entry filters for specified topic") + @Operation(summary = "Set entry filters for specified topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this" + @Parameter(description = "Whether leader broker redirected this" + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Entry filters for the specified topic") + @RequestBody(description = "Entry filters for the specified topic") EntryFilters entryFilters) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.ENTRY_FILTERS, PolicyOperation.WRITE) @@ -5049,20 +5346,20 @@ public void setEntryFilters(@Suspended final AsyncResponse asyncResponse, @DELETE @Path("/{tenant}/{namespace}/{topic}/entryFilters") - @ApiOperation(value = "Remove entry filters for specified topic.") + @Operation(summary = "Remove entry filters for specified topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this" + @Parameter(description = "Whether leader broker redirected this" + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -5086,18 +5383,21 @@ public void removeEntryFilters(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/shadowTopics") - @ApiOperation(value = "Get the shadow topic list for a topic", - response = String.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @Operation(summary = "Get the shadow topic list for a topic") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get the shadow topic list for a topic", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry")}) public void getShadowTopics( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SHADOW_TOPIC, PolicyOperation.READ) @@ -5112,23 +5412,23 @@ public void getShadowTopics( @PUT @Path("/{tenant}/{namespace}/{topic}/shadowTopics") - @ApiOperation(value = "Set shadow topic list for a topic") + @Operation(summary = "Set shadow topic list for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), }) public void setShadowTopics( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "List of shadow topics", required = true) List shadowTopics) { + @RequestBody(description = "List of shadow topics", required = true) List shadowTopics) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SHADOW_TOPIC, PolicyOperation.WRITE) .thenCompose(__ -> preValidation(authoritative)) @@ -5142,21 +5442,21 @@ public void setShadowTopics( @DELETE @Path("/{tenant}/{namespace}/{topic}/shadowTopics") - @ApiOperation(value = "Delete shadow topics for a topic") + @Operation(summary = "Delete shadow topics for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), }) public void deleteShadowTopics( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.SHADOW_TOPIC, PolicyOperation.WRITE) @@ -5171,14 +5471,14 @@ public void deleteShadowTopics( @POST @Path("/{tenant}/{namespace}/{topic}/autoSubscriptionCreation") - @ApiOperation(value = "Override namespace's allowAutoSubscriptionCreation setting for a topic") + @Operation(summary = "Override namespace's allowAutoSubscriptionCreation setting for a topic") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Topic doesn't exist"), - @ApiResponse(code = 405, message = + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Topic doesn't exist"), + @ApiResponse(responseCode = "405", description = "Topic level policy is disabled, enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void setAutoSubscriptionCreation( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -5186,7 +5486,7 @@ public void setAutoSubscriptionCreation( @PathParam("topic") String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Settings for automatic subscription creation") + @RequestBody(description = "Settings for automatic subscription creation") AutoSubscriptionCreationOverrideImpl autoSubscriptionCreationOverride) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.AUTO_SUBSCRIPTION_CREATION, PolicyOperation.WRITE) @@ -5201,13 +5501,16 @@ public void setAutoSubscriptionCreation( @GET @Path("/{tenant}/{namespace}/{topic}/autoSubscriptionCreation") - @ApiOperation(value = "Get autoSubscriptionCreation info in a topic", - response = AutoSubscriptionCreationOverrideImpl.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Topic does not exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @Operation(summary = "Get autoSubscriptionCreation info in a topic") + @ApiResponses(value = {@ApiResponse( + responseCode = "200", + description = "Get autoSubscriptionCreation info in a topic", + content = @Content(schema = @Schema(implementation = AutoSubscriptionCreationOverrideImpl.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Topic does not exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getAutoSubscriptionCreation( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @@ -5228,21 +5531,21 @@ public void getAutoSubscriptionCreation( @DELETE @Path("/{tenant}/{namespace}/{topic}/autoSubscriptionCreation") - @ApiOperation(value = "Remove autoSubscriptionCreation ina a topic.") + @Operation(summary = "Remove autoSubscriptionCreation ina a topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Topic does not exist"), - @ApiResponse(code = 405, - message = "Topic level policy is disabled, please enable the topic level policy and retry"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Topic does not exist"), + @ApiResponse(responseCode = "405", + description = "Topic level policy is disabled, please enable the topic level policy and retry"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void removeAutoSubscriptionCreation( @Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @ApiParam(value = "Whether leader broker redirected this call to this broker. For internal use.") + @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperationAsync(topicName, PolicyName.AUTO_SUBSCRIPTION_CREATION, PolicyOperation.WRITE) @@ -5265,16 +5568,17 @@ public void removeAutoSubscriptionCreation( @GET @Path("/{tenant}/{namespace}/{topic}/getMessageIdByIndex") - @ApiOperation(hidden = true, value = "Get Message ID by index.", - notes = "If the specified index is a system message, " + @Operation(hidden = true, summary = "Get Message ID by index.", + description = "If the specified index is a system message, " + "it will return the message id of the later message.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace or partitioned topic does not exist, " + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace or partitioned topic does not exist, " + "or the index is invalid"), - @ApiResponse(code = 406, message = "The topic is not a persistent topic"), - @ApiResponse(code = 412, message = "The broker is not enable broker entry metadata"), + @ApiResponse(responseCode = "406", description = "The topic is not a persistent topic"), + @ApiResponse(responseCode = "412", description = "The broker is not enable broker entry metadata"), }) public void getMessageIDByIndex(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceGroups.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceGroups.java index f0cef0f8edef3..4ce33d729668f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceGroups.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceGroups.java @@ -17,11 +17,14 @@ * under the License. */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -37,48 +40,54 @@ @Path("/resourcegroups") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@Api(value = "/resourcegroups", description = "ResourceGroups admin apis", tags = "resourcegroups") +@Tag(name = "resourcegroups", description = "ResourceGroups admin apis") @SuppressWarnings("deprecation") public class ResourceGroups extends ResourceGroupsBase { @GET - @ApiOperation(value = "Get the list of all the resourcegroups.", - response = String.class, responseContainer = "Set") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission")}) + @Operation(summary = "Get the list of all the resourcegroups.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the list of all the resourcegroups.", + content = @Content(array = @ArraySchema(uniqueItems = true, + schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission")}) public List getResourceGroups() { return internalGetResourceGroups(); } @GET @Path("/{resourcegroup}") - @ApiOperation(value = "Get the rate limiters specified for a resourcegroup.", response = ResourceGroup.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "ResourceGroup doesn't exist")}) + @Operation(summary = "Get the rate limiters specified for a resourcegroup.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the rate limiters specified for a resourcegroup.", + content = @Content(schema = @Schema(implementation = ResourceGroup.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "ResourceGroup doesn't exist")}) public ResourceGroup getResourceGroup(@PathParam("resourcegroup") String resourcegroup) { return internalGetResourceGroup(resourcegroup); } @PUT @Path("/{resourcegroup}") - @ApiOperation(value = "Creates a new resourcegroup with the specified rate limiters") + @Operation(summary = "Creates a new resourcegroup with the specified rate limiters") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "cluster doesn't exist")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "cluster doesn't exist")}) public void createOrUpdateResourceGroup(@PathParam("resourcegroup") String name, - @ApiParam(value = "Rate limiters for the resourcegroup") + @RequestBody(description = "Rate limiters for the resourcegroup") ResourceGroup resourcegroup) { internalCreateOrUpdateResourceGroup(name, resourcegroup); } @DELETE @Path("/{resourcegroup}") - @ApiOperation(value = "Delete a resourcegroup.") + @Operation(summary = "Delete a resourcegroup.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "ResourceGroup doesn't exist"), - @ApiResponse(code = 409, message = "ResourceGroup is in use")}) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "ResourceGroup doesn't exist"), + @ApiResponse(responseCode = "409", description = "ResourceGroup is in use")}) public void deleteResourceGroup(@PathParam("resourcegroup") String resourcegroup) { internalDeleteResourceGroup(resourcegroup); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceQuotas.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceQuotas.java index 7ec64f3af51a0..343a21a4f16bd 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceQuotas.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ResourceQuotas.java @@ -18,11 +18,15 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -40,13 +44,17 @@ @Path("/resource-quotas") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@Api(value = "/resource-quotas", description = "Quota admin APIs", tags = "resource-quotas") +@Tag(name = "resource-quotas", description = "Quota admin APIs") @SuppressWarnings("deprecation") public class ResourceQuotas extends ResourceQuotasBase { @GET - @ApiOperation(value = "Get the default quota", response = String.class, responseContainer = "Set") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get the default quota") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the default quota", + content = @Content(array = @ArraySchema(uniqueItems = true, + schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void getDefaultResourceQuota(@Suspended AsyncResponse response) { getDefaultResourceQuotaAsync() .thenAccept(response::resume) @@ -58,11 +66,15 @@ public void getDefaultResourceQuota(@Suspended AsyncResponse response) { } @POST - @ApiOperation(value = "Set the default quota", response = String.class, responseContainer = "Set") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Set the default quota") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Set the default quota", + content = @Content(array = @ArraySchema(uniqueItems = true, + schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public void setDefaultResourceQuota( @Suspended AsyncResponse response, - @ApiParam(value = "Default resource quota") ResourceQuota quota) { + @RequestBody(description = "Default resource quota") ResourceQuota quota) { setDefaultResourceQuotaAsync(quota) .thenAccept(__ -> response.resume(Response.noContent().build())) .exceptionally(ex -> { @@ -74,18 +86,20 @@ public void setDefaultResourceQuota( @GET @Path("/{tenant}/{namespace}/{bundle}") - @ApiOperation(value = "Get resource quota of a namespace bundle.", response = ResourceQuota.class) + @Operation(summary = "Get resource quota of a namespace bundle.") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Namespace does not exist") }) + @ApiResponse(responseCode = "200", description = "Get resource quota of a namespace bundle.", + content = @Content(schema = @Schema(implementation = ResourceQuota.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void getNamespaceBundleResourceQuota( @Suspended AsyncResponse response, - @ApiParam(value = "Tenant name") + @Parameter(description = "Tenant name") @PathParam("tenant") String tenant, - @ApiParam(value = "Namespace name within the specified tenant") + @Parameter(description = "Namespace name within the specified tenant") @PathParam("namespace") String namespace, - @ApiParam(value = "Namespace bundle range") + @Parameter(description = "Namespace bundle range") @PathParam("bundle") String bundleRange) { validateNamespaceName(tenant, namespace); internalGetNamespaceBundleResourceQuota(bundleRange) @@ -102,21 +116,21 @@ public void getNamespaceBundleResourceQuota( @POST @Path("/{tenant}/{namespace}/{bundle}") - @ApiOperation(value = "Set resource quota on a namespace.") + @Operation(summary = "Set resource quota on a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void setNamespaceBundleResourceQuota( @Suspended AsyncResponse response, - @ApiParam(value = "Tenant name") + @Parameter(description = "Tenant name") @PathParam("tenant") String tenant, - @ApiParam(value = "Namespace name within the specified tenant") + @Parameter(description = "Namespace name within the specified tenant") @PathParam("namespace") String namespace, - @ApiParam(value = "Namespace bundle range") + @Parameter(description = "Namespace bundle range") @PathParam("bundle") String bundleRange, - @ApiParam(value = "Resource quota for the specified namespace") ResourceQuota quota) { + @RequestBody(description = "Resource quota for the specified namespace") ResourceQuota quota) { validateNamespaceName(tenant, namespace); internalSetNamespaceBundleResourceQuota(bundleRange, quota) .thenAccept(__ -> { @@ -137,19 +151,19 @@ public void setNamespaceBundleResourceQuota( @DELETE @Path("/{tenant}/{namespace}/{bundle}") - @ApiOperation(value = "Remove resource quota for a namespace.") + @Operation(summary = "Remove resource quota for a namespace.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace"), - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 409, message = "Concurrent modification") }) + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void removeNamespaceBundleResourceQuota( @Suspended AsyncResponse response, - @ApiParam(value = "Tenant name") + @Parameter(description = "Tenant name") @PathParam("tenant") String tenant, - @ApiParam(value = "Namespace name within the specified tenant") + @Parameter(description = "Namespace name within the specified tenant") @PathParam("namespace") String namespace, - @ApiParam(value = "Namespace bundle range") + @Parameter(description = "Namespace bundle range") @PathParam("bundle") String bundleRange) { validateNamespaceName(tenant, namespace); internalRemoveNamespaceBundleResourceQuota(bundleRange) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java index 3fdb7ff75d056..13afb2abe2e62 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java @@ -18,11 +18,15 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -75,7 +79,7 @@ @CustomLog @Path("/scalable") @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/scalable", description = "Scalable topic admin APIs", tags = "scalable topic") +@Tag(name = "scalable topic", description = "Scalable topic admin APIs") public class ScalableTopics extends AdminResource { private ScalableTopicResources resources() { @@ -86,20 +90,22 @@ private ScalableTopicResources resources() { @GET @Path("/{tenant}/{namespace}") - @ApiOperation(value = "Get the list of scalable topics under a namespace.", - response = String.class, responseContainer = "List") + @Operation(summary = "Get the list of scalable topics under a namespace.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Tenant or namespace doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "200", description = "Get the list of scalable topics under a namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getList( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Filter to topics whose properties contain every key=value pair." + @Parameter(description = "Filter to topics whose properties contain every key=value pair." + " Each repetition of the parameter adds one filter (AND semantics).") @QueryParam("property") List properties) { validateNamespaceName(tenant, namespace); @@ -146,25 +152,26 @@ private static Map parseKeyValuePairs(List entries) { @PUT @Path("/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Create a new scalable topic.") + @Operation(summary = "Create a new scalable topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Scalable topic created successfully"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 409, message = "Scalable topic already exists"), - @ApiResponse(code = 412, message = "Invalid configuration"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Scalable topic created successfully"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "409", description = "Scalable topic already exists"), + @ApiResponse(responseCode = "412", description = "Invalid configuration"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void createScalableTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Number of initial segments") + @Parameter(description = "Number of initial segments") @QueryParam("numInitialSegments") @DefaultValue("1") int numInitialSegments, - @ApiParam(value = "Key value pair properties for the topic metadata") + @RequestBody(description = "Key value pair properties for the topic metadata") Map properties) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -234,25 +241,26 @@ private CompletableFuture createInitialSegmentTopicsAsync( @POST @Path("/{tenant}/{namespace}/{topic}/migrate") - @ApiOperation(value = "Migrate an existing regular (partitioned or non-partitioned) topic " + @Operation(summary = "Migrate an existing regular (partitioned or non-partitioned) topic " + "to a scalable topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Topic migrated successfully"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have produce permission on the topic"), - @ApiResponse(code = 404, message = "Topic doesn't exist"), - @ApiResponse(code = 409, message = "Already a scalable topic, or legacy v4 clients are " + @ApiResponse(responseCode = "204", description = "Topic migrated successfully"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have produce permission on the topic"), + @ApiResponse(responseCode = "404", description = "Topic doesn't exist"), + @ApiResponse(responseCode = "409", description = "Already a scalable topic, or legacy v4 clients are " + "still connected and force was not set"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void migrateToScalable( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Migrate even if legacy v4 clients are still connected to the topic") + @Parameter(description = "Migrate even if legacy v4 clients are still connected to the topic") @QueryParam("force") @DefaultValue("false") boolean force) { validateNamespaceName(tenant, namespace); // The scalable topic's canonical identity uses the topic:// domain; the migration @@ -431,19 +439,22 @@ private CompletableFuture terminateLegacyTopicsAsync(TopicName persistentB @GET @Path("/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Get scalable topic metadata.", response = ScalableTopicMetadata.class) + @Operation(summary = "Get scalable topic metadata.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "200", description = "Get scalable topic metadata.", + content = @Content(schema = @Schema(implementation = ScalableTopicMetadata.class))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getScalableTopicMetadata( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -470,22 +481,23 @@ public void getScalableTopicMetadata( @DELETE @Path("/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Delete a scalable topic and all its segments.") + @Operation(summary = "Delete a scalable topic and all its segments.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Scalable topic deleted successfully"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Scalable topic deleted successfully"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void deleteScalableTopic( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Force deletion even if topic has active subscriptions") + @Parameter(description = "Force deletion even if topic has active subscriptions") @QueryParam("force") @DefaultValue("false") boolean force) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -518,20 +530,23 @@ public void deleteScalableTopic( @GET @Path("/{tenant}/{namespace}/{topic}/stats") - @ApiOperation(value = "Get aggregated stats for a scalable topic.", - response = org.apache.pulsar.common.policies.data.ScalableTopicStats.class) + @Operation(summary = "Get aggregated stats for a scalable topic.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "200", description = "Get aggregated stats for a scalable topic.", + content = @Content(schema = @Schema( + implementation = org.apache.pulsar.common.policies.data.ScalableTopicStats.class))), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getStats( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -551,24 +566,25 @@ public void getStats( @PUT @Path("/{tenant}/{namespace}/{topic}/subscriptions/{subscription}") - @ApiOperation(value = "Create a subscription on a scalable topic.") + @Operation(summary = "Create a subscription on a scalable topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Subscription created successfully"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Subscription created successfully"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void createSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Subscription type: STREAM (controller-managed, ordered) " + @Parameter(description = "Subscription type: STREAM (controller-managed, ordered) " + "or QUEUE (direct per-segment attach, no controller coordination)") @QueryParam("type") @DefaultValue("STREAM") org.apache.pulsar.broker.resources.SubscriptionType type) { @@ -595,22 +611,23 @@ public void createSubscription( @DELETE @Path("/{tenant}/{namespace}/{topic}/subscriptions/{subscription}") - @ApiOperation(value = "Delete a subscription from a scalable topic.") + @Operation(summary = "Delete a subscription from a scalable topic.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Subscription deleted successfully"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic or subscription doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Subscription deleted successfully"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic or subscription doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void deleteSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -635,26 +652,27 @@ public void deleteSubscription( @POST @Path("/{tenant}/{namespace}/{topic}/subscriptions/{subscription}/seek") - @ApiOperation(value = "Reset a subscription's cursor on every segment to the given" + @Operation(summary = "Reset a subscription's cursor on every segment to the given" + " wall-clock timestamp. The controller uses each segment's recorded sealed-time" + " window to dispatch the cheapest per-segment op.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Cursor reset successfully on all segments"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic or subscription doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Cursor reset successfully on all segments"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic or subscription doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void seekSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Wall-clock millis since the unix epoch", required = true) + @Parameter(description = "Wall-clock millis since the unix epoch", required = true) @QueryParam("timestamp") long timestampMs) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -680,23 +698,24 @@ public void seekSubscription( @POST @Path("/{tenant}/{namespace}/{topic}/subscriptions/{subscription}/skip-all") - @ApiOperation(value = "Skip every undelivered message on the subscription, across every" + @Operation(summary = "Skip every undelivered message on the subscription, across every" + " segment in the DAG (advance each per-segment cursor to the end).") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Backlog cleared successfully on all segments"), - @ApiResponse(code = 401, message = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(code = 403, message = "Don't have admin permission on the namespace"), - @ApiResponse(code = 404, message = "Scalable topic or subscription doesn't exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Backlog cleared successfully on all segments"), + @ApiResponse(responseCode = "401", + description = "Don't have permission to administrate resources on this tenant"), + @ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"), + @ApiResponse(responseCode = "404", description = "Scalable topic or subscription doesn't exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void clearBacklog( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -723,21 +742,21 @@ public void clearBacklog( @POST @Path("/{tenant}/{namespace}/{topic}/split/{segmentId}") - @ApiOperation(value = "Split a segment into two halves.") + @Operation(summary = "Split a segment into two halves.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Segment split successfully"), - @ApiResponse(code = 404, message = "Scalable topic or segment doesn't exist"), - @ApiResponse(code = 412, message = "Segment is not active or cannot be split"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Segment split successfully"), + @ApiResponse(responseCode = "404", description = "Scalable topic or segment doesn't exist"), + @ApiResponse(responseCode = "412", description = "Segment is not active or cannot be split"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void splitSegment( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment ID to split", required = true) + @Parameter(description = "Segment ID to split", required = true) @PathParam("segmentId") long segmentId) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); @@ -761,23 +780,23 @@ public void splitSegment( @POST @Path("/{tenant}/{namespace}/{topic}/merge/{segmentId1}/{segmentId2}") - @ApiOperation(value = "Merge two adjacent segments into one.") + @Operation(summary = "Merge two adjacent segments into one.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Segments merged successfully"), - @ApiResponse(code = 404, message = "Scalable topic or segment doesn't exist"), - @ApiResponse(code = 412, message = "Segments are not active or not adjacent"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Segments merged successfully"), + @ApiResponse(responseCode = "404", description = "Scalable topic or segment doesn't exist"), + @ApiResponse(responseCode = "412", description = "Segments are not active or not adjacent"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void mergeSegments( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "First segment ID to merge", required = true) + @Parameter(description = "First segment ID to merge", required = true) @PathParam("segmentId1") long segmentId1, - @ApiParam(value = "Second segment ID to merge", required = true) + @Parameter(description = "Second segment ID to merge", required = true) @PathParam("segmentId2") long segmentId2) { validateNamespaceName(tenant, namespace); TopicName tn = TopicName.get(TopicDomain.topic.value(), namespaceName, encodedTopic); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/SchemasResource.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/SchemasResource.java index 6c33de66ac317..b60bdd08bf6f3 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/SchemasResource.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/SchemasResource.java @@ -19,13 +19,14 @@ package org.apache.pulsar.broker.admin.v2; import com.google.common.annotations.VisibleForTesting; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.Example; -import io.swagger.annotations.ExampleProperty; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; @@ -54,10 +55,9 @@ import org.apache.pulsar.common.util.FutureUtil; @Path("/schemas") -@Api( - value = "/schemas", - description = "Schemas related admin APIs", - tags = "schemas" +@Tag( + name = "schemas", + description = "Schemas related admin APIs" ) @SuppressWarnings("deprecation") public class SchemasResource extends SchemasResourceBase { @@ -70,15 +70,19 @@ public SchemasResource() { @GET @Path("/{tenant}/{namespace}/{topic}/schema") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Get the schema of a topic", response = GetSchemaResponse.class) + @Operation(summary = "Get the schema of a topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, - message = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "Get the schema of a topic", + content = @Content(schema = @Schema(implementation = GetSchemaResponse.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", + description = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void getSchema( @PathParam("tenant") String tenant, @@ -105,15 +109,19 @@ public void getSchema( @GET @Path("/{tenant}/{namespace}/{topic}/schema/{version}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Get the schema of a topic at a given version", response = GetSchemaResponse.class) + @Operation(summary = "Get the schema of a topic at a given version") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, - message = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "Get the schema of a topic at a given version", + content = @Content(schema = @Schema(implementation = GetSchemaResponse.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", + description = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void getSchema( @PathParam("tenant") String tenant, @@ -142,15 +150,19 @@ public void getSchema( @GET @Path("/{tenant}/{namespace}/{topic}/schemas") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Get the all schemas of a topic", response = GetAllVersionsSchemaResponse.class) + @Operation(summary = "Get the all schemas of a topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, - message = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "Get the all schemas of a topic", + content = @Content(schema = @Schema(implementation = GetAllVersionsSchemaResponse.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", + description = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void getAllSchemas( @PathParam("tenant") String tenant, @@ -177,15 +189,19 @@ public void getAllSchemas( @GET @Path("/{tenant}/{namespace}/{topic}/metadata") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Get the schema metadata of a topic", response = GetAllVersionsSchemaResponse.class) + @Operation(summary = "Get the schema metadata of a topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, - message = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "Get the schema metadata of a topic", + content = @Content(schema = @Schema(implementation = GetAllVersionsSchemaResponse.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", + description = "Tenant or Namespace or Topic doesn't exist; or Schema is not found for this topic"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void getSchemaMetadata( @PathParam("tenant") String tenant, @@ -210,14 +226,16 @@ public void getSchemaMetadata( @DELETE @Path("/{tenant}/{namespace}/{topic}/schema") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Delete all versions schema of a topic", response = DeleteSchemaResponse.class) + @Operation(summary = "Delete all versions schema of a topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, message = "Tenant or Namespace or Topic doesn't exist"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "Delete all versions schema of a topic", + content = @Content(schema = @Schema(implementation = DeleteSchemaResponse.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace or Topic doesn't exist"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void deleteSchema( @PathParam("tenant") String tenant, @@ -247,25 +265,27 @@ public void deleteSchema( @Path("/{tenant}/{namespace}/{topic}/schema") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Update the schema of a topic", response = PostSchemaResponse.class) + @Operation(summary = "Update the schema of a topic") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, message = "Tenant or Namespace or Topic doesn't exist"), - @ApiResponse(code = 409, message = "Incompatible schema"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 422, message = "Invalid schema data"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "Update the schema of a topic", + content = @Content(schema = @Schema(implementation = PostSchemaResponse.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace or Topic doesn't exist"), + @ApiResponse(responseCode = "409", description = "Incompatible schema"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "422", description = "Invalid schema data"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void postSchema( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") String topic, - @ApiParam(value = "A JSON value presenting a schema payload." + @RequestBody(description = "A JSON value presenting a schema payload." + " An example of the expected schema can be found down here.", - examples = @Example(value = @ExampleProperty(mediaType = MediaType.APPLICATION_JSON, - value = "{\"type\": \"STRING\", \"schema\": \"\", \"properties\": { \"key1\" : \"value1\" + } }"))) + content = @Content(mediaType = MediaType.APPLICATION_JSON, examples = @ExampleObject( + value = "{\"type\": \"STRING\", \"schema\": \"\", \"properties\": { \"key1\" : \"value1\" } }"))) PostSchemaPayload payload, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @Suspended final AsyncResponse response) { @@ -298,23 +318,27 @@ public void postSchema( @Path("/{tenant}/{namespace}/{topic}/compatibility") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - @ApiOperation(value = "test the schema compatibility", response = IsCompatibilityResponse.class) + @Operation(summary = "test the schema compatibility") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, message = "Tenant or Namespace or Topic doesn't exist"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "test the schema compatibility", + content = @Content(schema = @Schema(implementation = IsCompatibilityResponse.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace or Topic doesn't exist"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void testCompatibility( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") String topic, - @ApiParam(value = "A JSON value presenting a schema payload." + @RequestBody(description = "A JSON value presenting a schema payload." + " An example of the expected schema can be found down here.", - examples = @Example(value = @ExampleProperty(mediaType = MediaType.APPLICATION_JSON, - value = "{\"type\": \"STRING\", \"schema\": \"\"," + " \"properties\": { \"key1\" : \"value1\" + } }"))) + content = @Content(mediaType = MediaType.APPLICATION_JSON, examples = @ExampleObject( + value = "{\"type\": \"STRING\", \"schema\": \"\"," + " \"properties\": { \"key1\" : \"value1\" } }"))) PostSchemaPayload payload, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @Suspended final AsyncResponse response) { @@ -340,24 +364,28 @@ public void testCompatibility( @Path("/{tenant}/{namespace}/{topic}/version") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - @ApiOperation(value = "get the version of the schema", response = LongSchemaVersion.class) + @Operation(summary = "get the version of the schema") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(code = 401, message = "Client is not authorized or Don't have admin permission"), - @ApiResponse(code = 403, message = "Client is not authenticated"), - @ApiResponse(code = 404, message = "Tenant or Namespace or Topic doesn't exist"), - @ApiResponse(code = 412, message = "Failed to find the ownership for the topic"), - @ApiResponse(code = 422, message = "Invalid schema data"), - @ApiResponse(code = 500, message = "Internal Server Error"), + @ApiResponse(responseCode = "200", description = "get the version of the schema", + content = @Content(schema = @Schema(implementation = LongSchemaVersion.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic"), + @ApiResponse(responseCode = "401", + description = "Client is not authorized or Don't have admin permission"), + @ApiResponse(responseCode = "403", description = "Client is not authenticated"), + @ApiResponse(responseCode = "404", description = "Tenant or Namespace or Topic doesn't exist"), + @ApiResponse(responseCode = "412", description = "Failed to find the ownership for the topic"), + @ApiResponse(responseCode = "422", description = "Invalid schema data"), + @ApiResponse(responseCode = "500", description = "Internal Server Error"), }) public void getVersionBySchema( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") String topic, - @ApiParam(value = "A JSON value presenting a schema payload." + @RequestBody(description = "A JSON value presenting a schema payload." + " An example of the expected schema can be found down here.", - examples = @Example(value = @ExampleProperty(mediaType = MediaType.APPLICATION_JSON, - value = "{\"type\": \"STRING\", \"schema\": \"\"," + " \"properties\": { \"key1\" : \"value1\" + } }"))) + content = @Content(mediaType = MediaType.APPLICATION_JSON, examples = @ExampleObject( + value = "{\"type\": \"STRING\", \"schema\": \"\"," + " \"properties\": { \"key1\" : \"value1\" } }"))) PostSchemaPayload payload, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @Suspended final AsyncResponse response) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Segments.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Segments.java index 1a9c02778237c..ffc5d14664c01 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Segments.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Segments.java @@ -18,11 +18,12 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -64,7 +65,7 @@ @CustomLog @Path("/segments") @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/segments", description = "Segment topic admin APIs", tags = "segments") +@Tag(name = "segments", description = "Segment topic admin APIs") public class Segments extends AdminResource { private TopicName segmentTopicName(String tenant, String namespace, @@ -75,25 +76,25 @@ private TopicName segmentTopicName(String tenant, String namespace, @PUT @Path("/{tenant}/{namespace}/{topic}/{descriptor}") - @ApiOperation(value = "Create a segment topic on the owning broker. Super-user only.") + @Operation(summary = "Create a segment topic on the owning broker. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Segment topic created successfully"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Segment topic created successfully"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void createSegment( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Subscriptions to create on the new segment") + @RequestBody(description = "Subscriptions to create on the new segment") List subscriptions) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -132,24 +133,24 @@ public void createSegment( @POST @Path("/{tenant}/{namespace}/{topic}/{descriptor}/terminate") - @ApiOperation(value = "Terminate a segment topic so no more messages can be published. Super-user only.") + @Operation(summary = "Terminate a segment topic so no more messages can be published. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Segment topic terminated successfully"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 404, message = "Segment topic not found"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Segment topic terminated successfully"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "404", description = "Segment topic not found"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void terminateSegment( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -183,26 +184,26 @@ public void terminateSegment( @PUT @Path("/{tenant}/{namespace}/{topic}/{descriptor}/subscription/{subscription}") - @ApiOperation(value = "Create a subscription cursor on the segment topic at the earliest" + @Operation(summary = "Create a subscription cursor on the segment topic at the earliest" + " position. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Subscription cursor created (or already existed)"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Subscription cursor created (or already existed)"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void createSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -229,25 +230,25 @@ public void createSubscription( @DELETE @Path("/{tenant}/{namespace}/{topic}/{descriptor}/subscription/{subscription}") - @ApiOperation(value = "Delete a subscription cursor on the segment topic. Super-user only.") + @Operation(summary = "Delete a subscription cursor on the segment topic. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Subscription cursor deleted (or never existed)"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Subscription cursor deleted (or never existed)"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void deleteSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -284,26 +285,26 @@ public void deleteSubscription( @GET @Path("/{tenant}/{namespace}/{topic}/{descriptor}/subscription/{subscription}/backlog") - @ApiOperation(value = "Number of unconsumed entries in the segment topic for the " + @Operation(summary = "Number of unconsumed entries in the segment topic for the " + "given subscription. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 404, message = "Segment topic or subscription not found"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "404", description = "Segment topic or subscription not found"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getSubscriptionBacklog( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -337,29 +338,29 @@ public void getSubscriptionBacklog( @POST @Path("/{tenant}/{namespace}/{topic}/{descriptor}/subscription/{subscription}/seek") - @ApiOperation(value = "Reset the segment topic's subscription cursor to the given timestamp." + @Operation(summary = "Reset the segment topic's subscription cursor to the given timestamp." + " Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Cursor reset successfully"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 404, message = "Segment topic or subscription not found"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Cursor reset successfully"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "404", description = "Segment topic or subscription not found"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void seekSubscription( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Wall-clock millis since the unix epoch", required = true) + @Parameter(description = "Wall-clock millis since the unix epoch", required = true) @QueryParam("timestamp") long timestampMs, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -412,27 +413,27 @@ public void seekSubscription( @POST @Path("/{tenant}/{namespace}/{topic}/{descriptor}/subscription/{subscription}/skip-all") - @ApiOperation(value = "Skip every undelivered message on the segment topic's subscription —" + @Operation(summary = "Skip every undelivered message on the segment topic's subscription —" + " advance the cursor to the end. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Backlog cleared successfully"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 404, message = "Segment topic or subscription not found"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Backlog cleared successfully"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "404", description = "Segment topic or subscription not found"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void clearSubscriptionBacklog( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Subscription name", required = true) + @Parameter(description = "Subscription name", required = true) @PathParam("subscription") String subscription, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); @@ -467,25 +468,25 @@ public void clearSubscriptionBacklog( @DELETE @Path("/{tenant}/{namespace}/{topic}/{descriptor}") - @ApiOperation(value = "Delete a segment topic. Super-user only.") + @Operation(summary = "Delete a segment topic. Super-user only.") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Segment topic deleted successfully"), - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 403, message = "This operation requires super-user access"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "204", description = "Segment topic deleted successfully"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "403", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) public void deleteSegment( @Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify the parent topic name", required = true) + @Parameter(description = "Specify the parent topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Segment descriptor (e.g. 0000-7fff-1)", required = true) + @Parameter(description = "Segment descriptor (e.g. 0000-7fff-1)", required = true) @PathParam("descriptor") String descriptor, - @ApiParam(value = "Whether leader broker redirected this call to this broker.") + @Parameter(description = "Whether leader broker redirected this call to this broker.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @ApiParam(value = "Force deletion") + @Parameter(description = "Force deletion") @QueryParam("force") @DefaultValue("false") boolean force) { validateNamespaceName(tenant, namespace); TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Tenants.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Tenants.java index 6ebeb568e53d8..ab9653d6717fa 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Tenants.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Tenants.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -28,7 +28,6 @@ @Path("/tenants") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@Api(value = "/tenants", description = "Tenant admin apis", tags = "tenants") -@SuppressWarnings("deprecation") +@Tag(name = "tenants", description = "Tenant admin apis") public class Tenants extends TenantsBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Worker.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Worker.java index a4e473d07770e..725e0b9c67817 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Worker.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Worker.java @@ -18,9 +18,12 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.GET; import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; @@ -52,14 +55,15 @@ public WorkerService get() { } @GET - @ApiOperation( - value = "Fetches information about the Pulsar cluster running Pulsar Functions", - response = WorkerInfo.class, - responseContainer = "List" + @Operation( + summary = "Fetches information about the Pulsar cluster running Pulsar Functions" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Fetches information about the Pulsar cluster running Pulsar Functions", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = WorkerInfo.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/cluster") @Produces(MediaType.APPLICATION_JSON) @@ -68,13 +72,15 @@ public List getCluster() { } @GET - @ApiOperation( - value = "Fetches info about the leader node of the Pulsar cluster running Pulsar Functions", - response = WorkerInfo.class + @Operation( + summary = "Fetches info about the leader node of the Pulsar cluster running Pulsar Functions" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Fetches info about the leader node of the Pulsar cluster running Pulsar Functions", + content = @Content(schema = @Schema(implementation = WorkerInfo.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/cluster/leader") @Produces(MediaType.APPLICATION_JSON) @@ -83,15 +89,19 @@ public WorkerInfo getClusterLeader() { } @GET - @ApiOperation( - value = "Fetches information about which Pulsar Functions are assigned to which Pulsar clusters", - response = Map.class, - notes = "Returns a nested map structure which Swagger does not fully support for display." - + "Structure: Map>. Please refer to this structure for details." + @Operation( + summary = "Fetches information about which Pulsar Functions are assigned to which Pulsar clusters", + description = "Returns a map structure: Map>." ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Fetches information about which Pulsar Functions are assigned to which Pulsar " + + "clusters", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesArraySchema = @ArraySchema( + schema = @Schema(implementation = String.class), uniqueItems = true))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/assignments") @Produces(MediaType.APPLICATION_JSON) @@ -100,15 +110,18 @@ public Map> getAssignments() { } @GET - @ApiOperation( - value = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", - response = ConnectorDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", + description = "Fetches a list of supported Pulsar IO connectors currently running in cluster " + + "mode", + content = @Content(array = @ArraySchema(schema = + @Schema(implementation = ConnectorDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/connectors") @Produces(MediaType.APPLICATION_JSON) @@ -117,14 +130,14 @@ public List getConnectorsList() throws IOException { } @PUT - @ApiOperation( - value = "Triggers a rebalance of functions to workers" + @Operation( + summary = "Triggers a rebalance of functions to workers" ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/rebalance") public void rebalance() { @@ -132,16 +145,16 @@ public void rebalance() { } @PUT - @ApiOperation( - value = "Drains the specified worker, i.e., moves its work-assignments to other workers" + @Operation( + summary = "Drains the specified worker, i.e., moves its work-assignments to other workers" ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 409, message = "Drain already in progress"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "409", description = "Drain already in progress"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/leader/drain") public void drainAtLeader(@QueryParam("workerId") String workerId) { @@ -149,16 +162,16 @@ public void drainAtLeader(@QueryParam("workerId") String workerId) { } @PUT - @ApiOperation( - value = "Drains this worker, i.e., moves its work-assignments to other workers" + @Operation( + summary = "Drains this worker, i.e., moves its work-assignments to other workers" ) @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 409, message = "Drain already in progress"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "409", description = "Drain already in progress"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/drain") public void drain() { @@ -166,13 +179,15 @@ public void drain() { } @GET - @ApiOperation( - value = "Get the status of any ongoing drain operation at the specified worker", - response = LongRunningProcessStatus.class + @Operation( + summary = "Get the status of any ongoing drain operation at the specified worker" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "200", + description = "Get the status of any ongoing drain operation at the specified worker", + content = @Content(schema = @Schema(implementation = LongRunningProcessStatus.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/leader/drain") public LongRunningProcessStatus getDrainStatusFromLeader(@QueryParam("workerId") String workerId) { @@ -180,13 +195,15 @@ public LongRunningProcessStatus getDrainStatusFromLeader(@QueryParam("workerId") } @GET - @ApiOperation( - value = "Get the status of any ongoing drain operation at this worker", - response = LongRunningProcessStatus.class + @Operation( + summary = "Get the status of any ongoing drain operation at this worker" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "200", + description = "Get the status of any ongoing drain operation at this worker", + content = @Content(schema = @Schema(implementation = LongRunningProcessStatus.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/drain") public LongRunningProcessStatus getDrainStatus() { @@ -194,12 +211,14 @@ public LongRunningProcessStatus getDrainStatus() { } @GET - @ApiOperation( - value = "Checks if this node is the leader and is ready to service requests", - response = Boolean.class + @Operation( + summary = "Checks if this node is the leader and is ready to service requests" ) @ApiResponses(value = { - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Checks if this node is the leader and is ready to service requests", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/cluster/leader/ready") public Boolean isLeaderReady() { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java index 0433d05885c01..244749c2bc54d 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java @@ -18,9 +18,12 @@ */ package org.apache.pulsar.broker.admin.v2; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -43,14 +46,15 @@ public Workers workers() { @GET @Path("/metrics") - @ApiOperation( - value = "Gets the metrics for Monitoring", - notes = "Request should be executed by Monitoring agent on each worker to fetch the worker-metrics", - response = org.apache.pulsar.common.stats.Metrics.class, - responseContainer = "List") + @Operation( + summary = "Gets the metrics for Monitoring", + description = "Request should be executed by Monitoring agent on each worker to fetch the worker-metrics") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = org.apache.pulsar.common.stats.Metrics.class)))), + @ApiResponse(responseCode = "401", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Produces(MediaType.APPLICATION_JSON) public Collection getMetrics() throws Exception { @@ -59,14 +63,15 @@ public Collection getMetrics() throws Exception { @GET @Path("/functionsmetrics") - @ApiOperation( - value = "Get metrics for all functions owned by worker", - notes = "Requested should be executed by Monitoring agent on each worker to fetch the metrics", - response = WorkerFunctionInstanceStats.class, - responseContainer = "List") + @Operation( + summary = "Get metrics for all functions owned by worker", + description = "Requested should be executed by Monitoring agent on each worker to fetch the metrics") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", description = "Get metrics for all functions owned by worker", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = WorkerFunctionInstanceStats.class)))), + @ApiResponse(responseCode = "401", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Produces(MediaType.APPLICATION_JSON) public List getStats() throws IOException { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Functions.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Functions.java index 61d70f9e9f4a2..313bf0e004daf 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Functions.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Functions.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -26,9 +26,8 @@ import org.apache.pulsar.broker.admin.impl.FunctionsBase; @Path("/functions") -@Api(value = "/functions", description = "Functions admin apis", tags = "functions") +@Tag(name = "functions", description = "Functions admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class Functions extends FunctionsBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Packages.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Packages.java index b69e451389489..cda1650261d73 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Packages.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Packages.java @@ -18,10 +18,13 @@ */ package org.apache.pulsar.broker.admin.v3; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -42,24 +45,24 @@ import org.glassfish.jersey.media.multipart.FormDataParam; @Path("/packages") -@Api(value = "packages", tags = "packages") +@Tag(name = "packages") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class Packages extends PackagesBase { @GET @Path("/{type}/{tenant}/{namespace}/{packageName}/{version}/metadata") - @ApiOperation( - value = "Get the metadata of a package.", - response = PackageMetadata.class + @Operation( + summary = "Get the metadata of a package." ) @ApiResponses( value = { - @ApiResponse(code = 200, message = "Return the metadata of the specified package."), - @ApiResponse(code = 404, message = "The specified package is not existent."), - @ApiResponse(code = 412, message = "The package name is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "200", description = "Return the metadata of the specified package.", + content = @Content(schema = @Schema(implementation = PackageMetadata.class))), + @ApiResponse(responseCode = "404", description = "The specified package is not existent."), + @ApiResponse(responseCode = "412", description = "The package name is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) public void getMeta( @@ -75,16 +78,17 @@ public void getMeta( @PUT @Path("/{type}/{tenant}/{namespace}/{packageName}/{version}/metadata") - @ApiOperation( - value = "Update the metadata of a package." + @Operation( + summary = "Update the metadata of a package." ) @ApiResponses( value = { - @ApiResponse(code = 204, message = "Update the metadata of the specified package successfully."), - @ApiResponse(code = 404, message = "The specified package is not existent."), - @ApiResponse(code = 412, message = "The package name is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "204", description = "Update the metadata of the specified package " + + "successfully."), + @ApiResponse(responseCode = "404", description = "The specified package is not existent."), + @ApiResponse(responseCode = "412", description = "The package name is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) @Consumes(MediaType.APPLICATION_JSON) @@ -108,15 +112,15 @@ public void updateMeta( @POST @Path("/{type}/{tenant}/{namespace}/{packageName}/{version}") - @ApiOperation( - value = "Upload a package." + @Operation( + summary = "Upload a package." ) @ApiResponses( value = { - @ApiResponse(code = 204, message = "Upload the specified package successfully."), - @ApiResponse(code = 412, message = "The package name is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "204", description = "Upload the specified package successfully."), + @ApiResponse(responseCode = "412", description = "The package name is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -142,17 +146,18 @@ public void upload( @GET @Path("/{type}/{tenant}/{namespace}/{packageName}/{version}") - @ApiOperation( - value = "Download a package with the package name.", - response = StreamingOutput.class + @Operation( + summary = "Download a package with the package name." ) @ApiResponses( value = { - @ApiResponse(code = 200, message = "Download the specified package successfully."), - @ApiResponse(code = 404, message = "The specified package is not existent."), - @ApiResponse(code = 412, message = "The package name is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "200", description = "Download the specified package successfully.", + content = @Content(mediaType = "application/octet-stream", + schema = @Schema(type = "string", format = "binary"))), + @ApiResponse(responseCode = "404", description = "The specified package is not existent."), + @ApiResponse(responseCode = "412", description = "The package name is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) public StreamingOutput download( @@ -169,14 +174,14 @@ public StreamingOutput download( @Path("/{type}/{tenant}/{namespace}/{packageName}/{version}") @ApiResponses( value = { - @ApiResponse(code = 204, message = "Delete the specified package successfully."), - @ApiResponse(code = 404, message = "The specified package is not existent."), - @ApiResponse(code = 412, message = "The package name is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "204", description = "Delete the specified package successfully."), + @ApiResponse(responseCode = "404", description = "The specified package is not existent."), + @ApiResponse(responseCode = "412", description = "The package name is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) - @ApiOperation(value = "Delete a package with the package name.") + @Operation(summary = "Delete a package with the package name.") public void delete( final @PathParam("type") String type, final @PathParam("tenant") String tenant, @@ -190,18 +195,17 @@ public void delete( @GET @Path("/{type}/{tenant}/{namespace}/{packageName}") - @ApiOperation( - value = "Get all the versions of a package.", - response = String.class, - responseContainer = "List" + @Operation( + summary = "Get all the versions of a package." ) @ApiResponses( value = { - @ApiResponse(code = 200, message = "Return the package versions of the specified package."), - @ApiResponse(code = 404, message = "The specified package is not existent."), - @ApiResponse(code = 412, message = "The package name is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "200", description = "Return the package versions of the specified package.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "404", description = "The specified package is not existent."), + @ApiResponse(responseCode = "412", description = "The package name is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) public void listPackageVersion( @@ -216,18 +220,17 @@ public void listPackageVersion( @GET @Path("/{type}/{tenant}/{namespace}") - @ApiOperation( - value = "Get all the specified type packages in a namespace.", - response = PackageMetadata.class, - responseContainer = "List" + @Operation( + summary = "Get all the specified type packages in a namespace." ) @ApiResponses( value = { - @ApiResponse(code = 200, message = - "Return all the specified type package names in the specified namespace."), - @ApiResponse(code = 412, message = "The package type is illegal."), - @ApiResponse(code = 500, message = "Internal server error."), - @ApiResponse(code = 503, message = "Package Management Service is not enabled in the broker.") + @ApiResponse(responseCode = "200", description = + "Return all the specified type package names in the specified namespace.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = PackageMetadata.class)))), + @ApiResponse(responseCode = "412", description = "The package type is illegal."), + @ApiResponse(responseCode = "500", description = "Internal server error."), + @ApiResponse(responseCode = "503", description = "Package Management Service is not enabled in the broker.") } ) public void listPackages( diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sink.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sink.java index e5af5087dac6a..ff518fa326c87 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sink.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sink.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -26,7 +26,7 @@ import org.apache.pulsar.broker.admin.impl.SinksBase; @Path("/sink") -@Api(value = "/sink", description = "Sink admin apis", tags = "sink") +@Tag(name = "sink", description = "Sink admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Deprecated diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sinks.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sinks.java index 5beb33c6ffeae..3e13e31f3ba59 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sinks.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sinks.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -26,9 +26,8 @@ import org.apache.pulsar.broker.admin.impl.SinksBase; @Path("/sinks") -@Api(value = "/sinks", description = "Sinks admin apis", tags = "sinks") +@Tag(name = "sinks", description = "Sinks admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class Sinks extends SinksBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Source.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Source.java index 057696d693653..e156c6ce4187c 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Source.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Source.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -26,7 +26,7 @@ import org.apache.pulsar.broker.admin.impl.SourcesBase; @Path("/source") -@Api(value = "/source", description = "Source admin apis", tags = "source") +@Tag(name = "source", description = "Source admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Deprecated diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sources.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sources.java index 6b54331bd34c2..3481040e5def7 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sources.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Sources.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.broker.admin.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -26,9 +26,8 @@ import org.apache.pulsar.broker.admin.impl.SourcesBase; @Path("/sources") -@Api(value = "/sources", description = "Sources admin apis", tags = "sources") +@Tag(name = "sources", description = "Sources admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class Sources extends SourcesBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java index 31f87d3ae491a..687349fad1aa2 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java @@ -21,10 +21,13 @@ import static jakarta.ws.rs.core.Response.Status.METHOD_NOT_ALLOWED; import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; import static jakarta.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -60,16 +63,19 @@ @Path("/transactions") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@Api(value = "/transactions", description = "Transactions admin apis", tags = "transactions") +@Tag(name = "transactions", description = "Transactions admin apis") @SuppressWarnings("deprecation") public class Transactions extends TransactionsBase { @GET @Path("/coordinators") - @ApiOperation(value = "List transaction coordinators.", - response = TransactionCoordinatorInfo.class, responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "This Broker is not " + @Operation(summary = "List transaction coordinators.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "List transaction coordinators.", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = TransactionCoordinatorInfo.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "This Broker is not " + "configured with transactionCoordinatorEnabled=true.")}) public void listCoordinators(@Suspended final AsyncResponse asyncResponse) { checkTransactionCoordinatorEnabled(); @@ -78,12 +84,15 @@ public void listCoordinators(@Suspended final AsyncResponse asyncResponse) { @GET @Path("/coordinatorStats") - @ApiOperation(value = "Get transaction coordinator stats.", response = TransactionCoordinatorStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "This Broker is not " + @Operation(summary = "Get transaction coordinator stats.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction coordinator stats.", + content = @Content(schema = @Schema(implementation = TransactionCoordinatorStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "This Broker is not " + "configured with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 404, message = "Transaction coordinator not found"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "404", description = "Transaction coordinator not found"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getCoordinatorStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -94,14 +103,17 @@ public void getCoordinatorStats(@Suspended final AsyncResponse asyncResponse, @GET @Path("/transactionInBufferStats/{tenant}/{namespace}/{topic}/{mostSigBits}/{leastSigBits}") - @ApiOperation(value = "Get transaction state in transaction buffer.", response = TransactionInBufferStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @Operation(summary = "Get transaction state in transaction buffer.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction state in transaction buffer.", + content = @Content(schema = @Schema(implementation = TransactionInBufferStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getTransactionInBufferStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -133,14 +145,17 @@ public void getTransactionInBufferStats(@Suspended final AsyncResponse asyncResp @GET @Path("/transactionInPendingAckStats/{tenant}/{namespace}/{topic}/{subName}/{mostSigBits}/{leastSigBits}") - @ApiOperation(value = "Get transaction state in pending ack.", response = TransactionInPendingAckStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @Operation(summary = "Get transaction state in pending ack.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction state in pending ack.", + content = @Content(schema = @Schema(implementation = TransactionInPendingAckStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getTransactionInPendingAckStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -173,14 +188,17 @@ public void getTransactionInPendingAckStats(@Suspended final AsyncResponse async @GET @Path("/transactionBufferStats/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Get transaction buffer stats in topic.", response = TransactionBufferStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @Operation(summary = "Get transaction buffer stats in topic.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction buffer stats in topic.", + content = @Content(schema = @Schema(implementation = TransactionBufferStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getTransactionBufferStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -213,14 +231,18 @@ public void getTransactionBufferStats(@Suspended final AsyncResponse asyncRespon @GET @Path("/pendingAckStats/{tenant}/{namespace}/{topic}/{subName}") - @ApiOperation(value = "Get transaction pending ack stats in topic.", response = TransactionPendingAckStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic or subName doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @Operation(summary = "Get transaction pending ack stats in topic.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction pending ack stats in topic.", + content = @Content(schema = @Schema(implementation = TransactionPendingAckStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", + description = "Tenant or cluster or namespace or topic or subName doesn't exist"), + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPendingAckStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -251,15 +273,18 @@ public void getPendingAckStats(@Suspended final AsyncResponse asyncResponse, @GET @Path("/transactionMetadata/{mostSigBits}/{leastSigBits}") - @ApiOperation(value = "Get transaction metadata", response = TransactionMetadata.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic " + @Operation(summary = "Get transaction metadata") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction metadata", + content = @Content(schema = @Schema(implementation = TransactionMetadata.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic " + "or coordinator or transaction doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getTransactionMetadata(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -272,15 +297,19 @@ public void getTransactionMetadata(@Suspended final AsyncResponse asyncResponse, @GET @Path("/slowTransactions/{timeout}") - @ApiOperation(value = "Get slow transactions.", response = TransactionMetadata.class, responseContainer = "Map") - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic " + @Operation(summary = "Get slow transactions.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get slow transactions.", + content = @Content(schema = @Schema(type = "object", + additionalPropertiesSchema = TransactionMetadata.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic " + "or coordinator or transaction doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic don't owner by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic don't owner by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getSlowTransactions(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -292,13 +321,17 @@ public void getSlowTransactions(@Suspended final AsyncResponse asyncResponse, @GET @Path("/coordinatorInternalStats/{coordinatorId}") - @ApiOperation(value = "Get coordinator internal stats.", response = TransactionCoordinatorInternalStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "This Broker is not " + @Operation(summary = "Get coordinator internal stats.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get coordinator internal stats.", + content = @Content(schema = + @Schema(implementation = TransactionCoordinatorInternalStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "This Broker is not " + "configured with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 404, message = "Transaction coordinator not found"), - @ApiResponse(code = 405, message = "Broker don't use MLTransactionMetadataStore!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "404", description = "Transaction coordinator not found"), + @ApiResponse(responseCode = "405", description = "Broker don't use MLTransactionMetadataStore!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getCoordinatorInternalStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -310,17 +343,20 @@ public void getCoordinatorInternalStats(@Suspended final AsyncResponse asyncResp @GET @Path("/pendingAckInternalStats/{tenant}/{namespace}/{topic}/{subName}") - @ApiOperation(value = "Get transaction pending ack internal stats.", - response = TransactionPendingAckInternalStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic " + @Operation(summary = "Get transaction pending ack internal stats.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get transaction pending ack internal stats.", + content = @Content(schema = + @Schema(implementation = TransactionPendingAckInternalStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic " + "or subscription name doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 405, message = "Pending ack handle don't use managedLedger!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "405", description = "Pending ack handle don't use managedLedger!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPendingAckInternalStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -366,15 +402,18 @@ private Void resumeAsyncResponseWithBrokerException(@Suspended AsyncResponse asy @GET @Path("/transactionBufferInternalStats/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Get transaction buffer internal stats.", response = TransactionBufferInternalStats.class) + @Operation(summary = "Get transaction buffer internal stats.") @ApiResponses(value = { - @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not enable transaction"), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 405, message = "Transaction buffer don't use managedLedger!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification") + @ApiResponse(responseCode = "200", description = "Get transaction buffer internal stats.", + content = @Content(schema = + @Schema(implementation = TransactionBufferInternalStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), + @ApiResponse(responseCode = "503", description = "This Broker is not enable transaction"), + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "405", description = "Transaction buffer don't use managedLedger!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification") }) public void getTransactionBufferInternalStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @@ -404,12 +443,12 @@ public void getTransactionBufferInternalStats(@Suspended final AsyncResponse asy @POST @Path("/transactionCoordinator/replicas") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 406, message = "The number of replicas should be more than " + @ApiResponse(responseCode = "406", description = "The number of replicas should be more than " + "the current number of transaction coordinator replicas"), - @ApiResponse(code = 401, message = "This operation requires super-user access")}) + @ApiResponse(responseCode = "401", description = "This operation requires super-user access")}) public void scaleTransactionCoordinators(@Suspended final AsyncResponse asyncResponse, int replicas) { try { checkTransactionCoordinatorEnabled(); @@ -427,16 +466,19 @@ public void scaleTransactionCoordinators(@Suspended final AsyncResponse asyncRes @GET @Path("/positionStatsInPendingAck/{tenant}/{namespace}/{topic}/{subName}/{ledgerId}/{entryId}") - @ApiOperation(value = "Get position stats in pending ack.", response = PositionInPendingAckStats.class) - @ApiResponses(value = {@ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic " + @Operation(summary = "Get position stats in pending ack.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get position stats in pending ack.", + content = @Content(schema = @Schema(implementation = PositionInPendingAckStats.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic " + "or subscription name doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 405, message = "Pending ack handle don't use managedLedger!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "405", description = "Pending ack handle don't use managedLedger!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPositionStatsInPendingAck(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -471,17 +513,17 @@ public void getPositionStatsInPendingAck(@Suspended final AsyncResponse asyncRes @POST @Path("/abortTransaction/{mostSigBits}/{leastSigBits}") - @ApiOperation(value = "Abort transaction") + @Operation(summary = "Abort transaction") @ApiResponses(value = { - @ApiResponse(code = 204, message = "Operation successful"), - @ApiResponse(code = 404, message = "Tenant or cluster or namespace or topic " + @ApiResponse(responseCode = "204", description = "Operation successful"), + @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic " + "or coordinator or transaction doesn't exist"), - @ApiResponse(code = 503, message = "This Broker is not configured " + @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(code = 307, message = "Topic is not owned by this broker!"), - @ApiResponse(code = 400, message = "Topic is not a persistent topic!"), - @ApiResponse(code = 409, message = "Concurrent modification"), - @ApiResponse(code = 401, message = "This operation requires super-user access")}) + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), + @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), + @ApiResponse(responseCode = "409", description = "Concurrent modification"), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access")}) public void abortTransaction(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/lookup/v2/TopicLookup.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/lookup/v2/TopicLookup.java index 3d0269dee2173..8c7bb0f57138f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/lookup/v2/TopicLookup.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/lookup/v2/TopicLookup.java @@ -18,10 +18,12 @@ */ package org.apache.pulsar.broker.lookup.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; import jakarta.ws.rs.GET; @@ -39,7 +41,7 @@ import org.apache.pulsar.common.naming.TopicName; @Path("/v2/topic") -@Api(value = "lookup", tags = "lookup") +@Tag(name = "lookup") public class TopicLookup extends TopicLookupBase { static final String LISTENERNAME_HEADER = "X-Pulsar-ListenerName"; @@ -48,12 +50,14 @@ public class TopicLookup extends TopicLookupBase { @GET @Path("{topic-domain}/{tenant}/{namespace}/{topic}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Get the owner broker of the given topic.", - response = LookupData.class + @Operation( + summary = "Get the owner broker of the given topic." ) - @ApiResponses(value = { @ApiResponse(code = 307, - message = "Current broker doesn't serve the namespace of this topic") }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Get the owner broker of the given topic.", + content = @Content(schema = @Schema(implementation = LookupData.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this topic") }) public void lookupTopicAsync( @Suspended AsyncResponse asyncResponse, @PathParam("topic-domain") String topicDomain, @PathParam("tenant") String tenant, @@ -80,12 +84,15 @@ public void lookupTopicAsync( @GET @Path("{topic-domain}/{tenant}/{namespace}/{topic}/bundle") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation( - value = "Get the namespace bundle which the given topic belongs to.", - response = String.class + @Operation( + summary = "Get the namespace bundle which the given topic belongs to." ) - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 405, message = "Invalid topic domain type") }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Get the namespace bundle which the given topic belongs to.", + content = @Content(schema = @Schema(implementation = String.class))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "405", description = "Invalid topic domain type") }) public String getNamespaceBundle(@PathParam("topic-domain") String topicDomain, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java index 6c8f88d4ce477..27b594cf8f720 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java @@ -18,11 +18,14 @@ */ package org.apache.pulsar.broker.rest; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -39,23 +42,25 @@ @Path("/") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) -@Api(value = "/persistent", description = "Apis for produce,consume and ack message on topics.", tags = "topics") +@Tag(name = "topics", description = "Apis for produce,consume and ack message on topics.") @SuppressWarnings("deprecation") public class Topics extends TopicsBase { @POST @Path("/persistent/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Produce message to a persistent topic.", response = String.class, responseContainer = "List") + @Operation(summary = "Produce message to a persistent topic.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "200", description = "Produce message to a persistent topic.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnPersistentTopic(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, ProducerMessages producerMessages) { @@ -74,21 +79,22 @@ public void produceOnPersistentTopic(@Suspended final AsyncResponse asyncRespons @POST @Path("/persistent/{tenant}/{namespace}/{topic}/partitions/{partition}") - @ApiOperation(value = "Produce message to a partition of a persistent topic.", - response = String.class, responseContainer = "List") + @Operation(summary = "Produce message to a partition of a persistent topic.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "200", description = "Produce message to a partition of a persistent topic.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnPersistentTopicPartition(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Specify topic partition", required = true) + @Parameter(description = "Specify topic partition", required = true) @PathParam("partition") int partition, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, ProducerMessages producerMessages) { @@ -107,19 +113,20 @@ public void produceOnPersistentTopicPartition(@Suspended final AsyncResponse asy @POST @Path("/non-persistent/{tenant}/{namespace}/{topic}") - @ApiOperation(value = "Produce message to a non-persistent topic.", response = String.class, - responseContainer = "List") + @Operation(summary = "Produce message to a non-persistent topic.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "200", description = "Produce message to a non-persistent topic.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnNonPersistentTopic(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -139,21 +146,23 @@ public void produceOnNonPersistentTopic(@Suspended final AsyncResponse asyncResp @POST @Path("/non-persistent/{tenant}/{namespace}/{topic}/partitions/{partition}") - @ApiOperation(value = "Produce message to a partition of a non-persistent topic.", - response = String.class, responseContainer = "List") + @Operation(summary = "Produce message to a partition of a non-persistent topic.") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Client is not authorized to perform operation"), - @ApiResponse(code = 404, message = "tenant/namespace/topic doesn't exit"), - @ApiResponse(code = 412, message = "Namespace name is not valid"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "200", + description = "Produce message to a partition of a non-persistent topic.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), + @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnNonPersistentTopicPartition(@Suspended final AsyncResponse asyncResponse, - @ApiParam(value = "Specify the tenant", required = true) + @Parameter(description = "Specify the tenant", required = true) @PathParam("tenant") String tenant, - @ApiParam(value = "Specify the namespace", required = true) + @Parameter(description = "Specify the namespace", required = true) @PathParam("namespace") String namespace, - @ApiParam(value = "Specify topic name", required = true) + @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @ApiParam(value = "Specify topic partition", required = true) + @Parameter(description = "Specify topic partition", required = true) @PathParam("partition") int partition, @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/NoSwaggerDocumentation.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/NoSwaggerDocumentation.java deleted file mode 100644 index 0f5e8d832a2b4..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/NoSwaggerDocumentation.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.pulsar.broker.web; - -public @interface NoSwaggerDocumentation { - -} diff --git a/pulsar-broker/src/main/openapi/admin-v2.json b/pulsar-broker/src/main/openapi/admin-v2.json new file mode 100644 index 0000000000000..553f3cef497a4 --- /dev/null +++ b/pulsar-broker/src/main/openapi/admin-v2.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Admin REST API", + "description": "This provides the REST API for admin operations", + "version": "v2", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/admin/v2" + } + ] +} diff --git a/pulsar-broker/src/main/openapi/functions-v3.json b/pulsar-broker/src/main/openapi/functions-v3.json new file mode 100644 index 0000000000000..90dc4f1854d32 --- /dev/null +++ b/pulsar-broker/src/main/openapi/functions-v3.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Functions REST API", + "description": "This provides the REST API for Pulsar Functions operations", + "version": "v3", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/admin/v3" + } + ] +} diff --git a/pulsar-broker/src/main/openapi/lookup-v2.json b/pulsar-broker/src/main/openapi/lookup-v2.json new file mode 100644 index 0000000000000..729c1975c3b89 --- /dev/null +++ b/pulsar-broker/src/main/openapi/lookup-v2.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Lookup REST API", + "description": "This provides the REST API for lookup operations", + "version": "v2", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/lookup" + } + ] +} diff --git a/pulsar-broker/src/main/openapi/packages-v3.json b/pulsar-broker/src/main/openapi/packages-v3.json new file mode 100644 index 0000000000000..d438d86f17625 --- /dev/null +++ b/pulsar-broker/src/main/openapi/packages-v3.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Packages REST API", + "description": "This provides the REST API for Pulsar Packages operations", + "version": "v3", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/admin/v3" + } + ] +} diff --git a/pulsar-broker/src/main/openapi/sink-v3.json b/pulsar-broker/src/main/openapi/sink-v3.json new file mode 100644 index 0000000000000..d607dd1842723 --- /dev/null +++ b/pulsar-broker/src/main/openapi/sink-v3.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Sink REST API", + "description": "This provides the REST API for Pulsar Sink operations", + "version": "v3", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/admin/v3" + } + ] +} diff --git a/pulsar-broker/src/main/openapi/source-v3.json b/pulsar-broker/src/main/openapi/source-v3.json new file mode 100644 index 0000000000000..0e4071e27e807 --- /dev/null +++ b/pulsar-broker/src/main/openapi/source-v3.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Source REST API", + "description": "This provides the REST API for Pulsar Source operations", + "version": "v3", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/admin/v3" + } + ] +} diff --git a/pulsar-broker/src/main/openapi/transactions-v3.json b/pulsar-broker/src/main/openapi/transactions-v3.json new file mode 100644 index 0000000000000..7c032ad9a8271 --- /dev/null +++ b/pulsar-broker/src/main/openapi/transactions-v3.json @@ -0,0 +1,16 @@ +{ + "info": { + "title": "Pulsar Transactions REST API", + "description": "This provides the REST API for Pulsar Transactions operations", + "version": "v3", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "/admin/v3" + } + ] +} diff --git a/pulsar-client-tools/build.gradle.kts b/pulsar-client-tools/build.gradle.kts index f2555cb9d1457..6db5482e94229 100644 --- a/pulsar-client-tools/build.gradle.kts +++ b/pulsar-client-tools/build.gradle.kts @@ -40,6 +40,8 @@ dependencies { implementation(libs.jline) implementation(libs.commons.io) implementation(libs.commons.lang3) + // guava was previously leaked onto the compile classpath via compileOnly(swagger-core 1.x) + implementation(libs.guava) implementation(libs.commons.text) implementation(libs.asynchttpclient) implementation(libs.netty.reactive.streams) @@ -51,10 +53,9 @@ dependencies { implementation(libs.jetty.websocket.jetty.client) runtimeOnly(libs.jna) - compileOnly(libs.swagger.core) + compileOnly(libs.swagger.annotations) testImplementation(libs.jackson.dataformat.yaml) - testImplementation(libs.guava) } // Maven uses ant-plugin to copy pom.xml -> dummy.nar for TestCmdSinks/TestCmdSources. diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java index 73e5eb2e36870..bc0106c367db2 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.opentelemetry.api.OpenTelemetry; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.net.InetSocketAddress; import java.net.URI; @@ -58,379 +58,380 @@ public class ClientConfigurationData implements Serializable, Cloneable { private static final long serialVersionUID = 1L; - @ApiModelProperty( + @Schema( name = "serviceUrl", - required = true, - value = "Pulsar cluster HTTP URL to connect to a broker." + requiredMode = Schema.RequiredMode.REQUIRED, + description = "Pulsar cluster HTTP URL to connect to a broker." ) private String serviceUrl; - @ApiModelProperty( + @Schema( name = "serviceUrlProvider", - value = "The implementation class of ServiceUrlProvider used to generate ServiceUrl." + description = "The implementation class of ServiceUrlProvider used to generate ServiceUrl." ) @JsonIgnore private transient ServiceUrlProvider serviceUrlProvider; - @ApiModelProperty( + @Schema( name = "serviceUrlQuarantineInitDurationMs", - value = "The initial duration (in milliseconds) to quarantine endpoints that fail to connect." + description = "The initial duration (in milliseconds) to quarantine endpoints that fail to connect." + "A value of 0 means don't quarantine any endpoints even if they fail." ) private long serviceUrlQuarantineInitDurationMs = 60000; - @ApiModelProperty( + @Schema( name = "serviceUrlQuarantineMaxDurationMs", - value = "The max duration (in milliseconds) to quarantine endpoints that fail to connect." + description = "The max duration (in milliseconds) to quarantine endpoints that fail to connect." + "A value of 0 means don't quarantine any endpoints even if they fail." ) private long serviceUrlQuarantineMaxDurationMs = TimeUnit.DAYS.toMillis(1); - @ApiModelProperty( + @Schema( name = "authentication", - value = "Authentication settings of the client." + description = "Authentication settings of the client." ) @JsonIgnore private Authentication authentication; - @ApiModelProperty( + @Schema( name = "authPluginClassName", - value = "Class name of authentication plugin of the client." + description = "Class name of authentication plugin of the client." ) private String authPluginClassName; - @ApiModelProperty( + @Schema( name = "authParams", - value = "Authentication parameter of the client." + description = "Authentication parameter of the client." ) @Secret private String authParams; - @ApiModelProperty( + @Schema( name = "authParamMap", - value = "Authentication map of the client." + description = "Authentication map of the client." ) @Secret private Map authParamMap; - @ApiModelProperty( + @Schema( name = "originalPrincipal", - value = "Original principal for proxy authentication scenarios." + description = "Original principal for proxy authentication scenarios." ) private String originalPrincipal; - @ApiModelProperty( + @Schema( name = "operationTimeoutMs", - value = "Client operation timeout (in milliseconds)." + description = "Client operation timeout (in milliseconds)." ) private long operationTimeoutMs = 30000; - @ApiModelProperty( + @Schema( name = "lookupTimeoutMs", - value = "Client lookup timeout (in milliseconds)." + description = "Client lookup timeout (in milliseconds)." ) private long lookupTimeoutMs = -1; - @ApiModelProperty( + @Schema( name = "statsIntervalSeconds", - value = "Interval to print client stats (in seconds)." + description = "Interval to print client stats (in seconds)." ) private long statsIntervalSeconds = 60; - @ApiModelProperty( + @Schema( name = "numIoThreads", - value = "Number of IO threads." + description = "Number of IO threads." ) private int numIoThreads = Runtime.getRuntime().availableProcessors(); - @ApiModelProperty( + @Schema( name = "numListenerThreads", - value = "Number of consumer listener threads." + description = "Number of consumer listener threads." ) private int numListenerThreads = Runtime.getRuntime().availableProcessors(); - @ApiModelProperty( + @Schema( name = "connectionsPerBroker", - value = "Number of connections established between the client and each Broker." + description = "Number of connections established between the client and each Broker." + " A value of 0 means to disable connection pooling." ) private int connectionsPerBroker = 1; - @ApiModelProperty( + @Schema( name = "connectionMaxIdleSeconds", - value = "Release the connection if it is not used for more than [connectionMaxIdleSeconds] seconds. " + description = "Release the connection if it is not used for more than [connectionMaxIdleSeconds] seconds. " + "If [connectionMaxIdleSeconds] < 0, disabled the feature that auto release the idle connections" ) private int connectionMaxIdleSeconds = 60; - @ApiModelProperty( + @Schema( name = "useTcpNoDelay", - value = "Whether to use TCP NoDelay option." + description = "Whether to use TCP NoDelay option." ) private boolean useTcpNoDelay = true; - @ApiModelProperty( + @Schema( name = "useTls", - value = "Whether to use TLS." + description = "Whether to use TLS." ) private boolean useTls = false; - @ApiModelProperty( + @Schema( name = "tlsKeyFilePath", - value = "Path to the TLS key file." + description = "Path to the TLS key file." ) private String tlsKeyFilePath = null; - @ApiModelProperty( + @Schema( name = "tlsCertificateFilePath", - value = "Path to the TLS certificate file." + description = "Path to the TLS certificate file." ) private String tlsCertificateFilePath = null; - @ApiModelProperty( + @Schema( name = "tlsTrustCertsFilePath", - value = "Path to the trusted TLS certificate file." + description = "Path to the trusted TLS certificate file." ) private String tlsTrustCertsFilePath = null; - @ApiModelProperty( + @Schema( name = "tlsAllowInsecureConnection", - value = "Whether the client accepts untrusted TLS certificates from the broker." + description = "Whether the client accepts untrusted TLS certificates from the broker." ) private boolean tlsAllowInsecureConnection = false; - @ApiModelProperty( + @Schema( name = "tlsHostnameVerificationEnable", - value = "Whether the hostname is validated when the client creates a TLS connection with brokers." + description = "Whether the hostname is validated when the client creates a TLS connection with brokers." ) private boolean tlsHostnameVerificationEnable = false; - @ApiModelProperty( + @Schema( name = "sslFactoryPlugin", - value = "SSL Factory Plugin class to provide SSLEngine and SSLContext objects. The default " + description = "SSL Factory Plugin class to provide SSLEngine and SSLContext objects. The default " + " class used is DefaultPulsarSslFactory.") private String sslFactoryPlugin = DefaultPulsarSslFactory.class.getName(); - @ApiModelProperty( + @Schema( name = "sslFactoryPluginParams", - value = "SSL Factory plugin configuration parameters.") + description = "SSL Factory plugin configuration parameters.") private String sslFactoryPluginParams = ""; - @ApiModelProperty( + @Schema( name = "concurrentLookupRequest", - value = "The number of concurrent lookup requests that can be sent on each broker connection. " + description = "The number of concurrent lookup requests that can be sent on each broker connection. " + "Setting a maximum prevents overloading a broker." ) private int concurrentLookupRequest = 5000; - @ApiModelProperty( + @Schema( name = "maxLookupRequest", - value = "Maximum number of lookup requests allowed on " + description = "Maximum number of lookup requests allowed on " + "each broker connection to prevent overloading a broker." ) private int maxLookupRequest = 50000; - @ApiModelProperty( + @Schema( name = "maxLookupRedirects", - value = "Maximum times of redirected lookup requests." + description = "Maximum times of redirected lookup requests." ) private int maxLookupRedirects = 20; - @ApiModelProperty( + @Schema( name = "maxNumberOfRejectedRequestPerConnection", - value = "Maximum number of rejected requests of a broker in a certain time frame (60 seconds) " + description = "Maximum number of rejected requests of a broker in a certain time frame (60 seconds) " + "after the current connection is closed and the client " + "creating a new connection to connect to a different broker." ) private int maxNumberOfRejectedRequestPerConnection = 50; - @ApiModelProperty( + @Schema( name = "keepAliveIntervalSeconds", - value = "Seconds of keeping alive interval for each client broker connection." + description = "Seconds of keeping alive interval for each client broker connection." ) private int keepAliveIntervalSeconds = 30; - @ApiModelProperty( + @Schema( name = "connectionTimeoutMs", - value = "Duration of waiting for a connection to a broker to be established." + description = "Duration of waiting for a connection to a broker to be established." + "If the duration passes without a response from a broker, the connection attempt is dropped." ) private int connectionTimeoutMs = 10000; - @ApiModelProperty( + @Schema( name = "requestTimeoutMs", - value = "Maximum duration for completing a request." + description = "Maximum duration for completing a request." ) private int requestTimeoutMs = 60000; - @ApiModelProperty( + @Schema( name = "readTimeoutMs", - value = "Maximum read time of a request." + description = "Maximum read time of a request." ) private int readTimeoutMs = 60000; - @ApiModelProperty( + @Schema( name = "autoCertRefreshSeconds", - value = "Seconds of auto refreshing certificate." + description = "Seconds of auto refreshing certificate." ) private int autoCertRefreshSeconds = 300; - @ApiModelProperty( + @Schema( name = "initialBackoffIntervalNanos", - value = "Initial backoff interval (in nanosecond)." + description = "Initial backoff interval (in nanosecond)." ) private long initialBackoffIntervalNanos = TimeUnit.MILLISECONDS.toNanos(100); - @ApiModelProperty( + @Schema( name = "maxBackoffIntervalNanos", - value = "Max backoff interval (in nanosecond)." + description = "Max backoff interval (in nanosecond)." ) private long maxBackoffIntervalNanos = TimeUnit.SECONDS.toNanos(60); - @ApiModelProperty( + @Schema( name = "enableBusyWait", - value = "Whether to enable BusyWait for EpollEventLoopGroup." + description = "Whether to enable BusyWait for EpollEventLoopGroup." ) private boolean enableBusyWait = false; - @ApiModelProperty( + @Schema( name = "listenerName", - value = "Listener name for lookup. Clients can use listenerName to choose one of the listeners " + description = "Listener name for lookup. Clients can use listenerName to choose one of the listeners " + "as the service URL to create a connection to the broker as long as the network is accessible." + "\"advertisedListeners\" must enabled in broker side." ) private String listenerName; - @ApiModelProperty( + @Schema( name = "useKeyStoreTls", - value = "Set TLS using KeyStore way." + description = "Set TLS using KeyStore way." ) private boolean useKeyStoreTls = false; - @ApiModelProperty( + @Schema( name = "sslProvider", - value = "The TLS provider used by an internal client to authenticate with other Pulsar brokers." + description = "The TLS provider used by an internal client to authenticate with other Pulsar brokers." ) private String sslProvider = null; - @ApiModelProperty( + @Schema( name = "tlsKeyStoreType", - value = "TLS KeyStore type configuration." + description = "TLS KeyStore type configuration." ) private String tlsKeyStoreType = "JKS"; - @ApiModelProperty( + @Schema( name = "tlsKeyStorePath", - value = "Path of TLS KeyStore." + description = "Path of TLS KeyStore." ) private String tlsKeyStorePath = null; - @ApiModelProperty( + @Schema( name = "tlsKeyStorePassword", - value = "Password of TLS KeyStore." + description = "Password of TLS KeyStore." ) @Secret private String tlsKeyStorePassword = null; - @ApiModelProperty( + @Schema( name = "tlsTrustStoreType", - value = "TLS TrustStore type configuration. You need to set this configuration when client authentication" - + " is required." + description = "TLS TrustStore type configuration. You need to set this configuration when client " + + "authentication is required." ) private String tlsTrustStoreType = "JKS"; - @ApiModelProperty( + @Schema( name = "tlsTrustStorePath", - value = "Path of TLS TrustStore." + description = "Path of TLS TrustStore." ) private String tlsTrustStorePath = null; - @ApiModelProperty( + @Schema( name = "tlsTrustStorePassword", - value = "Password of TLS TrustStore." + description = "Password of TLS TrustStore." ) @Secret private String tlsTrustStorePassword = null; - @ApiModelProperty( + @Schema( name = "tlsCiphers", - value = "Set of TLS Ciphers." + description = "Set of TLS Ciphers." ) private Set tlsCiphers = new TreeSet<>(); - @ApiModelProperty( + @Schema( name = "tlsProtocols", - value = "Protocols of TLS." + description = "Protocols of TLS." ) private Set tlsProtocols = new TreeSet<>(); - @ApiModelProperty( + @Schema( name = "memoryLimitBytes", - value = "Limit of client memory usage (in byte). The 64M default can guarantee a high producer throughput." + description = "Limit of client memory usage (in byte). The 64M default can guarantee a high producer " + + "throughput." ) private long memoryLimitBytes = 64 * 1024 * 1024; - @ApiModelProperty( + @Schema( name = "proxyServiceUrl", - value = "URL of proxy service. proxyServiceUrl and proxyProtocol must be mutually inclusive." + description = "URL of proxy service. proxyServiceUrl and proxyProtocol must be mutually inclusive." ) private String proxyServiceUrl; - @ApiModelProperty( + @Schema( name = "proxyProtocol", - value = "Protocol of proxy service. proxyServiceUrl and proxyProtocol must be mutually inclusive." + description = "Protocol of proxy service. proxyServiceUrl and proxyProtocol must be mutually inclusive." ) private ProxyProtocol proxyProtocol; - @ApiModelProperty( + @Schema( name = "enableTransaction", - value = "Whether to enable transaction." + description = "Whether to enable transaction." ) private boolean enableTransaction = false; @JsonIgnore private Clock clock = Clock.systemDefaultZone(); - @ApiModelProperty( + @Schema( name = "dnsLookupBindAddress", - value = "The Pulsar client dns lookup bind address, default behavior is bind on 0.0.0.0" + description = "The Pulsar client dns lookup bind address, default behavior is bind on 0.0.0.0" ) private String dnsLookupBindAddress = null; - @ApiModelProperty( + @Schema( name = "dnsLookupBindPort", - value = "The Pulsar client dns lookup bind port, takes effect when dnsLookupBindAddress is configured," - + " default value is 0." + description = "The Pulsar client dns lookup bind port, takes effect when dnsLookupBindAddress is " + + "configured, default value is 0." ) private int dnsLookupBindPort = 0; - @ApiModelProperty( + @Schema( name = "dnsServerAddresses", - value = "The Pulsar client dns lookup server address" + description = "The Pulsar client dns lookup server address" ) @SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}) private List dnsServerAddresses = new ArrayList<>(); // socks5 - @ApiModelProperty( + @Schema( name = "socks5ProxyAddress", - value = "Address of SOCKS5 proxy." + description = "Address of SOCKS5 proxy." ) private InetSocketAddress socks5ProxyAddress; - @ApiModelProperty( + @Schema( name = "socks5ProxyUsername", - value = "User name of SOCKS5 proxy." + description = "User name of SOCKS5 proxy." ) private String socks5ProxyUsername; - @ApiModelProperty( + @Schema( name = "socks5ProxyPassword", - value = "Password of SOCKS5 proxy." + description = "Password of SOCKS5 proxy." ) @Secret private String socks5ProxyPassword; - @ApiModelProperty( + @Schema( name = "socks5ProxyScope", - value = "Selector that controls which connections go through the SOCKS5 proxy. " + description = "Selector that controls which connections go through the SOCKS5 proxy. " + "BINARY_ONLY (default for PulsarClient) only routes Pulsar binary protocol connections; " + "HTTP_ONLY only routes HTTP/HTTPS traffic (HTTP lookups, failover HTTP clients, admin REST); " + "BOTH routes both. This preserves backward compatibility with the pre-existing behavior " @@ -438,9 +439,9 @@ public class ClientConfigurationData implements Serializable, Cloneable { ) private Socks5ProxyScope socks5ProxyScope = Socks5ProxyScope.BINARY_ONLY; - @ApiModelProperty( + @Schema( name = "description", - value = "The extra description of the client version. The length cannot exceed 64." + description = "The extra description of the client version. The length cannot exceed 64." ) private String description; @@ -448,9 +449,9 @@ public class ClientConfigurationData implements Serializable, Cloneable { private transient OpenTelemetry openTelemetry; - @ApiModelProperty( + @Schema( name = "tracingEnabled", - value = "Whether to enable OpenTelemetry distributed tracing. When enabled, " + description = "Whether to enable OpenTelemetry distributed tracing. When enabled, " + "tracing interceptors are automatically added to producers and consumers." ) private boolean tracingEnabled = false; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java index fef97a2459557..a29ebcf01ab2c 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.Sets; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -59,28 +59,28 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { private static final long serialVersionUID = 1L; - @ApiModelProperty( + @Schema( name = "topicNames", - required = true, - value = "Topic name" + requiredMode = Schema.RequiredMode.REQUIRED, + description = "Topic name" ) private Set topicNames = new TreeSet<>(); - @ApiModelProperty( + @Schema( name = "topicsPattern", - value = "The regexp for the topic name(not contains partition suffix)." + description = "The regexp for the topic name(not contains partition suffix)." ) private Pattern topicsPattern; - @ApiModelProperty( + @Schema( name = "subscriptionName", - value = "Subscription name" + description = "Subscription name" ) private String subscriptionName; - @ApiModelProperty( + @Schema( name = "subscriptionType", - value = "Subscription type.\n" + description = "Subscription type.\n" + "Four subscription types are available:\n" + "* Exclusive\n" + "* Failover\n" @@ -104,25 +104,25 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { @JsonIgnore private ConsumerEventListener consumerEventListener; - @ApiModelProperty( + @Schema( name = "negativeAckRedeliveryBackoff", - value = "Interface for custom message is negativeAcked policy. You can specify `RedeliveryBackoff` for a" - + " consumer." + description = "Interface for custom message is negativeAcked policy. You can specify `RedeliveryBackoff`" + + " for a consumer." ) @JsonIgnore private RedeliveryBackoff negativeAckRedeliveryBackoff; - @ApiModelProperty( + @Schema( name = "ackTimeoutRedeliveryBackoff", - value = "Interface for custom message is ackTimeout policy. You can specify `RedeliveryBackoff` for a" - + " consumer." + description = "Interface for custom message is ackTimeout policy. You can specify `RedeliveryBackoff`" + + " for a consumer." ) @JsonIgnore private RedeliveryBackoff ackTimeoutRedeliveryBackoff; - @ApiModelProperty( + @Schema( name = "receiverQueueSize", - value = "Size of a consumer's receiver queue.\n" + description = "Size of a consumer's receiver queue.\n" + "\n" + "For example, the number of messages accumulated by a consumer before an application calls " + "`Receive`.\n" @@ -132,9 +132,9 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { ) private int receiverQueueSize = 1000; - @ApiModelProperty( + @Schema( name = "acknowledgementsGroupTimeMicros", - value = "Group a consumer acknowledgment for a specified time.\n" + description = "Group a consumer acknowledgment for a specified time.\n" + "\n" + "By default, a consumer uses 100ms grouping time to send out acknowledgments to a broker.\n" + "\n" @@ -145,24 +145,24 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { ) private long acknowledgementsGroupTimeMicros = TimeUnit.MILLISECONDS.toMicros(100); - @ApiModelProperty( + @Schema( name = "maxAcknowledgmentGroupSize", - value = "Group a consumer acknowledgment for the number of messages." + description = "Group a consumer acknowledgment for the number of messages." ) private int maxAcknowledgmentGroupSize = 1000; - @ApiModelProperty( + @Schema( name = "negativeAckRedeliveryDelayMicros", - value = "Delay to wait before redelivering messages that failed to be processed.\n" + description = "Delay to wait before redelivering messages that failed to be processed.\n" + "\n" + "When an application uses {@link Consumer#negativeAcknowledge(Message)}, failed messages are " + "redelivered after a fixed timeout." ) private long negativeAckRedeliveryDelayMicros = TimeUnit.MINUTES.toMicros(1); - @ApiModelProperty( + @Schema( name = "negativeAckPrecisionBitCnt", - value = "The redelivery time precision bit count. The lower bits of the redelivery time will be" + description = "The redelivery time precision bit count. The lower bits of the redelivery time will be" + "trimmed to reduce the memory occupation.\nThe default value is 8, which means the" + "redelivery time will be bucketed by 256ms, the redelivery time could be earlier(no later)" + "than the expected time, but no more than 256ms. \nIf set to k, the redelivery time will be" @@ -170,40 +170,40 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { ) private int negativeAckPrecisionBitCnt = 8; - @ApiModelProperty( + @Schema( name = "maxTotalReceiverQueueSizeAcrossPartitions", - value = "The max total receiver queue size across partitions.\n" + description = "The max total receiver queue size across partitions.\n" + "\n" + "This setting reduces the receiver queue size for individual partitions if the total receiver " + "queue size exceeds this value." ) private int maxTotalReceiverQueueSizeAcrossPartitions = 50000; - @ApiModelProperty( + @Schema( name = "consumerName", - value = "Consumer name" + description = "Consumer name" ) private String consumerName = null; - @ApiModelProperty( + @Schema( name = "ackTimeoutMillis", - value = "Timeout of unacked messages" + description = "Timeout of unacked messages" ) private long ackTimeoutMillis = 0; - @ApiModelProperty( + @Schema( name = "tickDurationMillis", - value = "Granularity of the ack-timeout redelivery.\n" + description = "Granularity of the ack-timeout redelivery.\n" + "\n" + "Using an higher `tickDurationMillis` reduces the memory overhead to track messages when setting " + "ack-timeout to a bigger value (for example, 1 hour)." ) private long tickDurationMillis = 1000; - @ApiModelProperty( + @Schema( name = "priorityLevel", - value = "Priority level for a consumer to which a broker gives more priority while dispatching messages " - + "in Shared subscription type.\n" + description = "Priority level for a consumer to which a broker gives more priority while dispatching " + + "messages in Shared subscription type.\n" + "\n" + "The broker follows descending priorities. For example, 0=max-priority, 1, 2,...\n" + "\n" @@ -243,26 +243,26 @@ public int getMaxPendingChuckedMessage() { return maxPendingChunkedMessage; } - @ApiModelProperty( + @Schema( name = "maxPendingChunkedMessage", - value = "The maximum size of a queue holding pending chunked messages. When the threshold is reached," + description = "The maximum size of a queue holding pending chunked messages. When the threshold is reached," + " the consumer drops pending messages to optimize memory utilization." ) // max pending chunked message to avoid sending incomplete message into the queue and memory private int maxPendingChunkedMessage = 10; - @ApiModelProperty( + @Schema( name = "autoAckOldestChunkedMessageOnQueueFull", - value = "Whether to automatically acknowledge pending chunked messages when the threshold of" + description = "Whether to automatically acknowledge pending chunked messages when the threshold of" + " `maxPendingChunkedMessage` is reached. If set to `false`, these messages will be redelivered" + " by their broker." ) private boolean autoAckOldestChunkedMessageOnQueueFull = false; - @ApiModelProperty( + @Schema( name = "expireTimeOfIncompleteChunkedMessageMillis", - value = "The time interval to expire incomplete chunks if a consumer fails to receive all the chunks in the" - + " specified time period. The default value is 1 minute." + description = "The time interval to expire incomplete chunks if a consumer fails to receive all the chunks" + + " in the specified time period. The default value is 1 minute." ) private long expireTimeOfIncompleteChunkedMessageMillis = TimeUnit.MINUTES.toMillis(1); @@ -272,9 +272,9 @@ public int getMaxPendingChuckedMessage() { @JsonIgnore private transient MessageCrypto messageCrypto = null; - @ApiModelProperty( + @Schema( name = "cryptoFailureAction", - value = "Consumer should take action when it receives a message that can not be decrypted.\n" + description = "Consumer should take action when it receives a message that can not be decrypted.\n" + "* **FAIL**: this is the default option to fail messages until crypto succeeds.\n" + "* **DISCARD**:silently acknowledge and not deliver message to an application.\n" + "* **CONSUME**: deliver encrypted messages to applications. It is the application's" @@ -290,9 +290,9 @@ public int getMaxPendingChuckedMessage() { ) private ConsumerCryptoFailureAction cryptoFailureAction; - @ApiModelProperty( + @Schema( name = "properties", - value = "A name or value property of this consumer.\n" + description = "A name or value property of this consumer.\n" + "\n" + "`properties` is application defined metadata attached to a consumer.\n" + "\n" @@ -301,10 +301,10 @@ public int getMaxPendingChuckedMessage() { ) private SortedMap properties = new TreeMap<>(); - @ApiModelProperty( + @Schema( name = "readCompacted", - value = "If enabling `readCompacted`, a consumer reads messages from a compacted topic rather than reading " - + "a full message backlog of a topic.\n" + description = "If enabling `readCompacted`, a consumer reads messages from a compacted topic rather than " + + "reading a full message backlog of a topic.\n" + "\n" + "A consumer only sees the latest value for each key in the compacted topic, up until reaching " + "the point in the topic message when compacting backlog. Beyond that point, send messages as " @@ -318,23 +318,24 @@ public int getMaxPendingChuckedMessage() { ) private boolean readCompacted = false; - @ApiModelProperty( + @Schema( name = "subscriptionInitialPosition", - value = "Initial position at which to set cursor when subscribing to a topic at first time." + description = "Initial position at which to set cursor when subscribing to a topic at first time." ) private SubscriptionInitialPosition subscriptionInitialPosition = SubscriptionInitialPosition.Latest; - @ApiModelProperty( + @Schema( name = "patternAutoDiscoveryPeriod", - value = "Topic auto discovery period when using a pattern for topic's consumer.\n" + description = "Topic auto discovery period when using a pattern for topic's consumer.\n" + "\n" + "The default value is 1 minute, with a minimum of 1 second." ) private int patternAutoDiscoveryPeriod = 60; - @ApiModelProperty( + @Schema( name = "regexSubscriptionMode", - value = "When subscribing to a topic using a regular expression, you can pick a certain type of topics.\n" + description = "When subscribing to a topic using a regular expression, you can pick a certain type " + + "of topics.\n" + "\n" + "* **PersistentOnly**: only subscribe to persistent topics.\n" + "* **NonPersistentOnly**: only subscribe to non-persistent topics.\n" @@ -342,9 +343,9 @@ public int getMaxPendingChuckedMessage() { ) private RegexSubscriptionMode regexSubscriptionMode = RegexSubscriptionMode.PersistentOnly; - @ApiModelProperty( + @Schema( name = "deadLetterPolicy", - value = "Dead letter policy for consumers.\n" + description = "Dead letter policy for consumers.\n" + "\n" + "By default, some messages are probably redelivered many times, even to the extent that it " + "never stops.\n" @@ -380,9 +381,9 @@ public int getMaxPendingChuckedMessage() { @JsonIgnore private BatchReceivePolicy batchReceivePolicy; - @ApiModelProperty( + @Schema( name = "autoUpdatePartitions", - value = "If `autoUpdatePartitions` is enabled, a consumer subscribes to partition increasement " + description = "If `autoUpdatePartitions` is enabled, a consumer subscribes to partition increasement " + "automatically.\n" + "\n" + "**Note**: this is only for partitioned consumers." @@ -391,10 +392,10 @@ public int getMaxPendingChuckedMessage() { private long autoUpdatePartitionsIntervalSeconds = 60; - @ApiModelProperty( + @Schema( name = "replicateSubscriptionState", - value = "If `replicateSubscriptionState` is enabled, a subscription state is replicated to geo-replicated" - + " clusters." + description = "If `replicateSubscriptionState` is enabled, a subscription state is replicated to" + + " geo-replicated clusters." ) @JsonProperty(access = JsonProperty.Access.READ_WRITE) private Boolean replicateSubscriptionState; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java index d65d53b70c069..013eae7f916d6 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Sets; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Set; import java.util.SortedMap; @@ -55,29 +55,29 @@ public class ProducerConfigurationData implements Serializable, Cloneable { public static final int DEFAULT_MAX_PENDING_MESSAGES = 0; public static final int DEFAULT_MAX_PENDING_MESSAGES_ACROSS_PARTITIONS = 0; - @ApiModelProperty( + @Schema( name = "topicName", - required = true, - value = "Topic name" + requiredMode = Schema.RequiredMode.REQUIRED, + description = "Topic name" ) private String topicName = null; - @ApiModelProperty( + @Schema( name = "producerName", - value = "Producer name" + description = "Producer name" ) private String producerName = null; - @ApiModelProperty( + @Schema( name = "sendTimeoutMs", - value = "Message send timeout in ms.\n" + description = "Message send timeout in ms.\n" + "If a message is not acknowledged by a server before the `sendTimeout` expires, an error occurs." ) private long sendTimeoutMs = 30000; - @ApiModelProperty( + @Schema( name = "blockIfQueueFull", - value = "If it is set to `true`, when the outgoing message queue is full, the `Send` and `SendAsync`" + description = "If it is set to `true`, when the outgoing message queue is full, the `Send` and `SendAsync`" + " methods of producer block, rather than failing and throwing errors.\n" + "If it is set to `false`, when the outgoing message queue is full, the `Send` and `SendAsync`" + " methods of producer fail and `ProducerQueueIsFullError` exceptions occur.\n" @@ -86,9 +86,9 @@ public class ProducerConfigurationData implements Serializable, Cloneable { ) private boolean blockIfQueueFull = false; - @ApiModelProperty( + @Schema( name = "maxPendingMessages", - value = "The maximum size of a queue holding pending messages.\n" + description = "The maximum size of a queue holding pending messages.\n" + "\n" + "For example, a message waiting to receive an acknowledgment from a [broker]" + "(https://pulsar.apache.org/docs/reference-terminology#broker).\n" @@ -100,18 +100,18 @@ public class ProducerConfigurationData implements Serializable, Cloneable { @Getter private int maxPendingMessages = DEFAULT_MAX_PENDING_MESSAGES; - @ApiModelProperty( + @Schema( name = "maxPendingMessagesAcrossPartitions", - value = "The maximum number of pending messages across partitions.\n" + description = "The maximum number of pending messages across partitions.\n" + "\n" + "Use the setting to lower the max pending messages for each partition ({@link " + "#setMaxPendingMessages(int)}) if the total number exceeds the configured value." ) private int maxPendingMessagesAcrossPartitions = DEFAULT_MAX_PENDING_MESSAGES_ACROSS_PARTITIONS; - @ApiModelProperty( + @Schema( name = "messageRoutingMode", - value = "Message routing logic for producers on [partitioned topics]" + description = "Message routing logic for producers on [partitioned topics]" + "(https://pulsar.apache.org/docs/concepts-architecture-overview#partitioned-topics).\n" + "Apply the logic only when setting no key on messages.\n" + "Available options are as follows:\n" @@ -121,10 +121,10 @@ public class ProducerConfigurationData implements Serializable, Cloneable { ) private MessageRoutingMode messageRoutingMode = null; - @ApiModelProperty( + @Schema( name = "hashingScheme", - value = "Hashing function determining the partition where you publish a particular message (partitioned " - + "topics only).\n" + description = "Hashing function determining the partition where you publish a particular message " + + "(partitioned topics only).\n" + "Available options are as follows:\n" + "* `pulsar.JavastringHash`: the equivalent of `string.hashCode()` in Java\n" + "* `pulsar.Murmur3_32Hash`: applies the [Murmur3](https://en.wikipedia.org/wiki/MurmurHash)" @@ -134,9 +134,9 @@ public class ProducerConfigurationData implements Serializable, Cloneable { ) private HashingScheme hashingScheme = HashingScheme.JavaStringHash; - @ApiModelProperty( + @Schema( name = "cryptoFailureAction", - value = "Producer should take action when encryption fails.\n" + description = "Producer should take action when encryption fails.\n" + "* **FAIL**: if encryption fails, unencrypted messages fail to send.\n" + "* **SEND**: if encryption fails, unencrypted messages are sent." ) @@ -145,31 +145,31 @@ public class ProducerConfigurationData implements Serializable, Cloneable { @JsonIgnore private MessageRouter customMessageRouter = null; - @ApiModelProperty( + @Schema( name = "batchingMaxPublishDelayMicros", - value = "Batching time period of sending messages." + description = "Batching time period of sending messages." ) private long batchingMaxPublishDelayMicros = TimeUnit.MILLISECONDS.toMicros(1); private int batchingPartitionSwitchFrequencyByPublishDelay = 10; - @ApiModelProperty( + @Schema( name = "batchingMaxMessages", - value = "The maximum number of messages permitted in a batch." + description = "The maximum number of messages permitted in a batch." ) private int batchingMaxMessages = DEFAULT_BATCHING_MAX_MESSAGES; private int batchingMaxBytes = 128 * 1024; // 128KB (keep the maximum consistent as previous versions) - @ApiModelProperty( + @Schema( name = "batchingEnabled", - value = "Enable batching of messages." + description = "Enable batching of messages." ) private boolean batchingEnabled = true; // enabled by default @JsonIgnore private BatcherBuilder batcherBuilder = BatcherBuilder.DEFAULT; - @ApiModelProperty( + @Schema( name = "chunkingEnabled", - value = "Enable chunking of messages." + description = "Enable chunking of messages." ) private boolean chunkingEnabled = false; private int chunkMaxMessageSize = -1; @@ -182,9 +182,9 @@ public class ProducerConfigurationData implements Serializable, Cloneable { private Set encryptionKeys = new TreeSet<>(); - @ApiModelProperty( + @Schema( name = "compressionType", - value = "Message data compression type used by a producer.\n" + description = "Message data compression type used by a producer.\n" + "Available options:\n" + "* [LZ4](https://github.com/lz4/lz4)\n" + "* [ZLIB](https://zlib.net/)\n" @@ -214,10 +214,10 @@ public class ProducerConfigurationData implements Serializable, Cloneable { private boolean isReplProducer; - @ApiModelProperty( + @Schema( name = "initialSubscriptionName", - value = "Use this configuration to automatically create an initial subscription when creating a topic." - + " If this field is not set, the initial subscription is not created." + description = "Use this configuration to automatically create an initial subscription when " + + "creating a topic. If this field is not set, the initial subscription is not created." ) private String initialSubscriptionName = null; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java index 29be90ec994f5..7d8f5dc17e5b8 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.HashSet; import java.util.List; @@ -43,10 +43,10 @@ public class ReaderConfigurationData implements Serializable, Cloneable { private static final long serialVersionUID = 1L; - @ApiModelProperty( + @Schema( name = "topicNames", - required = true, - value = "Topic name" + requiredMode = Schema.RequiredMode.REQUIRED, + description = "Topic name" ) private Set topicNames = new HashSet<>(); @@ -56,9 +56,9 @@ public class ReaderConfigurationData implements Serializable, Cloneable { @JsonIgnore private long startMessageFromRollbackDurationInSec; - @ApiModelProperty( + @Schema( name = "receiverQueueSize", - value = "Size of a consumer's receiver queue.\n" + description = "Size of a consumer's receiver queue.\n" + "\n" + "For example, the number of messages that can be accumulated by a consumer before an " + "application calls `Receive`.\n" @@ -68,45 +68,45 @@ public class ReaderConfigurationData implements Serializable, Cloneable { ) private int receiverQueueSize = 1000; - @ApiModelProperty( + @Schema( name = "readerListener", - value = "A listener that is called for message received." + description = "A listener that is called for message received." ) private ReaderListener readerListener; - @ApiModelProperty( + @Schema( name = "readerDecryptFailListener", - value = "A listener that is called for encrypted message received and decrypt fail." + description = "A listener that is called for encrypted message received and decrypt fail." ) private ReaderDecryptFailListener readerDecryptFailListener; - @ApiModelProperty( + @Schema( name = "readerName", - value = "Reader name" + description = "Reader name" ) private String readerName = null; - @ApiModelProperty( + @Schema( name = "subscriptionRolePrefix", - value = "Prefix of subscription role." + description = "Prefix of subscription role." ) private String subscriptionRolePrefix = null; - @ApiModelProperty( + @Schema( name = "subscriptionName", - value = "Subscription name" + description = "Subscription name" ) private String subscriptionName = null; - @ApiModelProperty( + @Schema( name = "cryptoKeyReader", - value = "Interface that abstracts the access to a key store." + description = "Interface that abstracts the access to a key store." ) private CryptoKeyReader cryptoKeyReader = null; - @ApiModelProperty( + @Schema( name = "cryptoFailureAction", - value = "Consumer should take action when it receives a message that can not be decrypted.\n" + description = "Consumer should take action when it receives a message that can not be decrypted.\n" + "* **FAIL**: this is the default option to fail messages until crypto succeeds.\n" + "* **DISCARD**: silently acknowledge and not deliver message to an application.\n" + "* **CONSUME**: deliver encrypted messages to applications. It is the application's" @@ -127,10 +127,10 @@ public class ReaderConfigurationData implements Serializable, Cloneable { @JsonIgnore private transient MessageCrypto messageCrypto = null; - @ApiModelProperty( + @Schema( name = "readCompacted", - value = "If enabling `readCompacted`, a consumer reads messages from a compacted topic rather than a full " - + "message backlog of a topic.\n" + description = "If enabling `readCompacted`, a consumer reads messages from a compacted topic rather than " + + "a full message backlog of a topic.\n" + "\n" + "A consumer only sees the latest value for each key in the compacted topic, up until reaching " + "the point in the topic message when compacting backlog. Beyond that point, send messages as " @@ -144,9 +144,9 @@ public class ReaderConfigurationData implements Serializable, Cloneable { ) private boolean readCompacted = false; - @ApiModelProperty( + @Schema( name = "resetIncludeHead", - value = "If set to true, the first message to be returned is the one specified by `messageId`.\n" + description = "If set to true, the first message to be returned is the one specified by `messageId`.\n" + "\n" + "If set to false, the first message to be returned is the one next to the message specified by " + "`messageId`." diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/functions/UpdateOptionsImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/functions/UpdateOptionsImpl.java index c7c02453fff47..ac56511262ef4 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/functions/UpdateOptionsImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/functions/UpdateOptionsImpl.java @@ -18,8 +18,7 @@ */ package org.apache.pulsar.common.functions; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.NoArgsConstructor; @@ -28,10 +27,10 @@ */ @Data @NoArgsConstructor -@ApiModel(value = "UpdateOptions", description = "Options while updating the sink") +@Schema(name = "UpdateOptions", description = "Options while updating the sink") public class UpdateOptionsImpl implements UpdateOptions { - @ApiModelProperty( - value = "Whether or not to update the auth data", + @Schema( + description = "Whether or not to update the auth data", name = "update-auth-data") private boolean updateAuthData = false; } diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java index 0a6db27341b4d..4adf1a139062a 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java @@ -20,8 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Map; import lombok.AllArgsConstructor; import lombok.Data; @@ -31,25 +30,25 @@ /** * The auto failover policy configuration data. */ -@ApiModel( - value = "AutoFailoverPolicyData", +@Schema( + name = "AutoFailoverPolicyData", description = "The auto failover policy configuration data" ) @Data @NoArgsConstructor @AllArgsConstructor public class AutoFailoverPolicyDataImpl implements AutoFailoverPolicyData { - @ApiModelProperty( + @Schema( name = "policy_type", - value = "The auto failover policy type", - allowableValues = "min_available" + description = "The auto failover policy type", + allowableValues = {"min_available"} ) @JsonProperty("policy_type") private AutoFailoverPolicyType policyType; - @ApiModelProperty( + @Schema( name = "parameters", - value = + description = "The parameters applied to the auto failover policy specified by `policy_type`.\n" + "The parameters for 'min_available' are :\n" + " - 'min_limit': the limit of minimal number of available brokers in primary" diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/BrokerNamespaceIsolationDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/BrokerNamespaceIsolationDataImpl.java index 52574dd6dbeff..38e8ac4eabbbf 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/BrokerNamespaceIsolationDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/BrokerNamespaceIsolationDataImpl.java @@ -18,8 +18,7 @@ */ package org.apache.pulsar.common.policies.data; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import lombok.AllArgsConstructor; import lombok.Data; @@ -28,8 +27,8 @@ /** * The namespace isolation data for a given broker. */ -@ApiModel( - value = "BrokerNamespaceIsolationData", +@Schema( + name = "BrokerNamespaceIsolationData", description = "The namespace isolation data for a given broker" ) @Data @@ -37,27 +36,27 @@ @NoArgsConstructor public final class BrokerNamespaceIsolationDataImpl implements BrokerNamespaceIsolationData { - @ApiModelProperty( + @Schema( name = "brokerName", - value = "The broker name", + description = "The broker name", example = "broker1:8080" ) private String brokerName; - @ApiModelProperty( + @Schema( name = "policyName", - value = "Policy name", + description = "Policy name", example = "my-policy" ) private String policyName; - @ApiModelProperty( + @Schema( name = "isPrimary", - value = "Is Primary broker", + description = "Is Primary broker", example = "true/false" ) private boolean isPrimary; - @ApiModelProperty( + @Schema( name = "namespaceRegex", - value = "The namespace-isolation policies attached to this broker" + description = "The namespace-isolation policies attached to this broker" ) private List namespaceRegex; //isolated namespace regex diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java index af82da4b790e1..7bdc43d866c08 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java @@ -18,8 +18,7 @@ */ package org.apache.pulsar.common.policies.data; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.LinkedHashSet; import java.util.Objects; import lombok.AllArgsConstructor; @@ -34,8 +33,8 @@ /** * The configuration data for a cluster. */ -@ApiModel( - value = "ClusterData", +@Schema( + name = "ClusterData", description = "The configuration data for a cluster" ) @Data @@ -43,147 +42,148 @@ @NoArgsConstructor @CustomLog public final class ClusterDataImpl implements ClusterData, Cloneable { - @ApiModelProperty( + @Schema( name = "serviceUrl", - value = "The HTTP rest service URL (for admin operations)", + description = "The HTTP rest service URL (for admin operations)", example = "http://pulsar.example.com:8080" ) private String serviceUrl; - @ApiModelProperty( + @Schema( name = "serviceUrlTls", - value = "The HTTPS rest service URL (for admin operations)", + description = "The HTTPS rest service URL (for admin operations)", example = "https://pulsar.example.com:8443" ) private String serviceUrlTls; - @ApiModelProperty( + @Schema( name = "brokerServiceUrl", - value = "The broker service url (for produce and consume operations)", + description = "The broker service url (for produce and consume operations)", example = "pulsar://pulsar.example.com:6650" ) private String brokerServiceUrl; - @ApiModelProperty( + @Schema( name = "brokerServiceUrlTls", - value = "The secured broker service url (for produce and consume operations)", + description = "The secured broker service url (for produce and consume operations)", example = "pulsar+ssl://pulsar.example.com:6651" ) private String brokerServiceUrlTls; - @ApiModelProperty( + @Schema( name = "proxyServiceUrl", - value = "Proxy-service url when client would like to connect to broker via proxy.", + description = "Proxy-service url when client would like to connect to broker via proxy.", example = "pulsar+ssl://ats-proxy.example.com:4443 or " + "pulsar://ats-proxy.example.com:4080" ) private String proxyServiceUrl; - @ApiModelProperty( + @Schema( name = "authenticationPlugin", - value = "Authentication plugin when client would like to connect to cluster.", + description = "Authentication plugin when client would like to connect to cluster.", example = "org.apache.pulsar.client.impl.auth.AuthenticationToken" ) private String authenticationPlugin; - @ApiModelProperty( + @Schema( name = "authenticationParameters", - value = "Authentication parameters when client would like to connect to cluster." + description = "Authentication parameters when client would like to connect to cluster." ) private String authenticationParameters; - @ApiModelProperty( + @Schema( name = "proxyProtocol", - value = "protocol to decide type of proxy routing eg: SNI-routing", + description = "protocol to decide type of proxy routing eg: SNI-routing", example = "SNI" ) private ProxyProtocol proxyProtocol; // For given Cluster1(us-west1, us-east1) and Cluster2(us-west2, us-east2) // Peer: [us-west1 -> us-west2] and [us-east1 -> us-east2] - @ApiModelProperty( + @Schema( name = "peerClusterNames", - value = "A set of peer cluster names" + description = "A set of peer cluster names" ) private LinkedHashSet peerClusterNames; - @ApiModelProperty( + @Schema( name = "brokerClientTlsEnabled", - value = "Enable TLS when talking with other brokers in the same cluster (admin operation)" + description = "Enable TLS when talking with other brokers in the same cluster (admin operation)" + " or different clusters (replication)" ) private boolean brokerClientTlsEnabled; - @ApiModelProperty( + @Schema( name = "tlsAllowInsecureConnection", - value = "Allow TLS connections to servers whose certificate cannot" + description = "Allow TLS connections to servers whose certificate cannot" + " be verified to have been signed by a trusted certificate" + " authority." ) private boolean tlsAllowInsecureConnection; - @ApiModelProperty( + @Schema( name = "brokerClientTlsEnabledWithKeyStore", - value = "Whether internal client use KeyStore type to authenticate with other Pulsar brokers" + description = "Whether internal client use KeyStore type to authenticate with other Pulsar brokers" ) private boolean brokerClientTlsEnabledWithKeyStore; - @ApiModelProperty( + @Schema( name = "brokerClientTlsTrustStoreType", - value = "TLS TrustStore type configuration for internal client: JKS, PKCS12" + description = "TLS TrustStore type configuration for internal client: JKS, PKCS12" + " used by the internal client to authenticate with Pulsar brokers", example = "JKS" ) private String brokerClientTlsTrustStoreType; - @ApiModelProperty( + @Schema( name = "brokerClientTlsTrustStore", - value = "TLS TrustStore path for internal client" + description = "TLS TrustStore path for internal client" + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsTrustStore; - @ApiModelProperty( + @Schema( name = "brokerClientTlsTrustStorePassword", - value = "TLS TrustStore password for internal client" + description = "TLS TrustStore password for internal client" + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsTrustStorePassword; - @ApiModelProperty( + @Schema( name = "brokerClientTlsKeyStoreType", - value = "TLS KeyStore type configuration for internal client: JKS, PKCS12," + description = "TLS KeyStore type configuration for internal client: JKS, PKCS12," + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsKeyStoreType; - @ApiModelProperty( + @Schema( name = "brokerClientTlsKeyStore", - value = "TLS KeyStore path for internal client, " + description = "TLS KeyStore path for internal client, " + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsKeyStore; - @ApiModelProperty( + @Schema( name = "brokerClientTlsKeyStorePassword", - value = "TLS KeyStore password for internal client, " + description = "TLS KeyStore password for internal client, " + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsKeyStorePassword; - @ApiModelProperty( + @Schema( name = "brokerClientTrustCertsFilePath", - value = "Path for the trusted TLS certificate file for outgoing connection to a server (broker)" + description = "Path for the trusted TLS certificate file for outgoing connection to a server (broker)" ) private String brokerClientTrustCertsFilePath; - @ApiModelProperty( + @Schema( name = "brokerClientKeyFilePath", - value = "TLS private key file for internal client, " + description = "TLS private key file for internal client, " + "used by the internal client to authenticate with Pulsar brokers") private String brokerClientKeyFilePath; - @ApiModelProperty( + @Schema( name = "brokerClientCertificateFilePath", - value = "TLS certificate file for internal client, " + description = "TLS certificate file for internal client, " + "used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientCertificateFilePath; - @ApiModelProperty( + @Schema( name = "brokerClientSslFactoryPlugin", - value = "SSL Factory plugin used by internal client to generate the SSL Context and Engine" + description = "SSL Factory plugin used by internal client to generate the SSL Context and Engine" ) private String brokerClientSslFactoryPlugin; - @ApiModelProperty( + @Schema( name = "brokerClientSslFactoryPluginParams", - value = "Parameters used by the internal client's SSL factory plugin to generate the SSL Context and Engine" + description = + "Parameters used by the internal client's SSL factory plugin to generate the SSL Context and Engine" ) private String brokerClientSslFactoryPluginParams; - @ApiModelProperty( + @Schema( name = "listenerName", - value = "listenerName when client would like to connect to cluster", + description = "listenerName when client would like to connect to cluster", example = "" ) private String listenerName; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java index c8af2dec3216b..5e821f1aecc1c 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java @@ -18,8 +18,7 @@ */ package org.apache.pulsar.common.policies.data; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -27,23 +26,23 @@ /** * The configuration data for a cluster. */ -@ApiModel( - value = "ClusterPolicies", +@Schema( + name = "ClusterPolicies", description = "The local cluster policies for a cluster" ) @Data @AllArgsConstructor @NoArgsConstructor public final class ClusterPoliciesImpl implements ClusterPolicies, Cloneable { - @ApiModelProperty( + @Schema( name = "migrated", - value = "flag to check if cluster is migrated to different cluster", + description = "flag to check if cluster is migrated to different cluster", example = "true/false" ) private boolean migrated; - @ApiModelProperty( + @Schema( name = "migratedClusterUrl", - value = "url of cluster where current cluster is migrated" + description = "url of cluster where current cluster is migrated" ) private ClusterUrl migratedClusterUrl; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/FailureDomainImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/FailureDomainImpl.java index c69043242e97b..1c3f93ea00181 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/FailureDomainImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/FailureDomainImpl.java @@ -18,8 +18,7 @@ */ package org.apache.pulsar.common.policies.data; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.HashSet; import java.util.Set; import lombok.AllArgsConstructor; @@ -29,8 +28,8 @@ /** * The data of a failure domain configuration in a cluster. */ -@ApiModel( - value = "FailureDomain", +@Schema( + name = "FailureDomain", description = "The data of a failure domain configuration in a cluster" ) @Data @@ -38,9 +37,9 @@ @AllArgsConstructor public final class FailureDomainImpl implements FailureDomain { - @ApiModelProperty( + @Schema( name = "brokers", - value = "The collection of brokers in the same failure domain", + description = "The collection of brokers in the same failure domain", example = "[ 'broker-1', 'broker-2' ]" ) public Set brokers; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/NamespaceIsolationDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/NamespaceIsolationDataImpl.java index 85be8090f52a1..e820dcf20efa4 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/NamespaceIsolationDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/NamespaceIsolationDataImpl.java @@ -20,8 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; @@ -34,8 +33,8 @@ /** * The data of namespace isolation configuration. */ -@ApiModel( - value = "NamespaceIsolationData", +@Schema( + name = "NamespaceIsolationData", description = "The data of namespace isolation configuration" ) @Data @@ -43,30 +42,30 @@ @NoArgsConstructor public class NamespaceIsolationDataImpl implements NamespaceIsolationData { - @ApiModelProperty( + @Schema( name = "namespaces", - value = "The list of namespaces to apply this namespace isolation data" + description = "The list of namespaces to apply this namespace isolation data" ) private List namespaces; - @ApiModelProperty( + @Schema( name = "primary", - value = "The list of primary brokers for serving the list of namespaces in this isolation policy" + description = "The list of primary brokers for serving the list of namespaces in this isolation policy" ) private List primary; - @ApiModelProperty( + @Schema( name = "secondary", - value = "The list of secondary brokers for serving the list of namespaces in this isolation policy" + description = "The list of secondary brokers for serving the list of namespaces in this isolation policy" ) private List secondary; - @ApiModelProperty( + @Schema( name = "auto_failover_policy", - value = "The data of auto-failover policy configuration", + description = "The data of auto-failover policy configuration", example = "{" - + " \"policy_type\": \"min_available\"" + + " \"policy_type\": \"min_available\"," + " \"parameters\": {" + " \"\": \"\"" + " }" @@ -75,9 +74,9 @@ public class NamespaceIsolationDataImpl implements NamespaceIsolationData { @JsonProperty("auto_failover_policy") private AutoFailoverPolicyData autoFailoverPolicy; - @ApiModelProperty( + @Schema( name = "unload_scope", - value = "The type of unload to perform while applying the new isolation policy.", + description = "The type of unload to perform while applying the new isolation policy.", example = "'changed' (default) for unloading only the namespaces whose placement is actually changing. " + "'all_matching' for unloading all matching namespaces. 'none' for not unloading any namespaces." ) diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java index 2e45b9c199f12..d54e156e88f09 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java @@ -18,8 +18,7 @@ */ package org.apache.pulsar.common.policies.data; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.HashSet; import java.util.Set; import lombok.AllArgsConstructor; @@ -32,13 +31,13 @@ @Data @AllArgsConstructor @NoArgsConstructor -@ApiModel(value = "TenantInfo", description = "Information of adminRoles and allowedClusters for tenant") +@Schema(name = "TenantInfo", description = "Information of adminRoles and allowedClusters for tenant") public class TenantInfoImpl implements TenantInfo { /** * List of role enabled as admin for this tenant. */ - @ApiModelProperty( - value = "Comma separated list of auth principal allowed to administrate the tenant.", + @Schema( + description = "Comma separated list of auth principal allowed to administrate the tenant.", name = "adminRoles" ) private Set adminRoles; @@ -46,8 +45,8 @@ public class TenantInfoImpl implements TenantInfo { /** * List of clusters this tenant is restricted on. */ - @ApiModelProperty( - value = "Comma separated allowed clusters.", + @Schema( + description = "Comma separated allowed clusters.", name = "allowedClusters" ) private Set allowedClusters; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java b/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java index f71888009bf4c..03663307e3d60 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.common.util; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Set; import lombok.Builder; @@ -36,122 +36,122 @@ public class PulsarSslConfiguration implements Serializable, Cloneable { private static final long serialVersionUID = 1L; - @ApiModelProperty( + @Schema( name = "tlsCiphers", - value = "TLS ciphers to be used", - required = true + description = "TLS ciphers to be used", + requiredMode = Schema.RequiredMode.REQUIRED ) private Set tlsCiphers; - @ApiModelProperty( + @Schema( name = "tlsProtocols", - value = "TLS protocols to be used", - required = true + description = "TLS protocols to be used", + requiredMode = Schema.RequiredMode.REQUIRED ) private Set tlsProtocols; - @ApiModelProperty( + @Schema( name = "allowInsecureConnection", - value = "Insecure Connections are allowed", - required = true + description = "Insecure Connections are allowed", + requiredMode = Schema.RequiredMode.REQUIRED ) private boolean allowInsecureConnection; - @ApiModelProperty( + @Schema( name = "requireTrustedClientCertOnConnect", - value = "Require trusted client certificate on connect", - required = true + description = "Require trusted client certificate on connect", + requiredMode = Schema.RequiredMode.REQUIRED ) private boolean requireTrustedClientCertOnConnect; - @ApiModelProperty( + @Schema( name = "authData", - value = "Authentication Data Provider utilized by the Client for identification" + description = "Authentication Data Provider utilized by the Client for identification" ) private AuthenticationDataProvider authData; - @ApiModelProperty( + @Schema( name = "tlsCustomParams", - value = "Custom Parameters required by Pulsar SSL factory plugins" + description = "Custom Parameters required by Pulsar SSL factory plugins" ) private String tlsCustomParams; - @ApiModelProperty( + @Schema( name = "tlsProvider", - value = "TLS Provider to be used" + description = "TLS Provider to be used" ) private String tlsProvider; - @ApiModelProperty( + @Schema( name = "tlsTrustStoreType", - value = "TLS Trust Store Type to be used" + description = "TLS Trust Store Type to be used" ) private String tlsTrustStoreType; - @ApiModelProperty( + @Schema( name = "tlsTrustStorePath", - value = "TLS Trust Store Path" + description = "TLS Trust Store Path" ) private String tlsTrustStorePath; - @ApiModelProperty( + @Schema( name = "tlsTrustStorePassword", - value = "TLS Trust Store Password" + description = "TLS Trust Store Password" ) private String tlsTrustStorePassword; - @ApiModelProperty( + @Schema( name = "tlsTrustCertsFilePath", - value = " TLS Trust certificates file path" + description = " TLS Trust certificates file path" ) private String tlsTrustCertsFilePath; - @ApiModelProperty( + @Schema( name = "tlsCertificateFilePath", - value = "Path for the TLS Certificate file" + description = "Path for the TLS Certificate file" ) private String tlsCertificateFilePath; - @ApiModelProperty( + @Schema( name = "tlsKeyFilePath", - value = "Path for TLS Private key file" + description = "Path for TLS Private key file" ) private String tlsKeyFilePath; - @ApiModelProperty( + @Schema( name = "tlsKeyStoreType", - value = "TLS Key Store Type to be used" + description = "TLS Key Store Type to be used" ) private String tlsKeyStoreType; - @ApiModelProperty( + @Schema( name = "tlsKeyStorePath", - value = "TLS Key Store Path" + description = "TLS Key Store Path" ) private String tlsKeyStorePath; - @ApiModelProperty( + @Schema( name = "tlsKeyStorePassword", - value = "TLS Key Store Password" + description = "TLS Key Store Password" ) private String tlsKeyStorePassword; - @ApiModelProperty( + @Schema( name = "isTlsEnabledWithKeystore", - value = "TLS configuration enabled with key store configs" + description = "TLS configuration enabled with key store configs" ) private boolean tlsEnabledWithKeystore; - @ApiModelProperty( + @Schema( name = "isServerMode", - value = "Is the SSL Configuration for a Server or Client", - required = true + description = "Is the SSL Configuration for a Server or Client", + requiredMode = Schema.RequiredMode.REQUIRED ) private boolean serverMode; - @ApiModelProperty( + @Schema( name = "isHttps", - value = "Is the SSL Configuration for a Http client or Server" + description = "Is the SSL Configuration for a Http client or Server" ) private boolean isHttps; diff --git a/pulsar-docs-tools/build.gradle.kts b/pulsar-docs-tools/build.gradle.kts index f5211f4b85aff..4438ae22edd6f 100644 --- a/pulsar-docs-tools/build.gradle.kts +++ b/pulsar-docs-tools/build.gradle.kts @@ -22,8 +22,9 @@ plugins { } dependencies { + implementation(libs.commons.lang3) + implementation(libs.guava) implementation(libs.slog) implementation(libs.swagger.annotations) - implementation(libs.swagger.core) implementation(libs.picocli) } diff --git a/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java b/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java index 603448d7404f0..8522b2c4c3310 100644 --- a/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java +++ b/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.docs.tools; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -76,14 +76,14 @@ public boolean run(String[] args) throws Exception { protected abstract String generateDocumentByClassName(String className) throws Exception; - protected Predicate isRequiredApiModel = field -> { - ApiModelProperty modelProperty = field.getAnnotation(ApiModelProperty.class); - return modelProperty.required(); + protected Predicate isRequiredSchema = field -> { + Schema schema = field.getAnnotation(Schema.class); + return schema.requiredMode() == Schema.RequiredMode.REQUIRED; }; - protected Predicate isOptionalApiModel = field -> { - ApiModelProperty modelProperty = field.getAnnotation(ApiModelProperty.class); - return !modelProperty.required(); + protected Predicate isOptionalSchema = field -> { + Schema schema = field.getAnnotation(Schema.class); + return schema.requiredMode() != Schema.RequiredMode.REQUIRED; }; private Annotation getFieldContextAnnotation(Field field) { @@ -150,14 +150,14 @@ protected void writeDocListByFieldContext(List> } } - protected void writeDocListByApiModel(List fieldList, StringBuilder sb, Object obj) throws Exception { + protected void writeDocListBySchema(List fieldList, StringBuilder sb, Object obj) throws Exception { for (Field field : fieldList) { - ApiModelProperty modelProperty = field.getAnnotation(ApiModelProperty.class); + Schema schema = field.getAnnotation(Schema.class); field.setAccessible(true); - String name = StringUtils.isBlank(modelProperty.name()) ? field.getName() : modelProperty.name(); + String name = StringUtils.isBlank(schema.name()) ? field.getName() : schema.name(); sb.append("### ").append(name).append("\n"); - sb.append(modelProperty.value().replace(">", "\\>")).append("\n\n"); + sb.append(schema.description().replace(">", "\\>")).append("\n\n"); sb.append("**Type**: `").append(field.getType().getCanonicalName()).append("`\n\n"); sb.append("**Default**: `").append(field.get(obj)).append("`\n\n"); } @@ -212,7 +212,7 @@ protected String generateDocByFieldContext(String className, String type) throws return sb.toString(); } - protected String generateDocByApiModelProperty(String className, String type) throws Exception { + protected String generateDocBySchema(String className, String type) throws Exception { final StringBuilder sb = new StringBuilder(); Class clazz = Class.forName(className); @@ -220,16 +220,16 @@ protected String generateDocByApiModelProperty(String className, String type) th Field[] fields = clazz.getDeclaredFields(); ArrayList fieldList = new ArrayList<>(Arrays.asList(fields)); - fieldList.removeIf(f -> f.getAnnotation(ApiModelProperty.class) == null); + fieldList.removeIf(f -> f.getAnnotation(Schema.class) == null); fieldList.sort(Comparator.comparing(Field::getName)); - List requiredFields = fieldList.stream().filter(isRequiredApiModel).collect(Collectors.toList()); - List optionalFields = fieldList.stream().filter(isOptionalApiModel).collect(Collectors.toList()); + List requiredFields = fieldList.stream().filter(isRequiredSchema).collect(Collectors.toList()); + List optionalFields = fieldList.stream().filter(isOptionalSchema).collect(Collectors.toList()); sb.append("# ").append(type).append("\n\n"); sb.append("## Required\n"); - writeDocListByApiModel(requiredFields, sb, obj); + writeDocListBySchema(requiredFields, sb, obj); sb.append("## Optional\n"); - writeDocListByApiModel(optionalFields, sb, obj); + writeDocListBySchema(optionalFields, sb, obj); return sb.toString(); } diff --git a/pulsar-functions/localrun-shaded/build.gradle.kts b/pulsar-functions/localrun-shaded/build.gradle.kts index 5777ed96b2ac8..882c0cbbbd19c 100644 --- a/pulsar-functions/localrun-shaded/build.gradle.kts +++ b/pulsar-functions/localrun-shaded/build.gradle.kts @@ -46,7 +46,7 @@ tasks.shadowJar { include(dependency("com.google.*:.*")) include(dependency("jakarta.servlet:.*")) include(dependency("org.reactivestreams:reactive-streams")) - include(dependency("io.swagger:.*")) + include(dependency("io.swagger.core.v3:.*")) include(dependency("org.yaml:snakeyaml")) include(dependency("io.perfmark:.*")) include(dependency("io.prometheus:.*")) diff --git a/pulsar-functions/runtime/build.gradle.kts b/pulsar-functions/runtime/build.gradle.kts index 34cb0d6c8e460..cbaba775d3ab4 100644 --- a/pulsar-functions/runtime/build.gradle.kts +++ b/pulsar-functions/runtime/build.gradle.kts @@ -51,6 +51,8 @@ dependencies { exclude(group = "org.bouncycastle", module = "bcprov-jdk18on") exclude(group = "javax.annotation", module = "javax.annotation-api") exclude(group = "software.amazon.awssdk") + // Swagger 1.x annotations on the generated k8s models are inert metadata; nothing reads them at runtime + exclude(group = "io.swagger", module = "swagger-annotations") } implementation(libs.simpleclient.hotspot) implementation(libs.prometheus.jmx.collector) diff --git a/pulsar-functions/secrets/build.gradle.kts b/pulsar-functions/secrets/build.gradle.kts index 91779589e50de..0dd441a0f2448 100644 --- a/pulsar-functions/secrets/build.gradle.kts +++ b/pulsar-functions/secrets/build.gradle.kts @@ -25,6 +25,8 @@ dependencies { implementation(project(":pulsar-functions:pulsar-functions-proto")) implementation(libs.kubernetes.client.java) { exclude(group = "software.amazon.awssdk") + // Swagger 1.x annotations on the generated k8s models are inert metadata; nothing reads them at runtime + exclude(group = "io.swagger", module = "swagger-annotations") } implementation(libs.gson) implementation(libs.commons.lang3) diff --git a/pulsar-functions/worker/build.gradle.kts b/pulsar-functions/worker/build.gradle.kts index d7455223757ca..a4201d6a2ae5d 100644 --- a/pulsar-functions/worker/build.gradle.kts +++ b/pulsar-functions/worker/build.gradle.kts @@ -45,7 +45,7 @@ dependencies { implementation(project(":pulsar-functions:pulsar-functions-proto")) implementation(project(":pulsar-functions:pulsar-functions-secrets")) implementation(project(":pulsar-docs-tools")) { - exclude(group = "io.swagger") + exclude(group = "io.swagger.core.v3") } implementation(project(":pulsar-package-management:pulsar-package-core")) @@ -83,10 +83,7 @@ dependencies { implementation(libs.simpleclient.hotspot) implementation(libs.simpleclient.common) - compileOnly(libs.swagger.core) { - exclude(group = "com.fasterxml.jackson.core") - exclude(group = "com.fasterxml.jackson.dataformat") - } + compileOnly(libs.swagger.annotations) testImplementation(libs.protobuf.java.util) testImplementation(project(":pulsar-functions:pulsar-functions-api-examples")) diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerReadinessResource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerReadinessResource.java index 1ef8055ec80ad..1a07c1a7d2f5a 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerReadinessResource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/WorkerReadinessResource.java @@ -18,9 +18,11 @@ */ package org.apache.pulsar.functions.worker.rest; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.GET; @@ -51,13 +53,15 @@ public synchronized WorkerService get() { } @GET - @ApiOperation( - value = "Determines whether the worker service is initialized and ready for use", - response = Boolean.class + @Operation( + summary = "Determines whether the worker service is initialized and ready for use" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", + description = "Determines whether the worker service is initialized and ready for use", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/initialized") public boolean isInitialized() { diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/FunctionsApiV2Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/FunctionsApiV2Resource.java index 36845a7489b7b..dac556d6ea57d 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/FunctionsApiV2Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/FunctionsApiV2Resource.java @@ -18,9 +18,12 @@ */ package org.apache.pulsar.functions.worker.rest.api.v2; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -37,8 +40,6 @@ import lombok.CustomLog; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.common.io.ConnectorDefinition; -import org.apache.pulsar.functions.proto.FunctionMetaData; -import org.apache.pulsar.functions.proto.FunctionStatus; import org.apache.pulsar.functions.worker.WorkerService; import org.apache.pulsar.functions.worker.rest.FunctionApiResource; import org.apache.pulsar.functions.worker.service.api.FunctionsV2; @@ -54,12 +55,12 @@ FunctionsV2 functions() { } @POST - @ApiOperation(value = "Creates a new Pulsar Function in cluster mode") + @Operation(summary = "Creates a new Pulsar Function in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request (function already exists, etc.)"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "Pulsar Function successfully created") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request (function already exists, etc.)"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully created") }) @Path("/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -76,11 +77,11 @@ public Response registerFunction(final @PathParam("tenant") String tenant, } @PUT - @ApiOperation(value = "Updates a Pulsar Function currently running in cluster mode") + @Operation(summary = "Updates a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request (function doesn't exist, etc.)"), - @ApiResponse(code = 200, message = "Pulsar Function successfully updated") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request (function doesn't exist, etc.)"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated") }) @Path("/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -98,13 +99,13 @@ public Response updateFunction(final @PathParam("tenant") String tenant, @DELETE - @ApiOperation(value = "Deletes a Pulsar Function currently running in cluster mode") + @Operation(summary = "Deletes a Pulsar Function currently running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function doesn't exist"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 200, message = "The function was successfully deleted") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", description = "The function was successfully deleted") }) @Path("/{tenant}/{namespace}/{functionName}") public Response deregisterFunction(final @PathParam("tenant") String tenant, @@ -114,15 +115,18 @@ public Response deregisterFunction(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Fetches information about a Pulsar Function currently running in cluster mode", - response = FunctionMetaData.class + @Operation( + summary = "Fetches information about a Pulsar Function currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist"), + @ApiResponse(responseCode = "200", + description = "Fetches information about a Pulsar Function currently running in cluster mode", + content = @Content(schema = @Schema(type = "object", + description = "FunctionMetaData (protobuf JSON format)"))) }) @Path("/{tenant}/{namespace}/{functionName}") public Response getFunctionInfo(final @PathParam("tenant") String tenant, @@ -133,15 +137,19 @@ public Response getFunctionInfo(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function instance", - response = FunctionStatus.class + @Operation( + summary = "Displays the status of a Pulsar Function instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist"), + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Function instance", + content = @Content(schema = @Schema(type = "object", + description = "InstanceCommunication.FunctionStatus (protobuf JSON format)"))) }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/status") public Response getFunctionInstanceStatus(final @PathParam("tenant") String tenant, @@ -154,14 +162,18 @@ public Response getFunctionInstanceStatus(final @PathParam("tenant") String tena } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function running in cluster mode", - response = FunctionStatus.class + @Operation( + summary = "Displays the status of a Pulsar Function running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions") + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Function running in cluster mode", + content = @Content(schema = @Schema(type = "object", + description = "InstanceCommunication.FunctionStatus (protobuf JSON format)"))) }) @Path("/{tenant}/{namespace}/{functionName}/status") public Response getFunctionStatus(final @PathParam("tenant") String tenant, @@ -171,14 +183,15 @@ public Response getFunctionStatus(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Lists all Pulsar Functions currently deployed in a given namespace", - response = String.class, - responseContainer = "Collection" + @Operation( + summary = "Lists all Pulsar Functions currently deployed in a given namespace" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions") + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "200", + description = "Lists all Pulsar Functions currently deployed in a given namespace", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))) }) @Path("/{tenant}/{namespace}") public Response listFunctions(final @PathParam("tenant") String tenant, @@ -187,15 +200,17 @@ public Response listFunctions(final @PathParam("tenant") String tenant, } @POST - @ApiOperation( - value = "Triggers a Pulsar Function with a user-specified value or file data", - response = Message.class + @Operation( + summary = "Triggers a Pulsar Function with a user-specified value or file data" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "200", + description = "Triggers a Pulsar Function with a user-specified value or file data", + content = @Content(schema = @Schema(implementation = Message.class))) }) @Path("/{tenant}/{namespace}/{functionName}/trigger") @Consumes(MediaType.MULTIPART_FORM_DATA) @@ -210,15 +225,17 @@ public Response triggerFunction(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Fetch the current state associated with a Pulsar Function", - response = String.class + @Operation( + summary = "Fetch the current state associated with a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The key does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The key does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "200", + description = "Fetch the current state associated with a Pulsar Function", + content = @Content(schema = @Schema(implementation = String.class))) }) @Path("/{tenant}/{namespace}/{functionName}/state/{key}") public Response getFunctionState(final @PathParam("tenant") String tenant, @@ -229,12 +246,15 @@ public Response getFunctionState(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart function instance", response = Void.class) + @Operation(summary = "Restart function instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "200", description = "Restart function instance", + content = @Content(schema = @Schema(implementation = Void.class)))}) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) public Response restartFunction(final @PathParam("tenant") String tenant, @@ -246,10 +266,12 @@ public Response restartFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart all function instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Restart all function instances") + @ApiResponses(value = {@ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "200", description = "Restart all function instances", + content = @Content(schema = @Schema(implementation = Void.class)))}) @Path("/{tenant}/{namespace}/{functionName}/restart") @Consumes(MediaType.APPLICATION_JSON) public Response restartFunction(final @PathParam("tenant") String tenant, @@ -259,10 +281,12 @@ public Response restartFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop function instance", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Stop function instance") + @ApiResponses(value = {@ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "200", description = "Stop function instance", + content = @Content(schema = @Schema(implementation = Void.class)))}) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) public Response stopFunction(final @PathParam("tenant") String tenant, @@ -274,10 +298,12 @@ public Response stopFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop all function instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Stop all function instances") + @ApiResponses(value = {@ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "200", description = "Stop all function instances", + content = @Content(schema = @Schema(implementation = Void.class)))}) @Path("/{tenant}/{namespace}/{functionName}/stop") @Consumes(MediaType.APPLICATION_JSON) public Response stopFunction(final @PathParam("tenant") String tenant, @@ -287,8 +313,8 @@ public Response stopFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation( - value = "Uploads Pulsar Function file data (admin only)", + @Operation( + summary = "Uploads Pulsar Function file data (admin only)", hidden = true ) @Path("/upload") @@ -299,8 +325,8 @@ public Response uploadFunction(final @FormDataParam("data") InputStream uploaded } @GET - @ApiOperation( - value = "Downloads Pulsar Function file data (admin only)", + @Operation( + summary = "Downloads Pulsar Function file data (admin only)", hidden = true ) @Path("/download") @@ -312,14 +338,16 @@ public Response downloadFunction(final @QueryParam("path") String path) { * Deprecated in favor of moving endpoint to {@link org.apache.pulsar.broker.admin.v2.Worker}. */ @GET - @ApiOperation( - value = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", - response = List.class + @Operation( + summary = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "200", + description = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", + content = @Content(schema = @Schema(implementation = List.class))) }) @Path("/connectors") @Deprecated diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerApiV2Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerApiV2Resource.java index cd94ce528411d..535de4a1c9fc9 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerApiV2Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerApiV2Resource.java @@ -18,10 +18,13 @@ */ package org.apache.pulsar.functions.worker.rest.api.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Consumes; @@ -54,7 +57,7 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @SuppressWarnings("deprecation") -@Api(value = "/worker", description = "Workers admin api", tags = "workers") +@Tag(name = "workers", description = "Workers admin api") public class WorkerApiV2Resource implements Supplier { public static final String ATTRIBUTE_WORKER_SERVICE = "worker"; @@ -99,14 +102,15 @@ public AuthenticationParameters authParams() { } @GET - @ApiOperation( - value = "Fetches information about the Pulsar cluster running Pulsar Functions", - response = WorkerInfo.class, - responseContainer = "List" + @Operation( + summary = "Fetches information about the Pulsar cluster running Pulsar Functions" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Fetches information about the Pulsar cluster running Pulsar Functions", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = WorkerInfo.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/cluster") @Produces(MediaType.APPLICATION_JSON) @@ -115,13 +119,15 @@ public List getCluster() { } @GET - @ApiOperation( - value = "Fetches info about the leader node of the Pulsar cluster running Pulsar Functions", - response = WorkerInfo.class + @Operation( + summary = "Fetches info about the leader node of the Pulsar cluster running Pulsar Functions" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Fetches info about the leader node of the Pulsar cluster running Pulsar Functions", + content = @Content(schema = @Schema(implementation = WorkerInfo.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/cluster/leader") @Produces(MediaType.APPLICATION_JSON) @@ -130,13 +136,16 @@ public WorkerInfo getClusterLeader() { } @GET - @ApiOperation( - value = "Fetches information about which Pulsar Functions are assigned to which Pulsar clusters", - response = Map.class + @Operation( + summary = "Fetches information about which Pulsar Functions are assigned to which Pulsar clusters" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Fetches information about which Pulsar Functions are assigned to which Pulsar" + + " clusters", + content = @Content(schema = @Schema(implementation = Map.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/assignments") @Produces(MediaType.APPLICATION_JSON) @@ -145,14 +154,16 @@ public Map> getAssignments() { } @GET - @ApiOperation( - value = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", - response = List.class + @Operation( + summary = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", + description = "Fetches a list of supported Pulsar IO connectors currently running in cluster mode", + content = @Content(schema = @Schema(implementation = List.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/connectors") public List getConnectorsList() throws IOException { @@ -160,13 +171,13 @@ public List getConnectorsList() throws IOException { } @PUT - @ApiOperation( - value = "Triggers a rebalance of functions to workers" + @Operation( + summary = "Triggers a rebalance of functions to workers" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/rebalance") public void rebalance() { @@ -174,15 +185,15 @@ public void rebalance() { } @PUT - @ApiOperation( - value = "Drains the specified worker, i.e., moves its work-assignments to other workers" + @Operation( + summary = "Drains the specified worker, i.e., moves its work-assignments to other workers" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 409, message = "Drain already in progress"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "409", description = "Drain already in progress"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/leader/drain") public void drainAtLeader(@QueryParam("workerId") String workerId) { @@ -190,15 +201,15 @@ public void drainAtLeader(@QueryParam("workerId") String workerId) { } @PUT - @ApiOperation( - value = "Drains this worker, i.e., moves its work-assignments to other workers" + @Operation( + summary = "Drains this worker, i.e., moves its work-assignments to other workers" ) @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 408, message = "Request timeout"), - @ApiResponse(code = 409, message = "Drain already in progress"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "408", description = "Request timeout"), + @ApiResponse(responseCode = "409", description = "Drain already in progress"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/drain") public void drain() { @@ -206,13 +217,15 @@ public void drain() { } @GET - @ApiOperation( - value = "Get the status of the drain operation for the specified worker", - response = LongRunningProcessStatus.class + @Operation( + summary = "Get the status of the drain operation for the specified worker" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "200", + description = "Get the status of the drain operation for the specified worker", + content = @Content(schema = @Schema(implementation = LongRunningProcessStatus.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/leader/drain") public LongRunningProcessStatus getDrainStatus(@QueryParam("workerId") String workerId) { @@ -220,13 +233,15 @@ public LongRunningProcessStatus getDrainStatus(@QueryParam("workerId") String wo } @GET - @ApiOperation( - value = "Get the status of the drain operation of this worker", - response = LongRunningProcessStatus.class + @Operation( + summary = "Get the status of the drain operation of this worker" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 503, message = "Worker service is not ready") + @ApiResponse(responseCode = "200", + description = "Get the status of the drain operation of this worker", + content = @Content(schema = @Schema(implementation = LongRunningProcessStatus.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "503", description = "Worker service is not ready") }) @Path("/drain") public LongRunningProcessStatus getDrainStatus() { @@ -234,12 +249,14 @@ public LongRunningProcessStatus getDrainStatus() { } @GET - @ApiOperation( - value = "Checks if this node is the leader and is ready to service requests", - response = Boolean.class + @Operation( + summary = "Checks if this node is the leader and is ready to service requests" ) @ApiResponses(value = { - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", + description = "Checks if this node is the leader and is ready to service requests", + content = @Content(schema = @Schema(implementation = Boolean.class))), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Path("/cluster/leader/ready") public Boolean isLeaderReady() { diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java index 571d817630393..ad257ecc1bf0d 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java @@ -18,10 +18,13 @@ */ package org.apache.pulsar.functions.worker.rest.api.v2; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Consumes; @@ -47,7 +50,7 @@ @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @SuppressWarnings("deprecation") -@Api(value = "/worker-stats", description = "Workers stats api", tags = "workers-stats") +@Tag(name = "workers-stats", description = "Workers stats api") public class WorkerStatsApiV2Resource implements Supplier { public static final String ATTRIBUTE_WORKERSTATS_SERVICE = "worker-stats"; @@ -91,14 +94,15 @@ public String clientAppId() { @GET @Path("/metrics") - @ApiOperation( - value = "Gets the metrics for Monitoring", - notes = "Request should be executed by Monitoring agent on each worker to fetch the worker-metrics", - response = org.apache.pulsar.common.stats.Metrics.class, - responseContainer = "List") + @Operation( + summary = "Gets the metrics for Monitoring", + description = "Request should be executed by Monitoring agent on each worker to fetch the worker-metrics") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", + content = @Content(array = @ArraySchema(schema = + @Schema(implementation = org.apache.pulsar.common.stats.Metrics.class)))), + @ApiResponse(responseCode = "401", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Produces(MediaType.APPLICATION_JSON) public List getMetrics() throws Exception { @@ -107,14 +111,15 @@ public List getMetrics() throws Exceptio @GET @Path("/functionsmetrics") - @ApiOperation( - value = "Get metrics for all functions owned by worker", - notes = "Requested should be executed by Monitoring agent on each worker to fetch the metrics", - response = WorkerFunctionInstanceStats.class, - responseContainer = "List") + @Operation( + summary = "Get metrics for all functions owned by worker", + description = "Requested should be executed by Monitoring agent on each worker to fetch the metrics") @ApiResponses(value = { - @ApiResponse(code = 401, message = "Don't have admin permission"), - @ApiResponse(code = 503, message = "Worker service is not running") + @ApiResponse(responseCode = "200", description = "Get metrics for all functions owned by worker", + content = @Content(array = @ArraySchema(schema = + @Schema(implementation = WorkerFunctionInstanceStats.class)))), + @ApiResponse(responseCode = "401", description = "Don't have admin permission"), + @ApiResponse(responseCode = "503", description = "Worker service is not running") }) @Produces(MediaType.APPLICATION_JSON) public List getStats() throws IOException { diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/FunctionsApiV3Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/FunctionsApiV3Resource.java index e1856c451189e..25b850e999ee0 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/FunctionsApiV3Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/FunctionsApiV3Resource.java @@ -18,10 +18,13 @@ */ package org.apache.pulsar.functions.worker.rest.api.v3; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -119,15 +122,18 @@ public List listFunctions(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function instance", - response = FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData.class + @Operation( + summary = "Displays the status of a Pulsar Function instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Function instance", + content = @Content(schema = @Schema( + implementation = FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/status") @@ -141,15 +147,17 @@ public FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData getFunct } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Function", - response = FunctionStatus.class + @Operation( + summary = "Displays the status of a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Function", + content = @Content(schema = @Schema(implementation = FunctionStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/status") @@ -162,15 +170,17 @@ public FunctionStatus getFunctionStatus( } @GET - @ApiOperation( - value = "Displays the stats of a Pulsar Function", - response = FunctionStatsImpl.class + @Operation( + summary = "Displays the stats of a Pulsar Function" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the stats of a Pulsar Function", + content = @Content(schema = @Schema(implementation = FunctionStatsImpl.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/stats") @@ -182,15 +192,17 @@ public FunctionStatsImpl getFunctionStats(final @PathParam("tenant") String tena } @GET - @ApiOperation( - value = "Displays the stats of a Pulsar Function instance", - response = FunctionInstanceStatsDataImpl.class + @Operation( + summary = "Displays the stats of a Pulsar Function instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The function doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the stats of a Pulsar Function instance", + content = @Content(schema = @Schema(implementation = FunctionInstanceStatsDataImpl.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The function doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/stats") @@ -217,12 +229,15 @@ public String triggerFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart function instance", response = Void.class) + @Operation(summary = "Restart function instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this function"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Restart function instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this function"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) @@ -235,11 +250,13 @@ public void restartFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart all function instances", response = Void.class) + @Operation(summary = "Restart all function instances") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Restart all function instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/restart") @Consumes(MediaType.APPLICATION_JSON) @@ -250,11 +267,13 @@ public void restartFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop function instance", response = Void.class) + @Operation(summary = "Stop function instance") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Stop function instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) @@ -267,11 +286,13 @@ public void stopFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop all function instances", response = Void.class) + @Operation(summary = "Stop all function instances") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Stop all function instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/stop") @Consumes(MediaType.APPLICATION_JSON) @@ -282,11 +303,13 @@ public void stopFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Start function instance", response = Void.class) + @Operation(summary = "Start function instance") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Start function instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/{instanceId}/start") @Consumes(MediaType.APPLICATION_JSON) @@ -299,11 +322,13 @@ public void startFunction(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Start all function instances", response = Void.class) + @Operation(summary = "Start all function instances") @ApiResponses(value = { - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", description = "Start all function instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{functionName}/start") @Consumes(MediaType.APPLICATION_JSON) @@ -328,19 +353,19 @@ public StreamingOutput downloadFunction(final @QueryParam("path") String path) { } @GET - @ApiOperation( - value = "Downloads Pulsar Function file data", + @Operation( + summary = "Downloads Pulsar Function file data", hidden = true ) @Path("/{tenant}/{namespace}/{functionName}/download") public StreamingOutput downloadFunction( - @ApiParam(value = "The tenant of functions") + @Parameter(description = "The tenant of functions") final @PathParam("tenant") String tenant, - @ApiParam(value = "The namespace of functions") + @Parameter(description = "The namespace of functions") final @PathParam("namespace") String namespace, - @ApiParam(value = "The name of functions") + @Parameter(description = "The name of functions") final @PathParam("functionName") String functionName, - @ApiParam(value = "Whether to download the transform function") + @Parameter(description = "Whether to download the transform function") final @QueryParam("transform-function") boolean transformFunction) { return functions() @@ -358,13 +383,14 @@ public List getConnectorsList() throws IOException { } @POST - @ApiOperation( - value = "Reload the built-in Functions" + @Operation( + summary = "Reload the built-in Functions" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/builtins/reload") public void reloadBuiltinFunctions() throws IOException { @@ -372,15 +398,15 @@ public void reloadBuiltinFunctions() throws IOException { } @GET - @ApiOperation( - value = "Fetches the list of built-in Pulsar functions", - response = FunctionDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches the list of built-in Pulsar functions" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", description = "Fetches the list of built-in Pulsar functions", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = FunctionDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Path("/builtins") @Produces(MediaType.APPLICATION_JSON) @@ -409,13 +435,13 @@ public void putFunctionState(final @PathParam("tenant") String tenant, } @PUT - @ApiOperation(value = "Updates a Pulsar Function on the worker leader", hidden = true) + @Operation(summary = "Updates a Pulsar Function on the worker leader", hidden = true) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have super-user permissions"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 307, message = "Redirecting to the worker leader"), - @ApiResponse(code = 200, message = "Pulsar Function successfully updated") + @ApiResponse(responseCode = "403", description = "The requester doesn't have super-user permissions"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "307", description = "Redirecting to the worker leader"), + @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated") }) @Path("/leader/{tenant}/{namespace}/{functionName}") @Consumes(MediaType.MULTIPART_FORM_DATA) diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinkApiV3Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinkApiV3Resource.java index 5d088fdb44716..dc2c531301447 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinkApiV3Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinkApiV3Resource.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.functions.worker.rest.api.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -27,7 +27,7 @@ /** * @deprecated in favor of {@link SinksApiV3Resource} */ -@Api(value = "/sink", description = "Sink admin apis", tags = "sink") +@Tag(name = "sink", description = "Sink admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("/sink") diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinksApiV3Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinksApiV3Resource.java index bdef639a491f8..61e47b0ed4943 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinksApiV3Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SinksApiV3Resource.java @@ -18,11 +18,14 @@ */ package org.apache.pulsar.functions.worker.rest.api.v3; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -49,7 +52,7 @@ @CustomLog @SuppressWarnings("deprecation") -@Api(value = "/sinks", description = "Sinks admin apis", tags = "sinks") +@Tag(name = "sinks", description = "Sinks admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("/sinks") @@ -108,15 +111,16 @@ public SinkConfig getSinkInfo(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Sink instance", - response = SinkStatus.SinkInstanceStatus.SinkInstanceStatusData.class - ) + @Operation(summary = "Displays the status of a Pulsar Sink instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this sink"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The sink doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Sink instance", + content = @Content(schema = + @Schema(implementation = SinkStatus.SinkInstanceStatus.SinkInstanceStatusData.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this sink"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The sink doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/status") @@ -130,15 +134,16 @@ public SinkStatus.SinkInstanceStatus.SinkInstanceStatusData getSinkInstanceStatu } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Sink running in cluster mode", - response = SinkStatus.class - ) + @Operation(summary = "Displays the status of a Pulsar Sink running in cluster mode") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this sink"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The sink doesn't exist") + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Sink running in cluster mode", + content = @Content(schema = @Schema(implementation = SinkStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this sink"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The sink doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sinkName}/status") @@ -156,12 +161,14 @@ public List listSink(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart sink instance", response = Void.class) + @Operation(summary = "Restart sink instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this sink"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") }) + @ApiResponse(responseCode = "200", description = "Restart sink instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this sink"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartSink(final @PathParam("tenant") String tenant, @@ -173,10 +180,13 @@ public void restartSink(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart all sink instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Restart all sink instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Restart all sink instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sinkName}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartSink(final @PathParam("tenant") String tenant, @@ -186,10 +196,13 @@ public void restartSink(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop sink instance", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Stop sink instance") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Stop sink instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopSink(final @PathParam("tenant") String tenant, @@ -201,10 +214,13 @@ public void stopSink(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop all sink instances", response = Void.class) - @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") }) + @Operation(summary = "Stop all sink instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Stop all sink instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{sinkName}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopSink(final @PathParam("tenant") String tenant, @@ -214,10 +230,13 @@ public void stopSink(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Start sink instance", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Start sink instance") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Start sink instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sinkName}/{instanceId}/start") @Consumes(MediaType.APPLICATION_JSON) public void startSink(final @PathParam("tenant") String tenant, @@ -229,10 +248,13 @@ public void startSink(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Start all sink instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Start all sink instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Start all sink instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sinkName}/start") @Consumes(MediaType.APPLICATION_JSON) public void startSink(final @PathParam("tenant") String tenant, @@ -248,33 +270,37 @@ public List getSinkList() { } @GET - @ApiOperation( - value = "Fetches information about config fields associated with the specified builtin sink", - response = ConfigFieldDefinition.class, - responseContainer = "List" - ) + @Operation( + summary = "Fetches information about config fields associated with the specified builtin sink") @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "builtin sink does not exist"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Fetches information about config fields associated with the specified builtin sink", + content = @Content(array = + @ArraySchema(schema = @Schema(implementation = ConfigFieldDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "builtin sink does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/builtinsinks/{name}/configdefinition") public List getSinkConfigDefinition( - @ApiParam(value = "The name of the builtin sink") final @PathParam("name") String name) throws IOException { + @Parameter(description = "The name of the builtin sink") + final @PathParam("name") String name) throws IOException { return sinks().getSinkConfigDefinition(name); } @POST - @ApiOperation( - value = "Reload the built-in connectors, including Sources and Sinks", - response = Void.class - ) + @Operation(summary = "Reload the built-in connectors, including Sources and Sinks") @ApiResponses(value = { - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Reload the built-in connectors, including Sources and Sinks", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/reloadBuiltInSinks") public void reloadSinks() { diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourceApiV3Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourceApiV3Resource.java index 53b15d449c4d3..e9dc853e40892 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourceApiV3Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourceApiV3Resource.java @@ -18,7 +18,7 @@ */ package org.apache.pulsar.functions.worker.rest.api.v3; -import io.swagger.annotations.Api; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; @@ -28,7 +28,7 @@ * @deprecated in favor of {@link SourcesApiV3Resource} */ @Path("/source") -@Api(value = "/source", description = "Source admin apis", tags = "source") +@Tag(name = "source", description = "Source admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Deprecated diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourcesApiV3Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourcesApiV3Resource.java index 80debc870d256..36cdd7d09c65b 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourcesApiV3Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v3/SourcesApiV3Resource.java @@ -18,11 +18,14 @@ */ package org.apache.pulsar.functions.worker.rest.api.v3; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -49,7 +52,7 @@ @CustomLog @SuppressWarnings("deprecation") -@Api(value = "/sources", description = "Sources admin apis", tags = "sources") +@Tag(name = "sources", description = "Sources admin apis") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("/sources") @@ -111,15 +114,18 @@ public SourceConfig getSourceInfo(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Source instance", - response = SourceStatus.SourceInstanceStatus.SourceInstanceStatusData.class + @Operation( + summary = "Displays the status of a Pulsar Source instance" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this source"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The source doesn't exist") + @ApiResponse(responseCode = "200", description = "Displays the status of a Pulsar Source instance", + content = @Content(schema = @Schema( + implementation = SourceStatus.SourceInstanceStatus.SourceInstanceStatusData.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this source"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The source doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/status") @@ -133,15 +139,18 @@ public SourceStatus.SourceInstanceStatus.SourceInstanceStatusData getSourceInsta } @GET - @ApiOperation( - value = "Displays the status of a Pulsar Source running in cluster mode", - response = SourceStatus.class + @Operation( + summary = "Displays the status of a Pulsar Source running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this source"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "The source doesn't exist") + @ApiResponse(responseCode = "200", + description = "Displays the status of a Pulsar Source running in cluster mode", + content = @Content(schema = @Schema(implementation = SourceStatus.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this source"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "The source doesn't exist") }) @Produces(MediaType.APPLICATION_JSON) @Path("/{tenant}/{namespace}/{sourceName}/status") @@ -161,12 +170,15 @@ public List listSources(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart source instance", response = Void.class) + @Operation(summary = "Restart source instance") @ApiResponses(value = { - @ApiResponse(code = 307, message = "Current broker doesn't serve the namespace of this source"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @ApiResponse(responseCode = "200", description = "Restart source instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "307", + description = "Current broker doesn't serve the namespace of this source"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartSource(final @PathParam("tenant") String tenant, @@ -178,10 +190,13 @@ public void restartSource(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Restart all source instances", response = Void.class) - @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error") }) + @Operation(summary = "Restart all source instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Restart all source instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/{tenant}/{namespace}/{sourceName}/restart") @Consumes(MediaType.APPLICATION_JSON) public void restartSource(final @PathParam("tenant") String tenant, @@ -191,10 +206,13 @@ public void restartSource(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop source instance", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Stop source instance") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Stop source instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopSource(final @PathParam("tenant") String tenant, @@ -206,10 +224,13 @@ public void stopSource(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Stop all source instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Stop all source instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Stop all source instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sourceName}/stop") @Consumes(MediaType.APPLICATION_JSON) public void stopSource(final @PathParam("tenant") String tenant, @@ -219,10 +240,13 @@ public void stopSource(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Start source instance", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Start source instance") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Start source instance", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sourceName}/{instanceId}/start") @Consumes(MediaType.APPLICATION_JSON) public void startSource(final @PathParam("tenant") String tenant, @@ -234,10 +258,13 @@ public void startSource(final @PathParam("tenant") String tenant, } @POST - @ApiOperation(value = "Start all source instances", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 404, message = "The function does not exist"), - @ApiResponse(code = 500, message = "Internal server error")}) + @Operation(summary = "Start all source instances") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Start all source instances", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "404", description = "The function does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) @Path("/{tenant}/{namespace}/{sourceName}/start") @Consumes(MediaType.APPLICATION_JSON) public void startSource(final @PathParam("tenant") String tenant, @@ -247,14 +274,17 @@ public void startSource(final @PathParam("tenant") String tenant, } @GET - @ApiOperation( - value = "Fetches a list of supported Pulsar IO source connectors currently running in cluster mode", - response = List.class + @Operation( + summary = "Fetches a list of supported Pulsar IO source connectors currently running in cluster mode" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 400, message = "Invalid request"), - @ApiResponse(code = 408, message = "Request timeout") + @ApiResponse(responseCode = "200", + description = "Fetches a list of supported Pulsar IO source connectors currently " + + "running in cluster mode", + content = @Content(schema = @Schema(implementation = List.class))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "400", description = "Invalid request"), + @ApiResponse(responseCode = "408", description = "Request timeout") }) @Produces(MediaType.APPLICATION_JSON) @Path("/builtinsources") @@ -263,34 +293,41 @@ public List getSourceList() { } @GET - @ApiOperation( - value = "Fetches information about config fields associated with the specified builtin source", - response = ConfigFieldDefinition.class, - responseContainer = "List" + @Operation( + summary = "Fetches information about config fields associated with the specified builtin source" ) @ApiResponses(value = { - @ApiResponse(code = 403, message = "The requester doesn't have admin permissions"), - @ApiResponse(code = 404, message = "builtin source does not exist"), - @ApiResponse(code = 500, message = "Internal server error"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later.") + @ApiResponse(responseCode = "200", + description = "Fetches information about config fields associated with the specified " + + "builtin source", + content = @Content(array = @ArraySchema( + schema = @Schema(implementation = ConfigFieldDefinition.class)))), + @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), + @ApiResponse(responseCode = "404", description = "builtin source does not exist"), + @ApiResponse(responseCode = "500", description = "Internal server error"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later.") }) @Produces(MediaType.APPLICATION_JSON) @Path("/builtinsources/{name}/configdefinition") public List getSourceConfigDefinition( - @ApiParam(value = "The name of the builtin source") final @PathParam("name") String name) + @Parameter(description = "The name of the builtin source") final @PathParam("name") String name) throws IOException { return sources().getSourceConfigDefinition(name); } @POST - @ApiOperation( - value = "Reload the built-in connectors, including Sources and Sinks", - response = Void.class + @Operation( + summary = "Reload the built-in connectors, including Sources and Sinks" ) @ApiResponses(value = { - @ApiResponse(code = 401, message = "This operation requires super-user access"), - @ApiResponse(code = 503, message = "Function worker service is now initializing. Please try again later."), - @ApiResponse(code = 500, message = "Internal server error") + @ApiResponse(responseCode = "200", + description = "Reload the built-in connectors, including Sources and Sinks", + content = @Content(schema = @Schema(implementation = Void.class))), + @ApiResponse(responseCode = "401", description = "This operation requires super-user access"), + @ApiResponse(responseCode = "503", + description = "Function worker service is now initializing. Please try again later."), + @ApiResponse(responseCode = "500", description = "Internal server error") }) @Path("/reloadBuiltInSources") public void reloadSources() { diff --git a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java index 3fbf702bdcb2b..a9c9dd2b2111d 100644 --- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java +++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java @@ -20,10 +20,14 @@ import static java.util.concurrent.TimeUnit.SECONDS; import io.netty.channel.Channel; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.GET; @@ -48,7 +52,8 @@ @CustomLog @Path("/") -@Api(value = "/proxy-stats", description = "Stats for proxy", tags = "proxy-stats", hidden = true) +@Tag(name = "proxy-stats", description = "Stats for proxy") +@Hidden @Produces(MediaType.APPLICATION_JSON) @SuppressWarnings("deprecation") public class ProxyStats { @@ -63,9 +68,11 @@ public class ProxyStats { @GET @Path("/connections") - @ApiOperation(value = "Proxy stats api to get info for live connections", - response = List.class, responseContainer = "List") - @ApiResponses(value = { @ApiResponse(code = 503, message = "Proxy service is not initialized") }) + @Operation(summary = "Proxy stats api to get info for live connections") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Proxy stats api to get info for live connections", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = List.class)))), + @ApiResponse(responseCode = "503", description = "Proxy service is not initialized") }) public List metrics() { throwIfNotSuperUser("metrics"); List stats = new ArrayList<>(); @@ -84,9 +91,13 @@ public List metrics() { @GET @Path("/topics") - @ApiOperation(value = "Proxy topic stats api", response = Map.class, responseContainer = "Map") - @ApiResponses(value = { @ApiResponse(code = 412, message = "Proxy logging should be > 2 to capture topic stats"), - @ApiResponse(code = 503, message = "Proxy service is not initialized") }) + @Operation(summary = "Proxy topic stats api") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Proxy topic stats api", + content = @Content(schema = @Schema(type = "object"), + additionalPropertiesSchema = @Schema(implementation = Map.class))), + @ApiResponse(responseCode = "412", description = "Proxy logging should be > 2 to capture topic stats"), + @ApiResponse(responseCode = "503", description = "Proxy service is not initialized") }) public Map topics() { throwIfNotSuperUser("topics"); Optional logLevel = proxyService().getConfiguration().getProxyLogLevel(); @@ -98,9 +109,9 @@ public Map topics() { @POST @Path("/logging/{logLevel}") - @ApiOperation(hidden = true, value = "Change proxy logging level dynamically", - notes = "It only changes log-level in memory, change it config file to persist the change") - @ApiResponses(value = { @ApiResponse(code = 412, message = "Proxy log level can be [0-2]"), }) + @Operation(hidden = true, summary = "Change proxy logging level dynamically", + description = "It only changes log-level in memory, change it config file to persist the change") + @ApiResponses(value = { @ApiResponse(responseCode = "412", description = "Proxy log level can be [0-2]"), }) public void updateProxyLogLevel(@PathParam("logLevel") int logLevel) { throwIfNotSuperUser("updateProxyLogLevel"); if (logLevel < 0 || logLevel > 2) { @@ -111,7 +122,7 @@ public void updateProxyLogLevel(@PathParam("logLevel") int logLevel) { @GET @Path("/logging") - @ApiOperation(hidden = true, value = "Get proxy logging") + @Operation(hidden = true, summary = "Get proxy logging") public int getProxyLogLevel(@PathParam("logLevel") int logLevel) { throwIfNotSuperUser("getProxyLogLevel"); return proxyService().getProxyLogLevel(); diff --git a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/util/CmdGenerateDocumentation.java b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/util/CmdGenerateDocumentation.java index 2ca3785eb9ac8..bf0111e50d3b5 100644 --- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/util/CmdGenerateDocumentation.java +++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/util/CmdGenerateDocumentation.java @@ -39,15 +39,15 @@ public String generateDocumentByClassName(String className) throws Exception { } else if (ServiceConfiguration.class.getName().equals(className)) { return generateDocByFieldContext(className, "Broker"); } else if (ClientConfigurationData.class.getName().equals(className)) { - return generateDocByApiModelProperty(className, "Client"); + return generateDocBySchema(className, "Client"); } else if (WebSocketProxyConfiguration.class.getName().equals(className)) { return generateDocByFieldContext(className, "WebSocket"); } else if (ProducerConfigurationData.class.getName().equals(className)) { - return generateDocByApiModelProperty(className, "Producer"); + return generateDocBySchema(className, "Producer"); } else if (ConsumerConfigurationData.class.getName().equals(className)) { - return generateDocByApiModelProperty(className, "Consumer"); + return generateDocBySchema(className, "Consumer"); } else if (ReaderConfigurationData.class.getName().equals(className)) { - return generateDocByApiModelProperty(className, "Reader"); + return generateDocBySchema(className, "Reader"); } else { return "Class [" + className + "] not found"; } diff --git a/pulsar-websocket/build.gradle.kts b/pulsar-websocket/build.gradle.kts index 40b322787c468..aae83d0db43c9 100644 --- a/pulsar-websocket/build.gradle.kts +++ b/pulsar-websocket/build.gradle.kts @@ -28,6 +28,8 @@ dependencies { implementation(project(":pulsar-client-original")) implementation(project(":pulsar-docs-tools")) implementation(libs.commons.lang3) + // guava was previously leaked onto the compile classpath via compileOnly(swagger-core 1.x) + implementation(libs.guava) implementation(libs.jersey.container.servlet.core) implementation(libs.jersey.container.servlet) implementation(libs.jersey.hk2) @@ -47,8 +49,7 @@ dependencies { implementation(libs.netty.common) implementation(libs.netty.buffer) - compileOnly(libs.swagger.core) + compileOnly(libs.swagger.annotations) - testImplementation(libs.guava) testImplementation(libs.netty.transport.native.epoll) } diff --git a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java index 3435ec6210400..b15f1e523b06a 100644 --- a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java +++ b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java @@ -19,10 +19,13 @@ package org.apache.pulsar.websocket.admin.v2; import static org.apache.pulsar.common.util.Codec.decode; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.Encoded; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @@ -37,25 +40,26 @@ import org.apache.pulsar.websocket.stats.ProxyTopicStat; @Path("/proxy-stats") -@Api(value = "/proxy", description = "Stats for web-socket proxy", tags = "proxy-stats") +@Tag(name = "proxy-stats", description = "Stats for web-socket proxy") @Produces(MediaType.APPLICATION_JSON) -@SuppressWarnings("deprecation") public class WebSocketProxyStatsV2 extends WebSocketProxyStatsBase { @GET @Path("/metrics") - @ApiOperation(value = "Gets the metrics for Monitoring", - notes = "Requested should be executed by Monitoring agent on each proxy to fetch the metrics", - response = Metrics.class, responseContainer = "List") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Gets the metrics for Monitoring", + description = "Requested should be executed by Monitoring agent on each proxy to fetch the metrics") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Metrics.class)))), + @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public Collection internalGetMetrics() throws Exception { return super.internalGetMetrics(); } @GET @Path("/{domain}/{tenant}/{namespace}/{topic}/stats") - @ApiOperation(value = "Get the stats for the topic.") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission"), - @ApiResponse(code = 404, message = "Topic does not exist") }) + @Operation(summary = "Get the stats for the topic.") + @ApiResponses(value = { @ApiResponse(responseCode = "403", description = "Don't have admin permission"), + @ApiResponse(responseCode = "404", description = "Topic does not exist") }) public ProxyTopicStat getStats(@PathParam("domain") String domain, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic) { return super.internalGetStats(TopicName.get(domain, tenant, namespace, decode(encodedTopic))); @@ -63,8 +67,8 @@ public ProxyTopicStat getStats(@PathParam("domain") String domain, @PathParam("t @GET @Path("/stats") - @ApiOperation(value = "Get the stats for the topic.") - @ApiResponses(value = { @ApiResponse(code = 403, message = "Don't have admin permission") }) + @Operation(summary = "Get the stats for the topic.") + @ApiResponses(value = { @ApiResponse(responseCode = "403", description = "Don't have admin permission") }) public Map internalGetProxyStats() { return super.internalGetProxyStats(); } diff --git a/tests/integration/build.gradle.kts b/tests/integration/build.gradle.kts index 3749d278564c2..693423e5f0649 100644 --- a/tests/integration/build.gradle.kts +++ b/tests/integration/build.gradle.kts @@ -57,12 +57,16 @@ dependencies { exclude(group = "org.bouncycastle") exclude(group = "javax.annotation", module = "javax.annotation-api") exclude(group = "software.amazon.awssdk") + // Swagger 1.x annotations on the generated k8s models are inert metadata; nothing reads them at runtime + exclude(group = "io.swagger", module = "swagger-annotations") } testImplementation(libs.kubernetes.client.java.api.fluent) { exclude(group = "io.prometheus", module = "simpleclient_httpserver") exclude(group = "org.bouncycastle") exclude(group = "javax.annotation", module = "javax.annotation-api") exclude(group = "software.amazon.awssdk") + // Swagger 1.x annotations on the generated k8s models are inert metadata; nothing reads them at runtime + exclude(group = "io.swagger", module = "swagger-annotations") } } From 93c3ad82a716e36a63927521b058b7c38bb7659c Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Thu, 4 Jun 2026 22:16:15 +0300 Subject: [PATCH 2/5] [improve][misc] Fix typos and whitespace in OpenAPI annotation descriptions Proofreads the summary/description strings of the OpenAPI (Swagger v3) annotations and fixes only clear textual defects, preserving meaning: - Spelling typos: "doesn't exit" -> "doesn't exist" (PersistentTopics, Namespaces, rest Topics), "ect" -> "etc", "sre" -> "are", "serviceconfiguration" -> "ServiceConfiguration", "Requested" -> "Request" (worker stats), "BrokersBase admin apis" -> "Brokers admin apis" (leaked base-class name). - Missing spaces at string-concatenation boundaries, e.g. "at thenamespace level", "tenant orsubscriber", "cluster.If authorization", "thiscall", "will betrimmed", "C++'s[Boost]". - Stray leading spaces in operation summaries (" Set retention...") and doubled spaces mid-sentence. - Missing closing parentheses, e.g. "(if instance-id is not provided, the stats of all instances is returned" and the sink/source parallelism and schema-type descriptions. Awkward-but-correct grammar was intentionally left untouched. Generated documents remain operation-identical with the published 4.2.1 docs (597/597 operations). Assisted-by: Claude Code (Opus 4.8) --- .../pulsar/broker/admin/impl/BrokersBase.java | 10 +-- .../broker/admin/impl/FunctionsBase.java | 14 ++-- .../pulsar/broker/admin/impl/SinksBase.java | 8 +-- .../pulsar/broker/admin/impl/SourcesBase.java | 4 +- .../pulsar/broker/admin/v2/BrokerStats.java | 2 +- .../pulsar/broker/admin/v2/Brokers.java | 2 +- .../pulsar/broker/admin/v2/Namespaces.java | 40 +++++------ .../broker/admin/v2/NonPersistentTopics.java | 2 +- .../broker/admin/v2/PersistentTopics.java | 70 +++++++++---------- .../org/apache/pulsar/broker/rest/Topics.java | 8 +-- .../impl/conf/ClientConfigurationData.java | 12 ++-- .../impl/conf/ConsumerConfigurationData.java | 8 +-- .../impl/conf/ProducerConfigurationData.java | 2 +- .../impl/conf/ReaderConfigurationData.java | 2 +- .../common/policies/data/ClusterDataImpl.java | 4 +- .../common/util/PulsarSslConfiguration.java | 2 +- .../rest/api/v2/WorkerStatsApiV2Resource.java | 2 +- 17 files changed, 96 insertions(+), 96 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java index c2ef621c14cad..c76900ce4df6a 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java @@ -72,12 +72,12 @@ public class BrokersBase extends AdminResource { @GET @Path("/{cluster}") @Operation( - summary = "Get the list of active brokers (broker ids) in the cluster." + summary = "Get the list of active brokers (broker ids) in the cluster. " + "If authorization is not enabled, any cluster name is valid.") @ApiResponses( value = { @ApiResponse(responseCode = "200", - description = "Get the list of active brokers (broker ids) in the cluster." + description = "Get the list of active brokers (broker ids) in the cluster. " + "If authorization is not enabled, any cluster name is valid.", content = @Content(array = @ArraySchema(uniqueItems = true, schema = @Schema(implementation = String.class)))), @@ -111,12 +111,12 @@ public void getActiveBrokers(@Suspended final AsyncResponse asyncResponse, @GET @Operation( - summary = "Get the list of active brokers (broker ids) in the local cluster." + summary = "Get the list of active brokers (broker ids) in the local cluster. " + "If authorization is not enabled") @ApiResponses( value = { @ApiResponse(responseCode = "200", - description = "Get the list of active brokers (broker ids) in the local cluster." + description = "Get the list of active brokers (broker ids) in the local cluster. " + "If authorization is not enabled", content = @Content(array = @ArraySchema(uniqueItems = true, schema = @Schema(implementation = String.class)))), @@ -194,7 +194,7 @@ public void getOwnedNamespaces(@Suspended final AsyncResponse asyncResponse, @POST @Path("/configuration/{configName}/{configValue}") @Operation(summary = - "Update dynamic serviceconfiguration into zk only. This operation requires Pulsar super-user privileges.") + "Update dynamic ServiceConfiguration into zk only. This operation requires Pulsar super-user privileges.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Service configuration updated successfully"), @ApiResponse(responseCode = "403", diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java index ad6a9c0eb92fa..11ee194539430 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java @@ -144,7 +144,7 @@ public void registerFunction( + "- **retainOrdering**\n" + " Function consumes and processes messages in order.\n" + "- **outputSchemaType**\n" - + " Represents either a builtin schema type (for example: 'avro', 'json', ect)" + + " Represents either a builtin schema type (for example: 'avro', 'json', etc)" + " or the class name for a Schema implementation." + "- **subName**\n" + " Pulsar source subscription name. User can specify a subscription-name" @@ -255,7 +255,7 @@ public void updateFunction( + "- **retainOrdering**\n" + " Function consumes and processes messages in order.\n" + "- **outputSchemaType**\n" - + " Represents either a builtin schema type (for example: 'avro', 'json', ect)" + + " Represents either a builtin schema type (for example: 'avro', 'json', etc)" + " or the class name for a Schema implementation." + "- **subName**\n" + " Pulsar source subscription name. User can specify" @@ -356,7 +356,7 @@ public FunctionStatus.FunctionInstanceStatus.FunctionInstanceStatusData getFunct @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, @Parameter(description = "The instanceId of a Pulsar Function (if instance-id is not provided," - + " the stats of all instances is returned") final @PathParam("instanceId") + + " the stats of all instances is returned)") final @PathParam("instanceId") String instanceId) throws IOException { return functions().getFunctionInstanceStatus(tenant, namespace, functionName, instanceId, uri.getRequestUri(), authParams()); @@ -436,7 +436,7 @@ public FunctionInstanceStatsDataImpl getFunctionInstanceStats( @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, @Parameter(description = "The instanceId of a Pulsar Function" - + " (if instance-id is not provided, the stats of all instances is returned") final @PathParam( + + " (if instance-id is not provided, the stats of all instances is returned)") final @PathParam( "instanceId") String instanceId) throws IOException { return functions().getFunctionsInstanceStats(tenant, namespace, functionName, instanceId, uri.getRequestUri(), authParams()); @@ -560,7 +560,7 @@ public void restartFunction( @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, @Parameter(description = - "The instanceId of a Pulsar Function (if instance-id is not provided, all instances are restarted") + "The instanceId of a Pulsar Function (if instance-id is not provided, all instances are restarted)") final @PathParam("instanceId") String instanceId) { functions().restartFunctionInstance(tenant, namespace, functionName, instanceId, uri.getRequestUri(), authParams()); @@ -603,7 +603,7 @@ public void stopFunction( @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, @Parameter(description = - "The instanceId of a Pulsar Function (if instance-id is not provided, all instances are stopped. ") + "The instanceId of a Pulsar Function (if instance-id is not provided, all instances are stopped.)") final @PathParam("instanceId") String instanceId) { functions().stopFunctionInstance(tenant, namespace, functionName, instanceId, uri.getRequestUri(), authParams()); @@ -646,7 +646,7 @@ public void startFunction( @Parameter(description = "The name of a Pulsar Function") final @PathParam("functionName") String functionName, @Parameter(description = "The instanceId of a Pulsar Function" - + " (if instance-id is not provided, all instances sre started. ") final @PathParam("instanceId") + + " (if instance-id is not provided, all instances are started.)") final @PathParam("instanceId") String instanceId) { functions().startFunctionInstance(tenant, namespace, functionName, instanceId, uri.getRequestUri(), authParams()); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java index 0f96ca799344e..c3ea336abd903 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java @@ -98,7 +98,7 @@ public void registerSink(@Parameter(description = "The tenant of a Pulsar Sink") + " TopicsPattern to consume from list of topics under a namespace that " + " match the pattern. [input] and [topicsPattern] are mutually " + " exclusive. Add SerDe class name for a pattern in customSerdeInputs " - + " (supported for java fun only)" + + " (supported for java fun only)\n" + "- **topicToSerdeClassName**\n" + " The map of input topics to SerDe class names" + " (specified as a JSON object)\n" @@ -121,7 +121,7 @@ public void registerSink(@Parameter(description = "The tenant of a Pulsar Sink") + " (specified as a JSON object)\n" + "- **parallelism**\n" + " The parallelism factor of a Pulsar Sink" - + " (i.e. the number of a Pulsar Sink instances to run \n" + + " (i.e. the number of a Pulsar Sink instances to run)\n" + "- **processingGuarantees**\n" + " The processing guarantees (aka delivery semantics) applied to" + " the Pulsar Sink. Possible Values: \"ATLEAST_ONCE\"," @@ -214,7 +214,7 @@ public void updateSink(@Parameter(description = "The tenant of a Pulsar Sink") + " TopicsPattern to consume from list of topics under a namespace that " + " match the pattern. [input] and [topicsPattern] are mutually " + " exclusive. Add SerDe class name for a pattern in customSerdeInputs " - + " (supported for java fun only)" + + " (supported for java fun only)\n" + "- **topicToSerdeClassName**\n" + " The map of input topics to" + " SerDe class names (specified as a JSON object)\n" @@ -237,7 +237,7 @@ public void updateSink(@Parameter(description = "The tenant of a Pulsar Sink") + " (specified as a JSON object)\n" + "- **parallelism**\n" + " The parallelism factor of a Pulsar Sink " - + "(i.e. the number of a Pulsar Sink instances to run \n" + + "(i.e. the number of a Pulsar Sink instances to run)\n" + "- **processingGuarantees**\n" + " The processing guarantees (aka delivery semantics) applied to the" + " Pulsar Sink. Possible Values: \"ATLEAST_ONCE\", \"ATMOST_ONCE\"," diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java index 0961d256c18f0..cf44e7e9282f0 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java @@ -93,7 +93,7 @@ public void registerSource( + "- **schemaType**\n" + " The schema type (either a builtin schema like 'avro', 'json', etc.. or " + " custom Schema class name to be used to" - + " encode messages emitted from the Pulsar Source\n" + + " encode messages emitted from the Pulsar Source)\n" + "- **configs**\n" + " Source config key/values\n" + "- **secrets**\n" @@ -160,7 +160,7 @@ public void updateSource( + "- **schemaType**\n" + " The schema type (either a builtin schema like 'avro', 'json', etc.. or " + " custom Schema class name to be used to encode" - + " messages emitted from the Pulsar Source\n" + + " messages emitted from the Pulsar Source)\n" + "- **configs**\n" + " Pulsar Source config key/values\n" + "- **secrets**\n" diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java index c54530b23448b..94edac7a63f7f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/BrokerStats.java @@ -59,7 +59,7 @@ public StreamingOutput getTopics2() throws Exception { @Path("/broker-resource-availability/{tenant}/{namespace}") @Operation(summary = "Broker availability report", description = "This API gives the current broker availability in " - + "percent, each resource percentage usage is calculated and then" + + "percent, each resource percentage usage is calculated and then " + "sum of all of the resource usage percent is called broker-resource-availability" + "

THIS API IS ONLY FOR USE BY TESTING FOR CONFIRMING NAMESPACE ALLOCATION ALGORITHM") @ApiResponses(value = { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java index 12bcd008648a5..3f4712fcedb02 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Brokers.java @@ -25,7 +25,7 @@ import org.apache.pulsar.broker.admin.impl.BrokersBase; @Path("/brokers") -@Tag(name = "brokers", description = "BrokersBase admin apis") +@Tag(name = "brokers", description = "Brokers admin apis") @Produces(MediaType.APPLICATION_JSON) public class Brokers extends BrokersBase { } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java index 9665d8ace1b2b..9d3187323ed36 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java @@ -378,7 +378,7 @@ public void grantPermissionOnNamespace(@Suspended AsyncResponse asyncResponse, @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "500", description = "Internal server error") }) public void grantPermissionsOnTopics(@Suspended final AsyncResponse asyncResponse, List options) { @@ -402,7 +402,7 @@ public void grantPermissionsOnTopics(@Suspended final AsyncResponse asyncRespons @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "500", description = "Internal server error") }) public void revokePermissionsOnTopics(@Suspended final AsyncResponse asyncResponse, List options) { @@ -1005,11 +1005,11 @@ public void getBundlesData(@Suspended final AsyncResponse asyncResponse, @Path("/{tenant}/{namespace}/unload") @Operation(summary = "Unload namespace", description = "Unload an active namespace from the current broker serving it. Performing this operation" - + " will let the brokerremoves all producers, consumers, and connections using this namespace," - + " and close all topics (includingtheir persistent store). During that operation," - + " the namespace is marked as tentatively unavailable until thebroker completes " + + " will let the broker removes all producers, consumers, and connections using this namespace," + + " and close all topics (including their persistent store). During that operation," + + " the namespace is marked as tentatively unavailable until the broker completes " + "the unloading action. This operation requires strictly super user privileges," - + " since it wouldresult in non-persistent message loss and" + + " since it would result in non-persistent message loss and" + " unexpected connection closure to the clients.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @@ -1499,7 +1499,7 @@ public void getBacklogQuotaMap( @POST @Path("/{tenant}/{namespace}/backlogQuota") - @Operation(summary = " Set a backlog quota for all the topics on a namespace.") + @Operation(summary = "Set a backlog quota for all the topics on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -1561,7 +1561,7 @@ public void getRetention(@Suspended final AsyncResponse asyncResponse, @POST @Path("/{tenant}/{namespace}/retention") - @Operation(summary = " Set retention configuration on a namespace.") + @Operation(summary = "Set retention configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -1576,7 +1576,7 @@ public void setRetention(@PathParam("tenant") String tenant, @PathParam("namespa @DELETE @Path("/{tenant}/{namespace}/retention") - @Operation(summary = " Remove retention configuration on a namespace.") + @Operation(summary = "Remove retention configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -1848,7 +1848,7 @@ public void clearNamespaceBundleBacklogForSubscription(@Suspended final AsyncRes @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", - description = "Don't have admin or operate permission on the namespacen"), + description = "Don't have admin or operate permission on the namespace"), @ApiResponse(responseCode = "404", description = "Namespace does not exist") }) public void unsubscribeNamespace(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, @@ -1897,7 +1897,7 @@ public void unsubscribeNamespaceBundle(@Suspended final AsyncResponse asyncRespo @POST @Path("/{tenant}/{namespace}/subscriptionAuthMode") - @Operation(summary = " Set a subscription auth mode for all the topics on a namespace.") + @Operation(summary = "Set a subscription auth mode for all the topics on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2118,7 +2118,7 @@ public void getMaxProducersPerTopic( @POST @Path("/{tenant}/{namespace}/maxProducersPerTopic") - @Operation(summary = " Set maxProducersPerTopic configuration on a namespace.") + @Operation(summary = "Set maxProducersPerTopic configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2215,7 +2215,7 @@ public void getMaxConsumersPerTopic( @POST @Path("/{tenant}/{namespace}/maxConsumersPerTopic") - @Operation(summary = " Set maxConsumersPerTopic configuration on a namespace.") + @Operation(summary = "Set maxConsumersPerTopic configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2272,7 +2272,7 @@ public void getMaxConsumersPerSubscription( @POST @Path("/{tenant}/{namespace}/maxConsumersPerSubscription") - @Operation(summary = " Set maxConsumersPerSubscription configuration on a namespace.") + @Operation(summary = "Set maxConsumersPerSubscription configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2290,7 +2290,7 @@ public void setMaxConsumersPerSubscription(@PathParam("tenant") String tenant, @DELETE @Path("/{tenant}/{namespace}/maxConsumersPerSubscription") - @Operation(summary = " Set maxConsumersPerSubscription configuration on a namespace.") + @Operation(summary = "Set maxConsumersPerSubscription configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2330,7 +2330,7 @@ public void getMaxUnackedMessagesPerConsumer(@Suspended final AsyncResponse asyn @POST @Path("/{tenant}/{namespace}/maxUnackedMessagesPerConsumer") - @Operation(summary = " Set maxConsumersPerTopic configuration on a namespace.") + @Operation(summary = "Set maxConsumersPerTopic configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2388,7 +2388,7 @@ public void getMaxUnackedmessagesPerSubscription( @POST @Path("/{tenant}/{namespace}/maxUnackedMessagesPerSubscription") - @Operation(summary = " Set maxUnackedMessagesPerSubscription configuration on a namespace.") + @Operation(summary = "Set maxUnackedMessagesPerSubscription configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2443,7 +2443,7 @@ public void getMaxSubscriptionsPerTopic(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/maxSubscriptionsPerTopic") - @Operation(summary = " Set maxSubscriptionsPerTopic configuration on a namespace.") + @Operation(summary = "Set maxSubscriptionsPerTopic configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -3040,7 +3040,7 @@ public void setSubscriptionTypesEnabled( @DELETE @Path("/{tenant}/{namespace}/subscriptionTypesEnabled") - @Operation(summary = " Remove subscription types enabled on a namespace.") + @Operation(summary = "Remove subscription types enabled on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Tenant or Namespace does not exist"), @@ -3220,7 +3220,7 @@ public void setOffloadPolicies(@PathParam("tenant") String tenant, @PathParam("n @DELETE @Path("/{tenant}/{namespace}/removeOffloadPolicies") - @Operation(summary = " Set offload configuration on a namespace.") + @Operation(summary = "Set offload configuration on a namespace.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java index 0856d481ced9f..e6046e6932a82 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java @@ -659,7 +659,7 @@ public void removeEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @Parameter(description = "Whether leader broker redirected this" + @Parameter(description = "Whether leader broker redirected this " + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java index 1249e7315c51d..32612277c44da 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java @@ -118,7 +118,7 @@ public class PersistentTopics extends PersistentTopicsBase { @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getList( @@ -159,7 +159,7 @@ public void getList( @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin or operate permission on the namespace"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getPartitionedTopicList( @@ -190,7 +190,7 @@ public void getPartitionedTopicList( @Path("/{tenant}/{namespace}/{topic}/permissions") @Operation(summary = "Get permissions on a topic.", description = "Retrieve the effective permissions for a topic." - + " These permissions are defined by the permissions set at the" + + " These permissions are defined by the permissions set at the " + "namespace level combined (union) with any eventual specific permission set on the topic." + " Returns a map structure: Map>.") @ApiResponses(value = { @@ -203,7 +203,7 @@ public void getPartitionedTopicList( @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Topic name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error")}) public void getPermissionsOnTopic( @@ -244,7 +244,7 @@ public void getPermissionsOnTopic( @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "409", description = "Concurrent modification"), @ApiResponse(responseCode = "412", description = "Topic name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error") }) @@ -274,7 +274,7 @@ public void grantPermissionsOnTopic( @DELETE @Path("/{tenant}/{namespace}/{topic}/permissions/{role}") @Operation(summary = "Revoke permissions on a topic.", - description = "Revoke permissions to a role on a single topic. If the permission was not set at the topic" + description = "Revoke permissions to a role on a single topic. If the permission was not set at the topic " + "level, but rather at the namespace level," + " this operation will return an error (HTTP status code 412).") @ApiResponses(value = { @@ -284,7 +284,7 @@ public void grantPermissionsOnTopic( @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Permissions are not set at the topic level"), @ApiResponse(responseCode = "500", description = "Internal server error")}) public void revokePermissionsOnTopic( @@ -1108,7 +1108,7 @@ public void getProperties( @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -1701,7 +1701,7 @@ public void deleteSubscription( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -1778,7 +1778,7 @@ public void skipMessages( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -1820,7 +1820,7 @@ public void expireTopicMessages( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -1863,7 +1863,7 @@ public void expireTopicMessages( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -1906,7 +1906,7 @@ public void expireMessagesForAllSubscriptions( @ApiResponse(responseCode = "400", description = "Create subscription on non persistent topic is not supported"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -1974,7 +1974,7 @@ public void createSubscription( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -2031,7 +2031,7 @@ public void resetCursor( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -2075,7 +2075,7 @@ public void updateSubscriptionProperties( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -2114,7 +2114,7 @@ public void getSubscriptionProperties( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -2163,7 +2163,7 @@ public void analyzeSubscriptionBacklog( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @@ -2210,7 +2210,7 @@ public void resetCursorOnPosition( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", @@ -2278,7 +2278,7 @@ public void examineMessage( @PathParam("namespace") String namespace, @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @Parameter(name = "initialPosition", description = "Relative start position to examine message." + @Parameter(name = "initialPosition", description = "Relative start position to examine message. " + "It can be 'latest' or 'earliest'", schema = @Schema(allowableValues = {"latest", "earliest"}, defaultValue = "latest")) @QueryParam("initialPosition") String initialPosition, @@ -2315,7 +2315,7 @@ public void examineMessage( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", @@ -2369,7 +2369,7 @@ public void getMessageById( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -3818,7 +3818,7 @@ public void removeMaxMessageSize(@Suspended final AsyncResponse asyncResponse, @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -3859,7 +3859,7 @@ public void terminate( @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -3889,7 +3889,7 @@ public void terminatePartitionedTopic(@Suspended final AsyncResponse asyncRespon @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -3929,7 +3929,7 @@ public void compact( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", @@ -3972,7 +3972,7 @@ public void compactionStatus( description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "400", description = "Message ID is null"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -4016,7 +4016,7 @@ public void triggerOffload( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -4055,7 +4055,7 @@ public void offloadStatus( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -4089,7 +4089,7 @@ public void getLastMessageId( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant or" + description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic does not exist"), @@ -4775,11 +4775,11 @@ public void removePublishRate(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/subscriptionTypesEnabled") @Operation( - summary = "Get is enable sub type fors specified topic.") + summary = "Get is enable sub type for specified topic.") @ApiResponses(value = { @ApiResponse( responseCode = "200", - description = "Get is enable sub type fors specified topic.", + description = "Get is enable sub type for specified topic.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = CommandSubscribe.SubType.class)))), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -5328,7 +5328,7 @@ public void setEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @Parameter(description = "Whether leader broker redirected this" + @Parameter(description = "Whether leader broker redirected this " + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @RequestBody(description = "Entry filters for the specified topic") @@ -5359,7 +5359,7 @@ public void removeEntryFilters(@Suspended final AsyncResponse asyncResponse, @PathParam("namespace") String namespace, @PathParam("topic") @Encoded String encodedTopic, @QueryParam("isGlobal") @DefaultValue("false") boolean isGlobal, - @Parameter(description = "Whether leader broker redirected this" + @Parameter(description = "Whether leader broker redirected this " + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) { validateTopicName(tenant, namespace, encodedTopic); @@ -5531,7 +5531,7 @@ public void getAutoSubscriptionCreation( @DELETE @Path("/{tenant}/{namespace}/{topic}/autoSubscriptionCreation") - @Operation(summary = "Remove autoSubscriptionCreation ina a topic.") + @Operation(summary = "Remove autoSubscriptionCreation in a topic.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java index 27b594cf8f720..6a93f6af12d84 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/rest/Topics.java @@ -52,7 +52,7 @@ public class Topics extends TopicsBase { @ApiResponse(responseCode = "200", description = "Produce message to a persistent topic.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnPersistentTopic(@Suspended final AsyncResponse asyncResponse, @@ -84,7 +84,7 @@ public void produceOnPersistentTopic(@Suspended final AsyncResponse asyncRespons @ApiResponse(responseCode = "200", description = "Produce message to a partition of a persistent topic.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnPersistentTopicPartition(@Suspended final AsyncResponse asyncResponse, @@ -118,7 +118,7 @@ public void produceOnPersistentTopicPartition(@Suspended final AsyncResponse asy @ApiResponse(responseCode = "200", description = "Produce message to a non-persistent topic.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnNonPersistentTopic(@Suspended final AsyncResponse asyncResponse, @@ -152,7 +152,7 @@ public void produceOnNonPersistentTopic(@Suspended final AsyncResponse asyncResp description = "Produce message to a partition of a non-persistent topic.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exit"), + @ApiResponse(responseCode = "404", description = "tenant/namespace/topic doesn't exist"), @ApiResponse(responseCode = "412", description = "Namespace name is not valid"), @ApiResponse(responseCode = "500", description = "Internal server error") }) public void produceOnNonPersistentTopicPartition(@Suspended final AsyncResponse asyncResponse, diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java index bc0106c367db2..b2df4f072c940 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java @@ -74,14 +74,14 @@ public class ClientConfigurationData implements Serializable, Cloneable { @Schema( name = "serviceUrlQuarantineInitDurationMs", description = "The initial duration (in milliseconds) to quarantine endpoints that fail to connect." - + "A value of 0 means don't quarantine any endpoints even if they fail." + + " A value of 0 means don't quarantine any endpoints even if they fail." ) private long serviceUrlQuarantineInitDurationMs = 60000; @Schema( name = "serviceUrlQuarantineMaxDurationMs", description = "The max duration (in milliseconds) to quarantine endpoints that fail to connect." - + "A value of 0 means don't quarantine any endpoints even if they fail." + + " A value of 0 means don't quarantine any endpoints even if they fail." ) private long serviceUrlQuarantineMaxDurationMs = TimeUnit.DAYS.toMillis(1); @@ -158,7 +158,7 @@ public class ClientConfigurationData implements Serializable, Cloneable { @Schema( name = "connectionMaxIdleSeconds", description = "Release the connection if it is not used for more than [connectionMaxIdleSeconds] seconds. " - + "If [connectionMaxIdleSeconds] < 0, disabled the feature that auto release the idle connections" + + "If [connectionMaxIdleSeconds] < 0, disabled the feature that auto release the idle connections" ) private int connectionMaxIdleSeconds = 60; @@ -207,7 +207,7 @@ public class ClientConfigurationData implements Serializable, Cloneable { @Schema( name = "sslFactoryPlugin", description = "SSL Factory Plugin class to provide SSLEngine and SSLContext objects. The default " - + " class used is DefaultPulsarSslFactory.") + + "class used is DefaultPulsarSslFactory.") private String sslFactoryPlugin = DefaultPulsarSslFactory.class.getName(); @Schema( @@ -252,7 +252,7 @@ public class ClientConfigurationData implements Serializable, Cloneable { @Schema( name = "connectionTimeoutMs", description = "Duration of waiting for a connection to a broker to be established." - + "If the duration passes without a response from a broker, the connection attempt is dropped." + + " If the duration passes without a response from a broker, the connection attempt is dropped." ) private int connectionTimeoutMs = 10000; @Schema( @@ -295,7 +295,7 @@ public class ClientConfigurationData implements Serializable, Cloneable { name = "listenerName", description = "Listener name for lookup. Clients can use listenerName to choose one of the listeners " + "as the service URL to create a connection to the broker as long as the network is accessible." - + "\"advertisedListeners\" must enabled in broker side." + + " \"advertisedListeners\" must enabled in broker side." ) private String listenerName; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java index a29ebcf01ab2c..acb2a38eacd23 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java @@ -163,10 +163,10 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { @Schema( name = "negativeAckPrecisionBitCnt", description = "The redelivery time precision bit count. The lower bits of the redelivery time will be" - + "trimmed to reduce the memory occupation.\nThe default value is 8, which means the" - + "redelivery time will be bucketed by 256ms, the redelivery time could be earlier(no later)" - + "than the expected time, but no more than 256ms. \nIf set to k, the redelivery time will be" - + "bucketed by 2^k ms.\nIf the value is 0, the redelivery time will be accurate to ms." + + " trimmed to reduce the memory occupation.\nThe default value is 8, which means the" + + " redelivery time will be bucketed by 256ms, the redelivery time could be earlier(no later)" + + " than the expected time, but no more than 256ms. \nIf set to k, the redelivery time will be" + + " bucketed by 2^k ms.\nIf the value is 0, the redelivery time will be accurate to ms." ) private int negativeAckPrecisionBitCnt = 8; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java index 013eae7f916d6..601cf78c8b893 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ProducerConfigurationData.java @@ -130,7 +130,7 @@ public class ProducerConfigurationData implements Serializable, Cloneable { + "* `pulsar.Murmur3_32Hash`: applies the [Murmur3](https://en.wikipedia.org/wiki/MurmurHash)" + " hashing function\n" + "* `pulsar.BoostHash`: applies the hashing function from C++'s" - + "[Boost](https://www.boost.org/doc/libs/1_62_0/doc/html/hash.html) library" + + " [Boost](https://www.boost.org/doc/libs/1_62_0/doc/html/hash.html) library" ) private HashingScheme hashingScheme = HashingScheme.JavaStringHash; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java index 7d8f5dc17e5b8..c374f9838a7c3 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java @@ -119,7 +119,7 @@ public class ReaderConfigurationData implements Serializable, Cloneable { + "\n" + "Delivered encrypted message contains {@link EncryptionContext} which contains encryption and " + "compression information in it using which application can decrypt consumed message payload." - + "cannot set with {@link ReaderDecryptFailListener}, and if ReaderDecryptFailListener are set,\n" + + " cannot set with {@link ReaderDecryptFailListener}, and if ReaderDecryptFailListener are set,\n" + "application should responsible for handling decryption failure." ) private ConsumerCryptoFailureAction cryptoFailureAction; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java index 7bdc43d866c08..05f0c99a8376b 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java @@ -144,13 +144,13 @@ public final class ClusterDataImpl implements ClusterData, Cloneable { private String brokerClientTlsKeyStoreType; @Schema( name = "brokerClientTlsKeyStore", - description = "TLS KeyStore path for internal client, " + description = "TLS KeyStore path for internal client," + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsKeyStore; @Schema( name = "brokerClientTlsKeyStorePassword", - description = "TLS KeyStore password for internal client, " + description = "TLS KeyStore password for internal client," + " used by the internal client to authenticate with Pulsar brokers" ) private String brokerClientTlsKeyStorePassword; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java b/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java index 03663307e3d60..86e566c12f049 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/util/PulsarSslConfiguration.java @@ -102,7 +102,7 @@ public class PulsarSslConfiguration implements Serializable, Cloneable { @Schema( name = "tlsTrustCertsFilePath", - description = " TLS Trust certificates file path" + description = "TLS Trust certificates file path" ) private String tlsTrustCertsFilePath; diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java index ad257ecc1bf0d..288967aa7d0f5 100644 --- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java +++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/v2/WorkerStatsApiV2Resource.java @@ -113,7 +113,7 @@ public List getMetrics() throws Exceptio @Path("/functionsmetrics") @Operation( summary = "Get metrics for all functions owned by worker", - description = "Requested should be executed by Monitoring agent on each worker to fetch the metrics") + description = "Request should be executed by Monitoring agent on each worker to fetch the metrics") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Get metrics for all functions owned by worker", content = @Content(array = @ArraySchema(schema = From 0e36cb845f0e04cad02c1eaa691663cb7e894bd5 Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Thu, 4 Jun 2026 22:17:36 +0300 Subject: [PATCH 3/5] [improve][build] Rename swaggerDocs task to generateOpenApiSpecs Renames the aggregate OpenAPI documentation task in pulsar-broker from `swaggerDocs` to `generateOpenApiSpecs` and its output directory from build/docs to build/openapi: ./gradlew :pulsar-broker:generateOpenApiSpecs -> pulsar-broker/build/openapi/ The generated file names and the flat + v2/ + v3/ layout are unchanged. Assisted-by: Claude Code (Opus 4.8) --- pulsar-broker/build.gradle.kts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pulsar-broker/build.gradle.kts b/pulsar-broker/build.gradle.kts index 3016b7fdea0bb..2b9a8b33fe3f3 100644 --- a/pulsar-broker/build.gradle.kts +++ b/pulsar-broker/build.gradle.kts @@ -216,7 +216,7 @@ lightproto { // ── OpenAPI (Swagger) REST API documentation ──────────────────────────────── // Mirrors the Maven build's `swagger` profile (kongchen swagger-maven-plugin, Swagger 1.x), // ported to the official Swagger Core v3 gradle plugin. Run on demand: -// ./gradlew :pulsar-broker:swaggerDocs (outputs to pulsar-broker/build/docs/) +// ./gradlew :pulsar-broker:generateOpenApiSpecs (outputs to pulsar-broker/build/openapi/) // The plugin's default `swaggerDeps` resolver dependencies target javax.ws.rs; declaring // our own dependencies on the configuration replaces them with the jakarta variants. dependencies { @@ -295,10 +295,10 @@ registerSwaggerTask("swaggerPackages", "swaggerpackages", "packages-v3.json") { // Assemble the documentation set in the layout published on pulsar.apache.org (see e.g. // pulsar-site static/swagger//): all files flat, plus v2/ and v3/ subdirectory copies // grouped by REST API version. -tasks.register("swaggerDocs") { +tasks.register("generateOpenApiSpecs") { group = "documentation" - description = "Generates all OpenAPI REST API documentation files to build/docs" - into(layout.buildDirectory.dir("docs")) + description = "Generates all OpenAPI REST API documentation files to build/openapi" + into(layout.buildDirectory.dir("openapi")) val v2Tasks = listOf("swaggerAdminV2", "swaggerLookup") val v3Tasks = listOf("swaggerFunctions", "swaggerTransactions", "swaggerSource", "swaggerSink", "swaggerPackages") v2Tasks.forEach { t -> From 164b6b23eda950ef470fad4f8b486d04d414d8b2 Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Thu, 4 Jun 2026 22:40:03 +0300 Subject: [PATCH 4/5] [improve][misc] Fix grammar in OpenAPI annotation descriptions Fixes ungrammatical and garbled wording in the OpenAPI annotation summary/description strings while preserving the technical meaning, e.g.: - "Get is enable sub type for specified topic" -> "Get the enabled subscription types for the specified topic" (and the Set variant) - "will let the broker removes all producers" -> "will make the broker remove all producers" - "Topic don't owner by this broker\!" -> "Topic is not owned by this broker\!"; "Broker don't use MLTransactionMetadataStore\!" -> "Broker doesn't use ..."; "This Broker is not enable transaction" -> "This Broker does not have transactions enabled" - "Partitioned topic already exist" -> "already exists"; "Expiry messages" -> "Expire messages"; "An REST endpoint" -> "A REST endpoint"; "The type of an value" -> "the type of a value"; "configurations's name" -> "configurations' names" - "Requested should be executed by Monitoring agent" -> "The request should be executed by the Monitoring agent" - copy-paste leaks: Source endpoints saying "Pulsar Function successfully created/updated" / "The function was successfully deleted" now say "Pulsar Source"; setEntryFilters request body description said "Enable sub types for the specified topic" - '"advertisedListeners" must enabled in broker side' -> 'must be enabled on the broker side'; missing spaces after punctuation ("schema.if", "**DISCARD**:silently", "earlier(no later)") Candidates were located by spell-checking the descriptions rendered into the generated OpenAPI documents and from the previous cleanup pass's report. Generated documents remain operation-identical with the published 4.2.1 docs (597/597 operations). Assisted-by: Claude Code (Opus 4.8) --- .../broker/admin/impl/BrokerStatsBase.java | 2 +- .../pulsar/broker/admin/impl/BrokersBase.java | 16 +++---- .../broker/admin/impl/FunctionsBase.java | 8 ++-- .../pulsar/broker/admin/impl/SinksBase.java | 8 ++-- .../pulsar/broker/admin/impl/SourcesBase.java | 44 ++++++++++--------- .../admin/v2/ExtNonPersistentTopics.java | 2 +- .../broker/admin/v2/ExtPersistentTopics.java | 2 +- .../pulsar/broker/admin/v2/Namespaces.java | 42 +++++++++--------- .../broker/admin/v2/NonPersistentTopics.java | 2 +- .../broker/admin/v2/PersistentTopics.java | 37 ++++++++-------- .../pulsar/broker/admin/v2/WorkerStats.java | 5 ++- .../pulsar/broker/admin/v3/Transactions.java | 12 ++--- .../impl/conf/ClientConfigurationData.java | 4 +- .../impl/conf/ConsumerConfigurationData.java | 11 ++--- .../impl/conf/ReaderConfigurationData.java | 7 +-- .../data/AutoFailoverPolicyDataImpl.java | 2 +- .../common/policies/data/ClusterDataImpl.java | 4 +- .../policies/data/ClusterPoliciesImpl.java | 4 +- .../common/policies/data/TenantInfoImpl.java | 2 +- .../apache/pulsar/proxy/stats/ProxyStats.java | 2 +- .../admin/v2/WebSocketProxyStatsV2.java | 3 +- 21 files changed, 113 insertions(+), 106 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java index e7f26d33c8c95..5762d29b33785 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokerStatsBase.java @@ -51,7 +51,7 @@ public class BrokerStatsBase extends AdminResource { @GET @Path("/metrics") @Operation(summary = "Gets the metrics for Monitoring", - description = "Requested should be executed by Monitoring agent on each broker to fetch the metrics") + description = "The request should be executed by the Monitoring agent on each broker to fetch the metrics") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Metrics.class)))), diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java index c76900ce4df6a..e728b3b9abd6e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/BrokersBase.java @@ -228,10 +228,10 @@ public void updateDynamicConfiguration(@Suspended AsyncResponse asyncResponse, @DELETE @Path("/configuration/{configName}") @Operation(summary = - "Delete dynamic ServiceConfiguration into metadata only." + "Delete dynamic ServiceConfiguration from metadata only." + " This operation requires Pulsar super-user privileges.") @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "Service configuration delete successfully"), + @ApiResponse(responseCode = "204", description = "Service configuration deleted successfully"), @ApiResponse(responseCode = "403", description = "You don't have admin permission to update service-configuration"), @ApiResponse(responseCode = "412", description = "Invalid dynamic-config value"), @@ -259,10 +259,10 @@ public void deleteDynamicConfiguration( @GET @Path("/configuration/values") - @Operation(summary = "Get value of all dynamic configurations' value overridden on local config") + @Operation(summary = "Get the values of all dynamic configurations overridden on local config") @ApiResponses(value = { @ApiResponse(responseCode = "200", - description = "Get value of all dynamic configurations' value overridden on local config", + description = "Get the values of all dynamic configurations overridden on local config", content = @Content(schema = @Schema(type = "object", additionalPropertiesSchema = String.class))), @ApiResponse(responseCode = "403", description = "You don't have admin permission to view configuration"), @ApiResponse(responseCode = "404", description = "Configuration not found"), @@ -283,9 +283,9 @@ public void getAllDynamicConfigurations(@Suspended AsyncResponse asyncResponse) @GET @Path("/configuration") - @Operation(summary = "Get all updatable dynamic configurations's name") + @Operation(summary = "Get all updatable dynamic configurations' names") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Get all updatable dynamic configurations's name", + @ApiResponse(responseCode = "200", description = "Get all updatable dynamic configurations' names", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "403", description = "You don't have admin permission to get configuration")}) public void getDynamicConfigurationName(@Suspended AsyncResponse asyncResponse) { @@ -373,7 +373,7 @@ public void getInternalConfigurationData(@Suspended AsyncResponse asyncResponse) @GET @Path("/backlog-quota-check") - @Operation(summary = "An REST endpoint to trigger backlogQuotaCheck") + @Operation(summary = "A REST endpoint to trigger backlogQuotaCheck") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Everything is OK"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -512,7 +512,7 @@ public String version() throws Exception { @ApiResponse(responseCode = "500", description = "Internal server error")}) public void shutDownBrokerGracefully( @Parameter(name = "maxConcurrentUnloadPerSec", - description = "if the value absent(value=0) means no concurrent limitation.") + description = "If the value is absent (value=0), it means there is no concurrency limit.") @QueryParam("maxConcurrentUnloadPerSec") int maxConcurrentUnloadPerSec, @QueryParam("forcedTerminateTopic") @DefaultValue("true") boolean forcedTerminateTopic, @Suspended final AsyncResponse asyncResponse diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java index 11ee194539430..076d735327985 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/FunctionsBase.java @@ -161,10 +161,10 @@ public void registerFunction( + "- **userConfig**\n" + " A map of user-defined configurations (specified as a JSON object).\n" + "- **secrets**\n" - + " This is a map of secretName(that is how the secret is going to be accessed" + + " This is a map of secretName (that is how the secret is going to be accessed" + " in the Pulsar Function via context) to an object that" + " encapsulates how the secret is fetched by the underlying secrets provider." - + " The type of an value here can be found by the" + + " The type of a value here can be found by the" + " SecretProviderConfigurator.getSecretObjectType() method. \n" + "- **cleanupSubscription**\n" + " Whether the subscriptions of a Pulsar Function created or used should be deleted" @@ -272,10 +272,10 @@ public void updateFunction( + "- **userConfig**\n" + " A map of user-defined configurations (specified as a JSON object).\n" + "- **secrets**\n" - + " This is a map of secretName(that is how the secret is going to be accessed" + + " This is a map of secretName (that is how the secret is going to be accessed" + " in the Pulsar Function via context) to an object that" + " encapsulates how the secret is fetched by the underlying secrets provider." - + " The type of an value here can be found by the" + + " The type of a value here can be found by the" + " SecretProviderConfigurator.getSecretObjectType() method. \n" + "- **cleanupSubscription**\n" + " Whether the subscriptions of a Pulsar Function created or used" diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java index c3ea336abd903..57f229721f9bc 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SinksBase.java @@ -113,10 +113,10 @@ public void registerSink(@Parameter(description = "The tenant of a Pulsar Sink") + "- **configs**\n" + " The map of configs (specified as a JSON object)\n" + "- **secrets**\n" - + " a map of secretName(aka how the secret is going to be \n" + + " a map of secretName (aka how the secret is going to be \n" + " accessed in the function via context) to an object that \n" + " encapsulates how the secret is fetched by the underlying \n" - + " secrets provider. The type of an value here can be found by the \n" + + " secrets provider. The type of a value here can be found by the \n" + " SecretProviderConfigurator.getSecretObjectType() method." + " (specified as a JSON object)\n" + "- **parallelism**\n" @@ -229,10 +229,10 @@ public void updateSink(@Parameter(description = "The tenant of a Pulsar Sink") + "- **configs**\n" + " The map of configs (specified as a JSON object)\n" + "- **secrets**\n" - + " a map of secretName(aka how the secret is going to be \n" + + " a map of secretName (aka how the secret is going to be \n" + " accessed in the function via context) to an object that \n" + " encapsulates how the secret is fetched by the underlying \n" - + " secrets provider. The type of an value here can be found by the \n" + + " secrets provider. The type of a value here can be found by the \n" + " SecretProviderConfigurator.getSecretObjectType() method." + " (specified as a JSON object)\n" + "- **parallelism**\n" diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java index cf44e7e9282f0..fa4e01c3c1248 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/SourcesBase.java @@ -57,9 +57,10 @@ Sources sources() { @POST @Operation(summary = "Creates a new Pulsar Source in cluster mode") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Pulsar Function successfully created"), + @ApiResponse(responseCode = "200", description = "Pulsar Source successfully created"), @ApiResponse(responseCode = "400", description = - "Invalid request (Function already exists or Tenant, Namespace or Name is not provided, etc.)"), + "Invalid request (The Pulsar Source already exists or Tenant," + + " Namespace or Name is not provided, etc.)"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), @ApiResponse(responseCode = "500", description = "Internal Server Error"), @ApiResponse(responseCode = "503", @@ -83,7 +84,7 @@ public void registerSource( + "Follow the steps below.\n" + "1. Create a JSON object using some of the following parameters.\n" + "A JSON value presenting configuration payload of a Pulsar Source." - + " An example of the expected functions can be found here.\n" + + " An example of the expected Pulsar Source can be found here.\n" + "- **classname**\n" + " The class name of a Pulsar Source if archive is file-url-path (file://).\n" + "- **topicName**\n" @@ -91,16 +92,16 @@ public void registerSource( + "- **serdeClassName**\n" + " The SerDe classname for the Pulsar Source.\n" + "- **schemaType**\n" - + " The schema type (either a builtin schema like 'avro', 'json', etc.. or " + + " The schema type (either a builtin schema like 'avro', 'json', etc. or " + " custom Schema class name to be used to" + " encode messages emitted from the Pulsar Source)\n" + "- **configs**\n" + " Source config key/values\n" + "- **secrets**\n" - + " This is a map of secretName(that is how the secret is going" + + " This is a map of secretName (that is how the secret is going" + " to be accessed in the function via context) to an object that" + " encapsulates how the secret is fetched by the underlying secrets provider." - + " The type of an value here can be found by the" + + " The type of a value here can be found by the" + " SecretProviderConfigurator.getSecretObjectType() method. \n" + "- **parallelism**\n" + " The parallelism factor of a Pulsar Source" @@ -128,10 +129,11 @@ public void registerSource( @ApiResponses(value = { @ApiResponse(responseCode = "403", description = "The requester doesn't have admin permissions"), @ApiResponse(responseCode = "400", description = - "Invalid request (Function already exists or Tenant, Namespace or Name is not provided, etc.)"), + "Invalid request (The Pulsar Source already exists or Tenant," + + " Namespace or Name is not provided, etc.)"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "200", description = "Pulsar Function successfully updated"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "200", description = "Pulsar Source successfully updated"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal Server Error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -158,16 +160,16 @@ public void updateSource( + "- **serdeClassName**\n" + " The SerDe classname for the Pulsar Source.\n" + "- **schemaType**\n" - + " The schema type (either a builtin schema like 'avro', 'json', etc.. or " + + " The schema type (either a builtin schema like 'avro', 'json', etc. or " + " custom Schema class name to be used to encode" + " messages emitted from the Pulsar Source)\n" + "- **configs**\n" + " Pulsar Source config key/values\n" + "- **secrets**\n" - + " This is a map of secretName(that is how the secret is going to" + + " This is a map of secretName (that is how the secret is going to" + " be accessed in the function via context) to an object that" + " encapsulates how the secret is fetched by the underlying secrets provider." - + " The type of an value here can be found by the" + + " The type of a value here can be found by the" + " SecretProviderConfigurator.getSecretObjectType() method.\n" + "- **parallelism**\n" + " The parallelism factor of a Pulsar Source" @@ -197,9 +199,9 @@ public void updateSource( @ApiResponses(value = { @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "408", description = "Request timeout"), - @ApiResponse(responseCode = "200", description = "The function was successfully deleted"), + @ApiResponse(responseCode = "200", description = "The Pulsar Source was successfully deleted"), @ApiResponse(responseCode = "500", description = "Internal Server Error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -224,7 +226,7 @@ public void deregisterSource( description = "Fetches information about a Pulsar Source currently running in cluster mode", content = @Content(schema = @Schema(implementation = SourceConfig.class))), @ApiResponse(responseCode = "400", description = "Invalid request"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") }) @@ -325,7 +327,7 @@ public List listSources( description = "Current broker doesn't serve the namespace of this source"), @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -349,7 +351,7 @@ public void restartSource( @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -372,7 +374,7 @@ public void restartSource( @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -395,7 +397,7 @@ public void stopSource( @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -418,7 +420,7 @@ public void stopSource( @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") @@ -441,7 +443,7 @@ public void startSource( @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "400", description = "Invalid request"), @ApiResponse(responseCode = "401", description = "Client is not authorized to perform operation"), - @ApiResponse(responseCode = "404", description = "Not Found(The Pulsar Source doesn't exist)"), + @ApiResponse(responseCode = "404", description = "Not Found (The Pulsar Source doesn't exist)"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Function worker service is now initializing. Please try again later.") diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java index c261bb7e99db8..a2e255f548e89 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java @@ -63,7 +63,7 @@ public class ExtNonPersistentTopics extends PersistentTopicsBase { @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), @ApiResponse(responseCode = "412", description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), @ApiResponse(responseCode = "500", description = "Internal server error"), diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java index 8e463b89a3408..8f907a3427980 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java @@ -65,7 +65,7 @@ public class ExtPersistentTopics extends PersistentTopicsBase { @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), @ApiResponse(responseCode = "412", description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), @ApiResponse(responseCode = "500", description = "Internal server error"), diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java index 9d3187323ed36..77c18f4169d17 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Namespaces.java @@ -1005,7 +1005,7 @@ public void getBundlesData(@Suspended final AsyncResponse asyncResponse, @Path("/{tenant}/{namespace}/unload") @Operation(summary = "Unload namespace", description = "Unload an active namespace from the current broker serving it. Performing this operation" - + " will let the broker removes all producers, consumers, and connections using this namespace," + + " will make the broker remove all producers, consumers, and connections using this namespace," + " and close all topics (including their persistent store). During that operation," + " the namespace is marked as tentatively unavailable until the broker completes " + "the unloading action. This operation requires strictly super user privileges," @@ -2553,12 +2553,12 @@ public void removeNamespaceAntiAffinityGroup(@Suspended AsyncResponse asyncRespo @GET @Path("{cluster}/antiAffinity/{group}") - @Operation(summary = "Get all namespaces that are grouped by given anti-affinity group in a given cluster." - + " api can be only accessed by admin of any of the existing tenant") + @Operation(summary = "Get all namespaces that are grouped by the given anti-affinity group in a given cluster." + + " This API can only be accessed by an admin of any of the existing tenants.") @ApiResponses(value = { @ApiResponse(responseCode = "200", - description = "Get all namespaces that are grouped by given anti-affinity group in a given cluster." - + " api can be only accessed by admin of any of the existing tenant", + description = "Get all namespaces that are grouped by the given anti-affinity group in a given" + + " cluster. This API can only be accessed by an admin of any of the existing tenants.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "412", description = "Cluster not exist/Anti-affinity group can't be empty.")}) @@ -2584,7 +2584,7 @@ public void getAntiAffinityNamespaces(@Suspended AsyncResponse asyncResponse, @Path("/{tenant}/{namespace}/compactionThreshold") @Operation(summary = "Maximum number of uncompacted bytes in topics before compaction is triggered.", description = "The backlog size is compared to the threshold periodically. " - + "A threshold of 0 disabled automatic compaction") + + "A threshold of 0 disables automatic compaction") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Maximum number of uncompacted bytes in topics before compaction is triggered.", @@ -2613,7 +2613,7 @@ public void getCompactionThreshold( @Path("/{tenant}/{namespace}/compactionThreshold") @Operation(summary = "Set maximum number of uncompacted bytes in a topic before compaction is triggered.", description = "The backlog size is compared to the threshold periodically. " - + "A threshold of 0 disabled automatic compaction") + + "A threshold of 0 disables automatic compaction") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2633,7 +2633,7 @@ public void setCompactionThreshold(@PathParam("tenant") String tenant, @Path("/{tenant}/{namespace}/compactionThreshold") @Operation(summary = "Delete maximum number of uncompacted bytes in a topic before compaction is triggered.", description = "The backlog size is compared to the threshold periodically. " - + "A threshold of 0 disabled automatic compaction") + + "A threshold of 0 disables automatic compaction") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2931,9 +2931,9 @@ public void setSchemaCompatibilityStrategy( @GET @Path("/{tenant}/{namespace}/isAllowAutoUpdateSchema") - @Operation(summary = "The flag of whether allow auto update schema") + @Operation(summary = "The flag of whether to allow auto update schema") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "The flag of whether allow auto update schema", + @ApiResponse(responseCode = "200", description = "The flag of whether to allow auto update schema", content = @Content(schema = @Schema(implementation = Boolean.class))), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace doesn't exist"), @@ -2965,7 +2965,7 @@ public void getIsAllowAutoUpdateSchema( @POST @Path("/{tenant}/{namespace}/isAllowAutoUpdateSchema") - @Operation(summary = "Update flag of whether allow auto update schema") + @Operation(summary = "Update flag of whether to allow auto update schema") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -2990,9 +2990,9 @@ public void setIsAllowAutoUpdateSchema( @GET @Path("/{tenant}/{namespace}/subscriptionTypesEnabled") - @Operation(summary = "The set of whether allow subscription types") + @Operation(summary = "The set of enabled subscription types") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "The set of whether allow subscription types", + @ApiResponse(responseCode = "200", description = "The set of enabled subscription types", content = @Content(array = @ArraySchema(schema = @Schema(implementation = SubscriptionType.class), uniqueItems = true))), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -3023,7 +3023,7 @@ public void getSubscriptionTypesEnabled( @POST @Path("/{tenant}/{namespace}/subscriptionTypesEnabled") - @Operation(summary = "Update set of whether allow share sub type") + @Operation(summary = "Update the set of enabled subscription types") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -3032,7 +3032,7 @@ public void getSubscriptionTypesEnabled( public void setSubscriptionTypesEnabled( @PathParam("tenant") String tenant, @PathParam("namespace") String namespace, - @RequestBody(description = "Set of whether allow subscription types", required = true) + @RequestBody(description = "Set of enabled subscription types", required = true) Set subscriptionTypesEnabled) { validateNamespaceName(tenant, namespace); internalSetSubscriptionTypesEnabled(subscriptionTypesEnabled); @@ -3136,9 +3136,9 @@ public void removeAllowedTopicPropertyKeysForMetrics( @Path("/{tenant}/{namespace}/schemaValidationEnforced") @Operation(summary = "Get schema validation enforced flag for namespace.", description = "If the flag is set to true, when a producer without a schema attempts to produce " - + "to a topic with schema in this namespace, the producer will be failed to connect. " - + "PLEASE be carefully on using this, since non-java clients don't support schema.if you " - + "enable this setting, it will cause non-java clients failed to produce.") + + "to a topic with schema in this namespace, the producer will fail to connect. " + + "PLEASE be careful when using this, since non-Java clients don't support schema. If you " + + "enable this setting, it will cause non-Java clients to fail to produce.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Get schema validation enforced flag for namespace.", content = @Content(schema = @Schema(implementation = Boolean.class))), @@ -3175,9 +3175,9 @@ public void getSchemaValidtionEnforced( @Path("/{tenant}/{namespace}/schemaValidationEnforced") @Operation(summary = "Set schema validation enforced flag on namespace.", description = "If the flag is set to true, when a producer without a schema attempts to produce to a topic" - + " with schema in this namespace, the producer will be failed to connect. PLEASE be" - + " carefully on using this, since non-java clients don't support schema.if you enable" - + " this setting, it will cause non-java clients failed to produce.") + + " with schema in this namespace, the producer will fail to connect. PLEASE be" + + " careful when using this, since non-Java clients don't support schema. If you enable" + + " this setting, it will cause non-Java clients to fail to produce.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java index e6046e6932a82..e89633265c455 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java @@ -632,7 +632,7 @@ public void setEntryFilters(@Suspended final AsyncResponse asyncResponse, @Parameter(description = "Whether leader broker redirected this " + "call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, - @RequestBody(description = "Enable sub types for the specified topic") + @RequestBody(description = "Entry filters for the specified topic") EntryFilters entryFilters) { validateTopicName(tenant, namespace, encodedTopic); preValidation(authoritative) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java index 32612277c44da..2301c7f7baa57 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java @@ -321,7 +321,7 @@ public void revokePermissionsOnTopic( @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), @ApiResponse(responseCode = "412", description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), @ApiResponse(responseCode = "500", description = "Internal server error"), @@ -367,7 +367,7 @@ public void createPartitionedTopic( description = "Don't have permission to administrate resources on this tenant"), @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "409", description = "Partitioned topic already exist"), + @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), @ApiResponse(responseCode = "412", description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), @ApiResponse(responseCode = "500", description = "Internal server error"), @@ -916,7 +916,7 @@ public void deleteDelayedDeliveryPolicies(@Suspended final AsyncResponse asyncRe @POST @Path("/{tenant}/{namespace}/{topic}/partitions") @Operation(summary = "Increment partitions of an existing partitioned topic.", - description = "It increments partitions of existing partitioned-topic") + description = "It increments the partitions of an existing partitioned topic.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Update topic partition successful."), @ApiResponse(responseCode = "307", @@ -1772,7 +1772,7 @@ public void skipMessages( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/expireMessages/{expireTimeInSeconds}") - @Operation(summary = "Expiry messages on a topic subscription.") + @Operation(summary = "Expire messages on a topic subscription.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "307", @@ -1783,7 +1783,7 @@ public void skipMessages( @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @ApiResponse(responseCode = "405", - description = "Expiry messages on a non-persistent topic is not allowed"), + description = "Expiring messages on a non-persistent topic is not allowed"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void expireTopicMessages( @@ -1794,7 +1794,7 @@ public void expireTopicMessages( @PathParam("namespace") String namespace, @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @Parameter(description = "Subscription to be Expiry messages on") + @Parameter(description = "Subscription to expire messages on") @PathParam("subName") String encodedSubName, @Parameter(description = "Expires beyond the specified number of seconds", schema = @Schema(defaultValue = "0")) @@ -1814,7 +1814,7 @@ public void expireTopicMessages( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/expireMessages") - @Operation(summary = "Expiry messages on a topic subscription.") + @Operation(summary = "Expire messages on a topic subscription.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "307", @@ -1825,7 +1825,7 @@ public void expireTopicMessages( @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @ApiResponse(responseCode = "405", - description = "Expiry messages on a non-persistent topic is not allowed"), + description = "Expiring messages on a non-persistent topic is not allowed"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) public void expireTopicMessages( @@ -1836,7 +1836,7 @@ public void expireTopicMessages( @PathParam("namespace") String namespace, @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @Parameter(description = "Subscription to be Expiry messages on") + @Parameter(description = "Subscription to expire messages on") @PathParam("subName") String encodedSubName, @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.") @QueryParam("authoritative") @DefaultValue("false") boolean authoritative, @@ -1857,7 +1857,7 @@ public void expireTopicMessages( @POST @Path("/{tenant}/{namespace}/{topic}/all_subscription/expireMessages/{expireTimeInSeconds}") - @Operation(summary = "Expiry messages on all subscriptions of topic.") + @Operation(summary = "Expire messages on all subscriptions of a topic.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "307", @@ -1868,7 +1868,7 @@ public void expireTopicMessages( @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Namespace or topic or subscription does not exist"), @ApiResponse(responseCode = "405", - description = "Expiry messages on a non-persistent topic is not allowed"), + description = "Expiring messages on a non-persistent topic is not allowed"), @ApiResponse(responseCode = "412", description = "Can't find owner for topic"), @ApiResponse(responseCode = "500", description = "Internal server error"), @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration")}) @@ -1904,7 +1904,7 @@ public void expireMessagesForAllSubscriptions( @ApiResponse(responseCode = "307", description = "Current broker doesn't serve the namespace of this topic"), @ApiResponse(responseCode = "400", - description = "Create subscription on non persistent topic is not supported"), + description = "Creating a subscription on a non-persistent topic is not supported"), @ApiResponse(responseCode = "401", description = "Don't have permission to administrate resources on this tenant or " + "subscriber is not authorized to access this operation"), @@ -1968,7 +1968,7 @@ public void createSubscription( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor/{timestamp}") @Operation(summary = "Reset subscription to message position closest to absolute timestamp (in ms).", - description = "It fence cursor and disconnects all active consumers before resetting cursor.") + description = "It fences the cursor and disconnects all active consumers before resetting the cursor.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "307", @@ -2157,7 +2157,7 @@ public void analyzeSubscriptionBacklog( @POST @Path("/{tenant}/{namespace}/{topic}/subscription/{subName}/resetcursor") @Operation(summary = "Reset subscription to message position closest to given position.", - description = "It fence cursor and disconnects all active consumers before resetting cursor.") + description = "It fences the cursor and disconnects all active consumers before resetting the cursor.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "307", @@ -4775,11 +4775,11 @@ public void removePublishRate(@Suspended final AsyncResponse asyncResponse, @GET @Path("/{tenant}/{namespace}/{topic}/subscriptionTypesEnabled") @Operation( - summary = "Get is enable sub type for specified topic.") + summary = "Get the enabled subscription types for the specified topic.") @ApiResponses(value = { @ApiResponse( responseCode = "200", - description = "Get is enable sub type for specified topic.", + description = "Get the enabled subscription types for the specified topic.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = CommandSubscribe.SubType.class)))), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -4810,7 +4810,7 @@ public void getSubscriptionTypesEnabled(@Suspended final AsyncResponse asyncResp @POST @Path("/{tenant}/{namespace}/{topic}/subscriptionTypesEnabled") - @Operation(summary = "Set is enable sub types for specified topic") + @Operation(summary = "Set the enabled subscription types for the specified topic") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Operation successful"), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @@ -5578,7 +5578,8 @@ public void removeAutoSubscriptionCreation( @ApiResponse(responseCode = "404", description = "Namespace or partitioned topic does not exist, " + "or the index is invalid"), @ApiResponse(responseCode = "406", description = "The topic is not a persistent topic"), - @ApiResponse(responseCode = "412", description = "The broker is not enable broker entry metadata"), + @ApiResponse(responseCode = "412", + description = "The broker does not have broker entry metadata enabled"), }) public void getMessageIDByIndex(@Suspended final AsyncResponse asyncResponse, @PathParam("tenant") String tenant, diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java index 244749c2bc54d..15ebb072083ba 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/WorkerStats.java @@ -48,7 +48,8 @@ public Workers workers() { @Path("/metrics") @Operation( summary = "Gets the metrics for Monitoring", - description = "Request should be executed by Monitoring agent on each worker to fetch the worker-metrics") + description = "The request should be executed by a Monitoring agent on each worker " + + "to fetch the worker-metrics") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", content = @Content(array = @ArraySchema( @@ -65,7 +66,7 @@ public Collection getMetrics() throws Exception { @Path("/functionsmetrics") @Operation( summary = "Get metrics for all functions owned by worker", - description = "Requested should be executed by Monitoring agent on each worker to fetch the metrics") + description = "The request should be executed by a Monitoring agent on each worker to fetch the metrics") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Get metrics for all functions owned by worker", content = @Content(array = @ArraySchema( diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java index 687349fad1aa2..70afc319d948e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v3/Transactions.java @@ -307,7 +307,7 @@ public void getTransactionMetadata(@Suspended final AsyncResponse asyncResponse, + "or coordinator or transaction doesn't exist"), @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), - @ApiResponse(responseCode = "307", description = "Topic don't owner by this broker!"), + @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getSlowTransactions(@Suspended final AsyncResponse asyncResponse, @@ -330,7 +330,7 @@ public void getSlowTransactions(@Suspended final AsyncResponse asyncResponse, @ApiResponse(responseCode = "503", description = "This Broker is not " + "configured with transactionCoordinatorEnabled=true."), @ApiResponse(responseCode = "404", description = "Transaction coordinator not found"), - @ApiResponse(responseCode = "405", description = "Broker don't use MLTransactionMetadataStore!"), + @ApiResponse(responseCode = "405", description = "Broker doesn't use MLTransactionMetadataStore!"), @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getCoordinatorInternalStats(@Suspended final AsyncResponse asyncResponse, @QueryParam("authoritative") @@ -354,7 +354,7 @@ public void getCoordinatorInternalStats(@Suspended final AsyncResponse asyncResp @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), - @ApiResponse(responseCode = "405", description = "Pending ack handle don't use managedLedger!"), + @ApiResponse(responseCode = "405", description = "Pending ack handle doesn't use managedLedger!"), @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPendingAckInternalStats(@Suspended final AsyncResponse asyncResponse, @@ -409,9 +409,9 @@ private Void resumeAsyncResponseWithBrokerException(@Suspended AsyncResponse asy @Schema(implementation = TransactionBufferInternalStats.class))), @ApiResponse(responseCode = "403", description = "Don't have admin permission"), @ApiResponse(responseCode = "404", description = "Tenant or cluster or namespace or topic doesn't exist"), - @ApiResponse(responseCode = "503", description = "This Broker is not enable transaction"), + @ApiResponse(responseCode = "503", description = "This Broker does not have transactions enabled"), @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), - @ApiResponse(responseCode = "405", description = "Transaction buffer don't use managedLedger!"), + @ApiResponse(responseCode = "405", description = "Transaction buffer doesn't use managedLedger!"), @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), @ApiResponse(responseCode = "409", description = "Concurrent modification") }) @@ -476,7 +476,7 @@ public void scaleTransactionCoordinators(@Suspended final AsyncResponse asyncRes @ApiResponse(responseCode = "503", description = "This Broker is not configured " + "with transactionCoordinatorEnabled=true."), @ApiResponse(responseCode = "307", description = "Topic is not owned by this broker!"), - @ApiResponse(responseCode = "405", description = "Pending ack handle don't use managedLedger!"), + @ApiResponse(responseCode = "405", description = "Pending ack handle doesn't use managedLedger!"), @ApiResponse(responseCode = "400", description = "Topic is not a persistent topic!"), @ApiResponse(responseCode = "409", description = "Concurrent modification")}) public void getPositionStatsInPendingAck(@Suspended final AsyncResponse asyncResponse, diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java index b2df4f072c940..1c282198eb059 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java @@ -158,7 +158,7 @@ public class ClientConfigurationData implements Serializable, Cloneable { @Schema( name = "connectionMaxIdleSeconds", description = "Release the connection if it is not used for more than [connectionMaxIdleSeconds] seconds. " - + "If [connectionMaxIdleSeconds] < 0, disabled the feature that auto release the idle connections" + + "If [connectionMaxIdleSeconds] < 0, disables the feature that auto-releases the idle connections" ) private int connectionMaxIdleSeconds = 60; @@ -295,7 +295,7 @@ public class ClientConfigurationData implements Serializable, Cloneable { name = "listenerName", description = "Listener name for lookup. Clients can use listenerName to choose one of the listeners " + "as the service URL to create a connection to the broker as long as the network is accessible." - + " \"advertisedListeners\" must enabled in broker side." + + " \"advertisedListeners\" must be enabled on the broker side." ) private String listenerName; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java index acb2a38eacd23..f388b726d3235 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConsumerConfigurationData.java @@ -106,7 +106,8 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { @Schema( name = "negativeAckRedeliveryBackoff", - description = "Interface for custom message is negativeAcked policy. You can specify `RedeliveryBackoff`" + description = "Interface for the custom message negative-acknowledgment policy. You can specify" + + " `RedeliveryBackoff`" + " for a consumer." ) @JsonIgnore @@ -114,7 +115,7 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { @Schema( name = "ackTimeoutRedeliveryBackoff", - description = "Interface for custom message is ackTimeout policy. You can specify `RedeliveryBackoff`" + description = "Interface for the custom message ack-timeout policy. You can specify `RedeliveryBackoff`" + " for a consumer." ) @JsonIgnore @@ -164,7 +165,7 @@ public class ConsumerConfigurationData implements Serializable, Cloneable { name = "negativeAckPrecisionBitCnt", description = "The redelivery time precision bit count. The lower bits of the redelivery time will be" + " trimmed to reduce the memory occupation.\nThe default value is 8, which means the" - + " redelivery time will be bucketed by 256ms, the redelivery time could be earlier(no later)" + + " redelivery time will be bucketed by 256ms, the redelivery time could be earlier (no later)" + " than the expected time, but no more than 256ms. \nIf set to k, the redelivery time will be" + " bucketed by 2^k ms.\nIf the value is 0, the redelivery time will be accurate to ms." ) @@ -276,13 +277,13 @@ public int getMaxPendingChuckedMessage() { name = "cryptoFailureAction", description = "Consumer should take action when it receives a message that can not be decrypted.\n" + "* **FAIL**: this is the default option to fail messages until crypto succeeds.\n" - + "* **DISCARD**:silently acknowledge and not deliver message to an application.\n" + + "* **DISCARD**: silently acknowledge and not deliver message to an application.\n" + "* **CONSUME**: deliver encrypted messages to applications. It is the application's" + " responsibility to decrypt the message.\n" + "\n" + "The decompression of message fails.\n" + "\n" - + "If messages contain batch messages, a client is not be able to retrieve individual messages in" + + "If messages contain batch messages, a client is not able to retrieve individual messages in" + " batch.\n" + "\n" + "Delivered encrypted message contains {@link EncryptionContext} which contains encryption and " diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java index c374f9838a7c3..b808c5e6d23cc 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java @@ -114,13 +114,14 @@ public class ReaderConfigurationData implements Serializable, Cloneable { + "\n" + "The message decompression fails.\n" + "\n" - + "If messages contain batch messages, a client is not be able to retrieve individual messages in" + + "If messages contain batch messages, a client is not able to retrieve individual messages in" + " batch.\n" + "\n" + "Delivered encrypted message contains {@link EncryptionContext} which contains encryption and " + "compression information in it using which application can decrypt consumed message payload." - + " cannot set with {@link ReaderDecryptFailListener}, and if ReaderDecryptFailListener are set,\n" - + "application should responsible for handling decryption failure." + + " It cannot be set together with a {@link ReaderDecryptFailListener}, and if a" + + " ReaderDecryptFailListener is set,\n" + + "the application is responsible for handling decryption failures." ) private ConsumerCryptoFailureAction cryptoFailureAction; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java index 4adf1a139062a..cf45d2f8f6229 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/AutoFailoverPolicyDataImpl.java @@ -50,7 +50,7 @@ public class AutoFailoverPolicyDataImpl implements AutoFailoverPolicyData { name = "parameters", description = "The parameters applied to the auto failover policy specified by `policy_type`.\n" - + "The parameters for 'min_available' are :\n" + + "The parameters for 'min_available' are:\n" + " - 'min_limit': the limit of minimal number of available brokers in primary" + " group before auto failover\n" + " - 'usage_threshold': the resource usage threshold. If the usage of a broker" diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java index 05f0c99a8376b..f092c4605b616 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterDataImpl.java @@ -86,7 +86,7 @@ public final class ClusterDataImpl implements ClusterData, Cloneable { private String authenticationParameters; @Schema( name = "proxyProtocol", - description = "protocol to decide type of proxy routing eg: SNI-routing", + description = "Protocol to decide the type of proxy routing, e.g. SNI-routing", example = "SNI" ) private ProxyProtocol proxyProtocol; @@ -114,7 +114,7 @@ public final class ClusterDataImpl implements ClusterData, Cloneable { private boolean tlsAllowInsecureConnection; @Schema( name = "brokerClientTlsEnabledWithKeyStore", - description = "Whether internal client use KeyStore type to authenticate with other Pulsar brokers" + description = "Whether the internal client uses KeyStore type to authenticate with other Pulsar brokers" ) private boolean brokerClientTlsEnabledWithKeyStore; @Schema( diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java index 5e821f1aecc1c..bb70a532a027f 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/ClusterPoliciesImpl.java @@ -36,13 +36,13 @@ public final class ClusterPoliciesImpl implements ClusterPolicies, Cloneable { @Schema( name = "migrated", - description = "flag to check if cluster is migrated to different cluster", + description = "Flag to check if the cluster is migrated to a different cluster", example = "true/false" ) private boolean migrated; @Schema( name = "migratedClusterUrl", - description = "url of cluster where current cluster is migrated" + description = "URL of the cluster to which the current cluster is migrated" ) private ClusterUrl migratedClusterUrl; diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java index d54e156e88f09..0c38b2228a190 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TenantInfoImpl.java @@ -37,7 +37,7 @@ public class TenantInfoImpl implements TenantInfo { * List of role enabled as admin for this tenant. */ @Schema( - description = "Comma separated list of auth principal allowed to administrate the tenant.", + description = "Comma separated list of auth principals allowed to administrate the tenant.", name = "adminRoles" ) private Set adminRoles; diff --git a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java index a9c9dd2b2111d..e6f62aa4379df 100644 --- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java +++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/stats/ProxyStats.java @@ -110,7 +110,7 @@ public Map topics() { @POST @Path("/logging/{logLevel}") @Operation(hidden = true, summary = "Change proxy logging level dynamically", - description = "It only changes log-level in memory, change it config file to persist the change") + description = "It only changes the log level in memory; change it in the config file to persist the change") @ApiResponses(value = { @ApiResponse(responseCode = "412", description = "Proxy log level can be [0-2]"), }) public void updateProxyLogLevel(@PathParam("logLevel") int logLevel) { throwIfNotSuperUser("updateProxyLogLevel"); diff --git a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java index b15f1e523b06a..e193ca89e27a4 100644 --- a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java +++ b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/v2/WebSocketProxyStatsV2.java @@ -46,7 +46,8 @@ public class WebSocketProxyStatsV2 extends WebSocketProxyStatsBase { @GET @Path("/metrics") @Operation(summary = "Gets the metrics for Monitoring", - description = "Requested should be executed by Monitoring agent on each proxy to fetch the metrics") + description = "The request should be executed by the Monitoring agent on each proxy " + + "to fetch the metrics") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Gets the metrics for Monitoring", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Metrics.class)))), From 02321b0f766fe14b4debdea0fc05a77de9780da8 Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Fri, 5 Jun 2026 00:23:19 +0300 Subject: [PATCH 5/5] [improve][admin] Fold ExtPersistentTopics into PersistentTopics, fix #18947 ExtPersistentTopics/ExtNonPersistentTopics were a workaround (self-described as such in their javadoc) for https://github.com/apache/pulsar/issues/18947: the PartitionedTopicMetadata variant of createPartitionedTopic shares PUT /{tenant}/{namespace}/{topic}/partitions with the int variant, the OpenAPI specification forbids two operations on the same path and method, and the Swagger 1.x toolchain produced unstable output - so the methods were exiled into separate undocumented classes, whose implementations then drifted from the originals. At runtime Jersey disambiguates the two methods by content type (the metadata variant declares @Consumes("application/vnd.partitioned-topic-metadata+json")), and OpenAPI 3 expresses exactly that: a single operation whose requestBody carries one schema per media type. With that representation the workaround classes are unnecessary: - The metadata overload moves into PersistentTopics next to the int overload, marked @Operation(hidden = true) so the path is documented once; the visible operation's request body documents both content types (application/json -> integer, application/vnd.partitioned-topic-metadata+json -> PartitionedTopicMetadata with partitions and properties). - Both overloads share a new validateAndCreatePartitionedTopic helper. NonPersistentTopics overrides only this helper (non-persistent topics validate the topic name without the partitioned-name/policy checks), so the inherited metadata overload picks up the right validation via virtual dispatch and the duplicated, drifted method bodies are gone. - ExtPersistentTopics and ExtNonPersistentTopics are removed; PersistentTopicsTest now exercises the metadata variant through PersistentTopics. The /admin/v2 Jersey registration is package-based, so no registration changes are needed. Verified: PersistentTopicsTest passes (46/46, including the metadata-variant creation tests); two consecutive OpenAPI generation runs are byte-identical (the instability from #18947 is gone); the generated document remains operation-identical with the published 4.2.1 docs (521/521 admin v2 operations) while PUT .../partitions now documents both content types. Assisted-by: Claude Code (Opus 4.8) --- pulsar-broker/build.gradle.kts | 3 - .../admin/v2/ExtNonPersistentTopics.java | 97 ----------------- .../broker/admin/v2/ExtPersistentTopics.java | 101 ------------------ .../broker/admin/v2/NonPersistentTopics.java | 23 +++- .../broker/admin/v2/PersistentTopics.java | 44 +++++++- .../broker/admin/PersistentTopicsTest.java | 15 +-- 6 files changed, 62 insertions(+), 221 deletions(-) delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java diff --git a/pulsar-broker/build.gradle.kts b/pulsar-broker/build.gradle.kts index 2b9a8b33fe3f3..7dbd9e60de30d 100644 --- a/pulsar-broker/build.gradle.kts +++ b/pulsar-broker/build.gradle.kts @@ -256,9 +256,6 @@ registerSwaggerTask("swaggerAdminV2", "swagger", "admin-v2.json") { "org.apache.pulsar.broker.admin.v2.Namespaces", "org.apache.pulsar.broker.admin.v2.NonPersistentTopics", "org.apache.pulsar.broker.admin.v2.PersistentTopics", - // See https://github.com/apache/pulsar/issues/18947 - // "org.apache.pulsar.broker.admin.v2.ExtPersistentTopics", - // "org.apache.pulsar.broker.admin.v2.ExtNonPersistentTopics", "org.apache.pulsar.broker.admin.v2.ResourceGroups", "org.apache.pulsar.broker.admin.v2.ResourceQuotas", "org.apache.pulsar.broker.admin.v2.SchemasResource", diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java deleted file mode 100644 index a2e255f548e89..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtNonPersistentTopics.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.pulsar.broker.admin.v2; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.parameters.RequestBody; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.Encoded; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.container.AsyncResponse; -import jakarta.ws.rs.container.Suspended; -import jakarta.ws.rs.core.MediaType; -import org.apache.pulsar.broker.admin.impl.PersistentTopicsBase; -import org.apache.pulsar.common.partition.PartitionedTopicMetadata; - -/** - * This class is for preventing docs conflict before we find a good way to fix - * ISSUE-18947. - */ -@Path("/non-persistent") -@Produces(MediaType.APPLICATION_JSON) -@Tag(name = "non-persistent topic", description = "Non-Persistent topic admin apis") -@SuppressWarnings("deprecation") -public class ExtNonPersistentTopics extends PersistentTopicsBase { - - @PUT - @Consumes(PartitionedTopicMetadata.MEDIA_TYPE) - @Path("/{tenant}/{namespace}/{topic}/partitions") - @Operation(summary = "Create a partitioned topic.", - description = "It needs to be called before creating a producer on a partitioned topic.") - @ApiResponses(value = { - @ApiResponse(responseCode = "307", - description = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), - @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" - + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), - @ApiResponse(responseCode = "412", - description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), - @ApiResponse(responseCode = "500", description = "Internal server error"), - @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") - }) - public void createPartitionedTopic( - @Suspended final AsyncResponse asyncResponse, - @Parameter(description = "Specify the tenant", required = true) - @PathParam("tenant") String tenant, - @Parameter(description = "Specify the namespace", required = true) - @PathParam("namespace") String namespace, - @Parameter(description = "Specify topic name", required = true) - @PathParam("topic") @Encoded String encodedTopic, - @RequestBody(description = "The metadata for the topic", - required = true) PartitionedTopicMetadata metadata, - @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { - try { - validateNamespaceName(tenant, namespace); - validateGlobalNamespaceOwnership(); - validateTopicName(tenant, namespace, encodedTopic); - internalCreatePartitionedTopic(asyncResponse, metadata.partitions, createLocalTopicOnly, - metadata.properties); - } catch (Exception e) { - log.error() - .attr("topic", topicName) - .exception(e) - .log("Failed to create partitioned topic"); - resumeAsyncResponseExceptionally(asyncResponse, e); - } - } -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java deleted file mode 100644 index 8f907a3427980..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ExtPersistentTopics.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.pulsar.broker.admin.v2; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.parameters.RequestBody; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.Encoded; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.container.AsyncResponse; -import jakarta.ws.rs.container.Suspended; -import jakarta.ws.rs.core.MediaType; -import org.apache.pulsar.broker.admin.impl.PersistentTopicsBase; -import org.apache.pulsar.common.partition.PartitionedTopicMetadata; -import org.apache.pulsar.common.policies.data.PolicyName; -import org.apache.pulsar.common.policies.data.PolicyOperation; - -/** - * This class is for preventing docs conflict before we find a good way to fix - * ISSUE-18947. - */ -@Path("/persistent") -@Produces(MediaType.APPLICATION_JSON) -@Tag(name = "persistent topic", description = "Persistent topic admin apis") -@SuppressWarnings("deprecation") -public class ExtPersistentTopics extends PersistentTopicsBase { - - @PUT - @Consumes(PartitionedTopicMetadata.MEDIA_TYPE) - @Path("/{tenant}/{namespace}/{topic}/partitions") - @Operation(summary = "Create a partitioned topic.", - description = "It needs to be called before creating a producer on a partitioned topic.") - @ApiResponses(value = { - @ApiResponse(responseCode = "307", - description = "Current broker doesn't serve the namespace of this topic"), - @ApiResponse(responseCode = "401", - description = "Don't have permission to administrate resources on this tenant"), - @ApiResponse(responseCode = "403", description = "Don't have admin permission"), - @ApiResponse(responseCode = "404", description = "Tenant or namespace doesn't exist"), - @ApiResponse(responseCode = "406", description = "The number of partitions should be more than 0 and" - + " less than or equal to maxNumPartitionsPerPartitionedTopic"), - @ApiResponse(responseCode = "409", description = "Partitioned topic already exists"), - @ApiResponse(responseCode = "412", - description = "Failed Reason : Name is invalid or Namespace does not have any clusters configured"), - @ApiResponse(responseCode = "500", description = "Internal server error"), - @ApiResponse(responseCode = "503", description = "Failed to validate global cluster configuration") - }) - public void createPartitionedTopic( - @Suspended final AsyncResponse asyncResponse, - @Parameter(description = "Specify the tenant", required = true) - @PathParam("tenant") String tenant, - @Parameter(description = "Specify the namespace", required = true) - @PathParam("namespace") String namespace, - @Parameter(description = "Specify topic name", required = true) - @PathParam("topic") @Encoded String encodedTopic, - @RequestBody(description = "The metadata for the topic", - required = true) PartitionedTopicMetadata metadata, - @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { - try { - validateNamespaceName(tenant, namespace); - validateGlobalNamespaceOwnership(); - validatePartitionedTopicName(tenant, namespace, encodedTopic); - validateTopicPolicyOperation(topicName, PolicyName.PARTITION, PolicyOperation.WRITE); - validateCreateTopic(topicName); - internalCreatePartitionedTopic(asyncResponse, metadata.partitions, createLocalTopicOnly, - metadata.properties); - } catch (Exception e) { - log.error() - .attr("topic", topicName) - .exception(e) - .log("Failed to create partitioned topic"); - resumeAsyncResponseExceptionally(asyncResponse, e); - } - } -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java index e89633265c455..cec46d6ce452c 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -196,16 +197,30 @@ public void createPartitionedTopic( @PathParam("namespace") String namespace, @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @RequestBody(description = "The number of partitions for the topic", - required = true, - content = @Content(schema = @Schema(type = "integer", defaultValue = "0"))) + @RequestBody(description = "The number of partitions for the topic, or the partitioned topic metadata" + + " (partitions and properties) when the request is sent with the '" + + PartitionedTopicMetadata.MEDIA_TYPE + "' content type", + required = true, content = { + @Content(mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(type = "integer", defaultValue = "0")), + @Content(mediaType = PartitionedTopicMetadata.MEDIA_TYPE, + schema = @Schema(implementation = PartitionedTopicMetadata.class))}) int numPartitions, @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { + validateAndCreatePartitionedTopic(asyncResponse, tenant, namespace, encodedTopic, numPartitions, + createLocalTopicOnly, null); + } + + // Also handles the inherited 'application/vnd.partitioned-topic-metadata+json' createPartitionedTopic + // overload: non-persistent topics validate the topic name only. + @Override + protected void validateAndCreatePartitionedTopic(AsyncResponse asyncResponse, String tenant, String namespace, + String encodedTopic, int numPartitions, boolean createLocalTopicOnly, Map properties) { try { validateNamespaceName(tenant, namespace); validateGlobalNamespaceOwnership(); validateTopicName(tenant, namespace, encodedTopic); - internalCreatePartitionedTopic(asyncResponse, numPartitions, createLocalTopicOnly); + internalCreatePartitionedTopic(asyncResponse, numPartitions, createLocalTopicOnly, properties); } catch (Exception e) { log.error() .attr("topic", topicName) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java index 2301c7f7baa57..edd8da2b8c393 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java @@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.Encoded; @@ -335,17 +336,54 @@ public void createPartitionedTopic( @PathParam("namespace") String namespace, @Parameter(description = "Specify topic name", required = true) @PathParam("topic") @Encoded String encodedTopic, - @RequestBody(description = "The number of partitions for the topic", - required = true, content = @Content(schema = @Schema(type = "integer", defaultValue = "0"))) + @RequestBody(description = "The number of partitions for the topic, or the partitioned topic metadata" + + " (partitions and properties) when the request is sent with the '" + + PartitionedTopicMetadata.MEDIA_TYPE + "' content type", + required = true, content = { + @Content(mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(type = "integer", defaultValue = "0")), + @Content(mediaType = PartitionedTopicMetadata.MEDIA_TYPE, + schema = @Schema(implementation = PartitionedTopicMetadata.class))}) int numPartitions, @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { + validateAndCreatePartitionedTopic(asyncResponse, tenant, namespace, encodedTopic, numPartitions, + createLocalTopicOnly, null); + } + + @PUT + @Consumes(PartitionedTopicMetadata.MEDIA_TYPE) + @Path("/{tenant}/{namespace}/{topic}/partitions") + // hidden = true: this method shares PUT .../partitions with the overload above and OpenAPI forbids two + // operations on the same path and method (https://github.com/apache/pulsar/issues/18947). The request body + // this method accepts is documented on the overload above as the alternate + // 'application/vnd.partitioned-topic-metadata+json' content type. + @Operation(summary = "Create a partitioned topic.", + description = "It needs to be called before creating a producer on a partitioned topic.", + hidden = true) + public void createPartitionedTopic( + @Suspended final AsyncResponse asyncResponse, + @Parameter(description = "Specify the tenant", required = true) + @PathParam("tenant") String tenant, + @Parameter(description = "Specify the namespace", required = true) + @PathParam("namespace") String namespace, + @Parameter(description = "Specify topic name", required = true) + @PathParam("topic") @Encoded String encodedTopic, + @RequestBody(description = "The metadata for the topic", + required = true) PartitionedTopicMetadata metadata, + @QueryParam("createLocalTopicOnly") @DefaultValue("false") boolean createLocalTopicOnly) { + validateAndCreatePartitionedTopic(asyncResponse, tenant, namespace, encodedTopic, metadata.partitions, + createLocalTopicOnly, metadata.properties); + } + + protected void validateAndCreatePartitionedTopic(AsyncResponse asyncResponse, String tenant, String namespace, + String encodedTopic, int numPartitions, boolean createLocalTopicOnly, Map properties) { try { validateNamespaceName(tenant, namespace); validateGlobalNamespaceOwnership(); validatePartitionedTopicName(tenant, namespace, encodedTopic); validateTopicPolicyOperation(topicName, PolicyName.PARTITION, PolicyOperation.WRITE); validateCreateTopic(topicName); - internalCreatePartitionedTopic(asyncResponse, numPartitions, createLocalTopicOnly); + internalCreatePartitionedTopic(asyncResponse, numPartitions, createLocalTopicOnly, properties); } catch (Exception e) { log.error() .attr("topic", topicName) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/PersistentTopicsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/PersistentTopicsTest.java index ad9cb45e5aea3..b8945f63cc772 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/PersistentTopicsTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/PersistentTopicsTest.java @@ -59,7 +59,6 @@ import org.apache.bookkeeper.mledger.ManagedCursor; import org.apache.commons.collections4.MapUtils; import org.apache.pulsar.broker.BrokerTestUtil; -import org.apache.pulsar.broker.admin.v2.ExtPersistentTopics; import org.apache.pulsar.broker.admin.v2.NonPersistentTopics; import org.apache.pulsar.broker.admin.v2.PersistentTopics; import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; @@ -121,7 +120,6 @@ public class PersistentTopicsTest extends MockedPulsarServiceBaseTest { private PersistentTopics persistentTopics; - private ExtPersistentTopics extPersistentTopics; private final String testTenant = "my-tenant"; private final String testLocalCluster = "use"; private final String testNamespace = "my-namespace"; @@ -159,15 +157,6 @@ protected void setup() throws Exception { doNothing().when(persistentTopics).validateAdminAccessForTenant(this.testTenant); doReturn(mock(AuthenticationDataHttps.class)).when(persistentTopics).clientAuthData(); - extPersistentTopics = spy(ExtPersistentTopics.class); - extPersistentTopics.setServletContext(mock(ServletContext.class)); - extPersistentTopics.setPulsar(pulsar); - doReturn(false).when(extPersistentTopics).isRequestHttps(); - doReturn(null).when(extPersistentTopics).originalPrincipal(); - doReturn("test").when(extPersistentTopics).clientAppId(); - doReturn(TopicDomain.persistent.value()).when(extPersistentTopics).domain(); - doNothing().when(extPersistentTopics).validateAdminAccessForTenant(this.testTenant); - doReturn(mock(AuthenticationDataHttps.class)).when(extPersistentTopics).clientAuthData(); nonPersistentTopic = spy(NonPersistentTopics.class); nonPersistentTopic.setServletContext(mock(ServletContext.class)); @@ -586,7 +575,7 @@ public void testCreatePartitionedTopic() { Map topicMetadata = new HashMap<>(); topicMetadata.put("key1", "value1"); PartitionedTopicMetadata metadata = new PartitionedTopicMetadata(2, topicMetadata); - extPersistentTopics.createPartitionedTopic(response2, testTenant, testNamespace, topicName2, metadata, true); + persistentTopics.createPartitionedTopic(response2, testTenant, testNamespace, topicName2, metadata, true); Awaitility.await().untilAsserted(() -> { persistentTopics.getPartitionedMetadata(response2, testTenant, testNamespace, topicName2, true, false); @@ -692,7 +681,7 @@ public void testUpdatePartitionedTopicHavingProperties() throws Exception { ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(PartitionedTopicMetadata.class); PartitionedTopicMetadata metadata = new PartitionedTopicMetadata(2, topicMetadata); - extPersistentTopics.createPartitionedTopic(response, tenant, namespace, topic, metadata, true); + persistentTopics.createPartitionedTopic(response, tenant, namespace, topic, metadata, true); Awaitility.await().untilAsserted(() -> { persistentTopics.getPartitionedMetadata(response, tenant, namespace, topic, true, false);