diff --git a/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml b/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml index d0a77f3a4f04..fa11a5a2e4ec 100755 --- a/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml +++ b/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml @@ -1897,6 +1897,14 @@ + + + + + + + diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index 9e9481a95718..f7d026cebb78 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -187,6 +187,16 @@ azure-sdk-template 1.0.4-beta.20 + + com.azure + azure-data-schemaregistry + 1.0.0-beta.1 + + + com.azure + azure-data-schemaregistry-avro + 1.0.0-beta.1 + com.microsoft.azure azure-spring-boot @@ -208,7 +218,6 @@ 2.2.5-beta.1 - diff --git a/eng/versioning/external_dependencies.txt b/eng/versioning/external_dependencies.txt index 07ba36ba999b..89cfbd7f7aad 100644 --- a/eng/versioning/external_dependencies.txt +++ b/eng/versioning/external_dependencies.txt @@ -40,6 +40,7 @@ io.reactivex:rxjava;1.2.4 javax.annotation:javax.annotation-api;1.3.2 javax.servlet:javax.servlet-api;4.0.1 javax.validation:validation-api;2.0.1.Final +org.apache.avro:avro;1.9.2 org.apache.httpcomponents:httpclient;4.3.6 org.apache.logging.log4j:log4j-api;2.11.1 org.apache.logging.log4j:log4j-core;2.11.1 diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index 47727e35469e..254c47c2f508 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -20,6 +20,8 @@ com.azure:azure-cosmos;4.0.1-beta.3;4.0.1-beta.4 com.azure:azure-cosmos-examples;4.0.1-beta.1;4.0.1-beta.1 com.azure:azure-cosmos-benchmark;4.0.1-beta.1;4.0.1-beta.1 com.azure:azure-data-appconfiguration;1.1.1;1.2.0-beta.1 +com.azure:azure-data-schemaregistry;1.0.0-beta.1;1.0.0-beta.1 +com.azure:azure-data-schemaregistry-avro;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-e2e;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-identity;1.0.6;1.1.0-beta.5 com.azure:azure-identity-perf;1.0.0-beta.1;1.0.0-beta.1 diff --git a/pom.xml b/pom.xml index da436a3d829d..e3ed25ccadd1 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,7 @@ sdk/keyvault sdk/loganalytics sdk/mediaservices + sdk/schemaregistry sdk/search sdk/servicebus sdk/storage diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/README.md b/sdk/schemaregistry/azure-data-schemaregistry-avro/README.md new file mode 100644 index 000000000000..2eefe88c09be --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/README.md @@ -0,0 +1,17 @@ +# Azure Schema Registry Avro Serializer/Deserializer client library for Java + +This library contains Avro-specific implementations of Azure Schema Registry-back serializers and deserializers, in addition to builder classes that specify required configurations. + +This class requires a Maven dependency on `org.apache.avro:avro:1.9.2`. + +## Getting started + +## Key concepts + +## Examples + +## Troubleshooting + +## Next steps + +## Contributing diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/pom.xml b/sdk/schemaregistry/azure-data-schemaregistry-avro/pom.xml new file mode 100644 index 000000000000..1f9920fee584 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/pom.xml @@ -0,0 +1,97 @@ + + + + + + 4.0.0 + + + com.azure + azure-client-sdk-parent + 1.7.0 + ../../parents/azure-client-sdk-parent + + + com.azure + azure-data-schemaregistry-avro + 1.0.0-beta.1 + + Microsoft Azure Schema Registry - Avro-specific package for client library + Avro-specific package for Azure Schema Registry client library + https://github.com/Azure/azure-sdk-for-java + + + + azure-java-build-docs + ${site.url}/site/${project.artifactId} + + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + + true + + + + + com.azure + azure-data-schemaregistry + 1.0.0-beta.1 + + + org.apache.avro + avro + 1.9.2 + + + + + org.junit.jupiter + junit-jupiter-api + 5.6.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.6.2 + test + + + org.junit.jupiter + junit-jupiter-params + 5.6.2 + test + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M3 + + + + + com.azure:* + org.apache.avro:avro:[1.9.2] + + + + + + + + diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroByteDecoder.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroByteDecoder.java new file mode 100644 index 000000000000..9b3893583771 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroByteDecoder.java @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.ByteDecoder; +import com.azure.data.schemaregistry.SerializationException; +import org.apache.avro.Schema; +import org.apache.avro.generic.GenericDatumReader; +import org.apache.avro.io.DatumReader; +import org.apache.avro.io.DecoderFactory; +import org.apache.avro.specific.SpecificDatumReader; + +import java.io.IOException; +import java.util.Objects; + +/** + * Apache Avro ByteDecoder implementation with all Avro-specific functionality required to deserialize byte arrays + * given an Avro schema. + */ +public class AvroByteDecoder extends AvroCodec + implements ByteDecoder { + private final ClientLogger logger = new ClientLogger(AvroByteDecoder.class); + private static final DecoderFactory DECODER_FACTORY = DecoderFactory.get(); + private final boolean avroSpecificReader; + + /** + * Instantiates AvroByteDecoder instance + * @param avroSpecificReader flag indicating if attempting to decode as Avro SpecificRecord + */ + public AvroByteDecoder(boolean avroSpecificReader) { + this.avroSpecificReader = avroSpecificReader; + } + + /** + * @param b byte array containing encoded bytes + * @param object schema for Avro reader read - fetched from Azure Schema Registry + * @return deserialized object + * @throws SerializationException upon deserialization failure + */ + public Object decodeBytes(byte[] b, Object object) { + Objects.requireNonNull(object, "Schema must not be null."); + + if (!(object instanceof Schema)) { + throw logger.logExceptionAsError( + new SerializationException("Object must be an Avro schema.")); + } + Schema schema = (Schema) object; + + if (schema.getType().equals(Schema.Type.BYTES)) { + return b; + } + + DatumReader reader = getDatumReader(schema); + + try { + Object result = reader.read(null, DECODER_FACTORY.binaryDecoder(b, null)); + + if (schema.getType().equals(Schema.Type.STRING)) { + return result.toString(); + } + + return result; + } catch (IOException | RuntimeException e) { + // avro deserialization may throw AvroRuntimeException, NullPointerException, etc + throw logger.logExceptionAsError(new SerializationException("Error deserializing Avro message.", e)); + } + } + + /** + * Returns correct reader for decoding payload. + * + * @param writerSchema Avro schema fetched from schema registry store + * @return correct Avro DatumReader object given encoder configuration + */ + private DatumReader getDatumReader(Schema writerSchema) { + boolean writerSchemaIsPrimitive = AvroSchemaUtils.getPrimitiveSchemas().values().contains(writerSchema); + // do not use SpecificDatumReader if writerSchema is a primitive + if (avroSpecificReader && !writerSchemaIsPrimitive) { + return new SpecificDatumReader<>(writerSchema); + } else { + return new GenericDatumReader<>(writerSchema); + } + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroByteEncoder.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroByteEncoder.java new file mode 100644 index 000000000000..266d7cd840ca --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroByteEncoder.java @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.ByteEncoder; +import com.azure.data.schemaregistry.SerializationException; +import org.apache.avro.Schema; +import org.apache.avro.generic.GenericDatumWriter; +import org.apache.avro.io.BinaryEncoder; +import org.apache.avro.io.DatumWriter; +import org.apache.avro.io.EncoderFactory; +import org.apache.avro.specific.SpecificDatumWriter; +import org.apache.avro.specific.SpecificRecord; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * ByteEncoder implementation with all Avro-specific functionality required to serialize Java objects into byte arrays. + */ +public class AvroByteEncoder extends AvroCodec + implements ByteEncoder { + private final ClientLogger logger = new ClientLogger(AvroByteEncoder.class); + private static final EncoderFactory ENCODER_FACTORY = EncoderFactory.get(); + + /** + * @param object Schema object used to generate schema string + * @see AvroSchemaUtils for distinction between primitive and Avro schema generation + * @return string representation of schema + */ + @Override + public String getSchemaString(Object object) { + Schema schema = AvroSchemaUtils.getSchema(object); + return schema.toString(); + } + + /** + * Returns schema name for storing schemas in schema registry store. + * + * @param object Schema object used to generate schema path + * @return schema name as string + */ + @Override + public String getSchemaName(Object object) { + return AvroSchemaUtils.getSchema(object).getFullName(); + } + + /** + * Returns ByteArrayOutputStream containing Avro encoding of object parameter + * @param object Object to be encoded into byte stream + * @return closed ByteArrayOutputStream + * @throws SerializationException wraps runtime exceptions + */ + @Override + public ByteArrayOutputStream encode(Object object) { + Schema schema = AvroSchemaUtils.getSchema(object); + + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (object instanceof byte[]) { + out.write((byte[]) object); // todo: real avro byte arrays require writing array size to buffer + } else { + BinaryEncoder encoder = ENCODER_FACTORY.directBinaryEncoder(out, null); + DatumWriter writer; + if (object instanceof SpecificRecord) { + writer = new SpecificDatumWriter<>(schema); + } else { + writer = new GenericDatumWriter<>(schema); + } + writer.write(object, encoder); + encoder.flush(); + } + return out; + } catch (IOException | RuntimeException e) { + // Avro serialization can throw AvroRuntimeException, NullPointerException, ClassCastException, etc + throw logger.logExceptionAsError( + new SerializationException("Error serializing Avro message", e)); + } + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroCodec.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroCodec.java new file mode 100644 index 000000000000..bbf70f18342c --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroCodec.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.data.schemaregistry.Codec; +import org.apache.avro.Schema; + +/** + * Base Codec class for Avro encoder and decoder implementations + */ +abstract class AvroCodec implements Codec { + @Override + public String schemaType() { + return "avro"; + } + + /** + * @param schemaString string representation of schema + * @return avro schema + */ + @Override + public Schema parseSchemaString(String schemaString) { + return (new Schema.Parser()).parse(schemaString); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroSchemaUtils.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroSchemaUtils.java new file mode 100644 index 000000000000..fbdf3fd90336 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/AvroSchemaUtils.java @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.core.util.logging.ClientLogger; +import org.apache.avro.Schema; +import org.apache.avro.generic.GenericContainer; + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Utility class for Avro schema functionality. + */ +class AvroSchemaUtils { + private static final Map PRIMITIVE_SCHEMAS; + + static { + Schema.Parser parser = new Schema.Parser(); + PRIMITIVE_SCHEMAS = new HashMap<>(); + PRIMITIVE_SCHEMAS.put("Null", createPrimitiveSchema(parser, "null")); + PRIMITIVE_SCHEMAS.put("Boolean", createPrimitiveSchema(parser, "boolean")); + PRIMITIVE_SCHEMAS.put("Integer", createPrimitiveSchema(parser, "int")); + PRIMITIVE_SCHEMAS.put("Long", createPrimitiveSchema(parser, "long")); + PRIMITIVE_SCHEMAS.put("Float", createPrimitiveSchema(parser, "float")); + PRIMITIVE_SCHEMAS.put("Double", createPrimitiveSchema(parser, "double")); + PRIMITIVE_SCHEMAS.put("String", createPrimitiveSchema(parser, "string")); + PRIMITIVE_SCHEMAS.put("Bytes", createPrimitiveSchema(parser, "bytes")); + } + + /** + * Generates Avro Schema object for the specified primitive type. + * @param parser Avro schema parser + * @param type primitive schema type + * @return Avro Schema object for corresponding primitive type + */ + private static Schema createPrimitiveSchema(Schema.Parser parser, String type) { + String schemaString = String.format("{\"type\" : \"%s\"}", type); + return parser.parse(schemaString); + } + + /** + * Maintains map of primitive schemas. + * @return Map containing string representation of primitive type to corresponding Avro primitive schema + */ + public static Map getPrimitiveSchemas() { + return Collections.unmodifiableMap(PRIMITIVE_SCHEMAS); + } + + /** + * Returns Avro schema for specified object, including null values + * + * @param object object for which Avro schema is being returned + * @return Avro schema for object's data structure + * + * @throws IllegalArgumentException if object type is unsupported + */ + public static Schema getSchema(Object object) throws IllegalArgumentException { + if (object == null) { + return PRIMITIVE_SCHEMAS.get("Null"); + } else if (object instanceof Boolean) { + return PRIMITIVE_SCHEMAS.get("Boolean"); + } else if (object instanceof Integer) { + return PRIMITIVE_SCHEMAS.get("Integer"); + } else if (object instanceof Long) { + return PRIMITIVE_SCHEMAS.get("Long"); + } else if (object instanceof Float) { + return PRIMITIVE_SCHEMAS.get("Float"); + } else if (object instanceof Double) { + return PRIMITIVE_SCHEMAS.get("Double"); + } else if (object instanceof CharSequence) { + return PRIMITIVE_SCHEMAS.get("String"); + } else if (object instanceof byte[] || object instanceof ByteBuffer) { + return PRIMITIVE_SCHEMAS.get("Bytes"); + } else if (object instanceof GenericContainer) { + return ((GenericContainer) object).getSchema(); + } else { + ClientLogger logger = new ClientLogger(AvroSchemaUtils.class); + throw logger.logExceptionAsError( + new IllegalArgumentException( + "Unsupported Avro type. Supported types are null, Boolean, Integer, Long, " + + "Float, Double, String, byte[] and IndexedRecord")); + } + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroAsyncDeserializer.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroAsyncDeserializer.java new file mode 100644 index 000000000000..e43ab1de10f5 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroAsyncDeserializer.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.data.schemaregistry.SerializationException; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.util.concurrent.Executors; + +/** + * Asynchronous registry-based deserializer implementation. + */ +public class SchemaRegistryAvroAsyncDeserializer { + private static final int DEFAULT_THREAD_POOL_SIZE = 8; + + private final SchemaRegistryAvroDeserializer deserializer; + private final Scheduler scheduler; + + /** + * Instantiates instance of async deserializer. + * + * @param deserializer synchronous internal deserializer implementation + */ + SchemaRegistryAvroAsyncDeserializer(SchemaRegistryAvroDeserializer deserializer) { + this.deserializer = deserializer; + this.scheduler = Schedulers.fromExecutor(Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE)); + } + + /** + * Async wrapper around synchronous deserialization method + * @param data bytes containing schema ID and encoded byte representation of object + * @return Mono wrapper around deserialized object + * @throws SerializationException if deserialization operation fails + */ + public Mono deserialize(byte[] data) throws SerializationException { + return Mono + .fromCallable(() -> this.deserializer.deserialize(data)) + .subscribeOn(scheduler); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroAsyncSerializer.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroAsyncSerializer.java new file mode 100644 index 000000000000..7d8edfb020ba --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroAsyncSerializer.java @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.data.schemaregistry.AbstractDataSerializer; +import com.azure.data.schemaregistry.SerializationException; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.util.concurrent.Executors; + +/** + * Asynchronous registry-based serializer implementation. + */ +public class SchemaRegistryAvroAsyncSerializer extends AbstractDataSerializer { + private static final int DEFAULT_THREAD_POOL_SIZE = 8; + + private final SchemaRegistryAvroSerializer serializer; + private final Scheduler scheduler; + + /** + * @param serializer synchronous Avro serializer implementation + */ + SchemaRegistryAvroAsyncSerializer(SchemaRegistryAvroSerializer serializer) { + this.serializer = serializer; + this.scheduler = Schedulers.fromExecutor(Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE)); + } + + /** + * Async wrapper around sync serialization operation + * + * @param object object to be serialized to bytes + * @return Avro byte representation of object + * @throws SerializationException upon serialization operation failure + */ + public Mono serialize(Object object) throws SerializationException { + if (object == null) { + return Mono.empty(); + } + + return Mono + .fromCallable(() -> this.serializer.serialize(object)) + .subscribeOn(scheduler); + } +} + diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroDeserializer.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroDeserializer.java new file mode 100644 index 000000000000..c683ebc2ec9d --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroDeserializer.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.data.schemaregistry.AbstractDataDeserializer; +import com.azure.data.schemaregistry.SerializationException; +import com.azure.data.schemaregistry.client.CachedSchemaRegistryClient; + +/** + * A deserializer implementation capable of automatedly deserializing encoded byte array payloads into Java objects by + * fetching payload-specified schemas from the Azure Schema Registry store. + *

+ * SchemaRegistryAvroDeserializer instances should be built using the static Builder class. + *

+ * Pluggable with the core Azure SDK Deserializer interface. + * + * @see AbstractDataDeserializer See AbstractDataDeserializer for internal deserialization implementation + */ +public class SchemaRegistryAvroDeserializer extends AbstractDataDeserializer { + SchemaRegistryAvroDeserializer(CachedSchemaRegistryClient registryClient, boolean avroSpecificReader) { + super(registryClient); + + loadByteDecoder(new AvroByteDecoder(avroSpecificReader)); + } + + /** + * Deserializes byte array into Java object using payload-specified schema. + * + * @param data Byte array containing serialized bytes + * @return decoded Java object + * + * @throws SerializationException Throws on deserialization failure. + * Exception may contain inner exceptions detailing failure condition. + */ + public Object deserialize(byte[] data) throws SerializationException { + return super.deserialize(data); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroDeserializerBuilder.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroDeserializerBuilder.java new file mode 100644 index 000000000000..f661ee5d7b3f --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroDeserializerBuilder.java @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.core.credential.TokenCredential; +import com.azure.data.schemaregistry.client.CachedSchemaRegistryClient; +import com.azure.data.schemaregistry.client.CachedSchemaRegistryClientBuilder; + +import java.util.Objects; + +/** + * Builder class for constructing {@link SchemaRegistryAvroDeserializer} and {@link SchemaRegistryAvroAsyncDeserializer} + */ +public class SchemaRegistryAvroDeserializerBuilder { + + private String registryUrl; + private TokenCredential credential; + private boolean avroSpecificReader; + private Integer maxSchemaMapSize; + + /** + * Instantiates instance of Builder class. + * Supplies default avro.specific.reader value. + * + */ + public SchemaRegistryAvroDeserializerBuilder() { + this.registryUrl = null; + this.credential = null; + this.avroSpecificReader = false; + this.maxSchemaMapSize = null; + } + + /** + * Sets the service endpoint for the Azure Schema Registry instance. + * + * @return The updated {@link SchemaRegistryAvroDeserializerBuilder} object. + * @param schemaRegistryUrl The URL of the Azure Schema Registry instance + * @throws NullPointerException if {@code schemaRegistryUrl} is null + */ + public SchemaRegistryAvroDeserializerBuilder schemaRegistryUrl(String schemaRegistryUrl) { + Objects.requireNonNull(schemaRegistryUrl, "'schemaRegistryUrl' cannot be null."); + this.registryUrl = schemaRegistryUrl; + return this; + } + + /** + * + * @param credential TokenCredential to be used for authenticating with Azure Schema Registry Service + * @return updated {@link SchemaRegistryAvroDeserializerBuilder} instance + */ + public SchemaRegistryAvroDeserializerBuilder credential(TokenCredential credential) { + this.credential = credential; + return this; + } + + /** + * Specifies if objects should be deserialized into Avro SpecificRecords via Avro SpecificDatumReader + * @param avroSpecificReader specific reader flag + * @return updated {@link SchemaRegistryAvroDeserializerBuilder} instance + */ + public SchemaRegistryAvroDeserializerBuilder avroSpecificReader(boolean avroSpecificReader) { + this.avroSpecificReader = avroSpecificReader; + return this; + } + + /** + * Specifies maximum schema object cache size for underlying CachedSchemaRegistryClient. If specified cache + * size is exceeded, all caches are recycled. + * + * @param maxSchemaMapSize maximum number of schemas per cache + * @return updated {@link SchemaRegistryAvroDeserializerBuilder} instance + */ + public SchemaRegistryAvroDeserializerBuilder maxSchemaMapSize(int maxSchemaMapSize) { + this.maxSchemaMapSize = maxSchemaMapSize; + return this; + } + + /** + * Construct instance of {@link SchemaRegistryAvroAsyncDeserializer} + * + * @return {@link SchemaRegistryAvroAsyncDeserializer} instance + * + * @throws NullPointerException if parameters are incorrectly set. + * @throws IllegalArgumentException if credential is not set. + */ + public SchemaRegistryAvroAsyncDeserializer buildAsyncClient() { + return new SchemaRegistryAvroAsyncDeserializer(this.buildSyncClient()); + } + + /** + * Construct instance of {@link SchemaRegistryAvroDeserializer} + * + * @return {@link SchemaRegistryAvroDeserializer} instance + * + * @throws NullPointerException if parameters are incorrectly set. + * @throws IllegalArgumentException if credential is not set. + */ + public SchemaRegistryAvroDeserializer buildSyncClient() { + CachedSchemaRegistryClient client = new CachedSchemaRegistryClientBuilder() + .endpoint(registryUrl) + .credential(credential) + .maxSchemaMapSize(maxSchemaMapSize) + .buildClient(); + return new SchemaRegistryAvroDeserializer(client, this.avroSpecificReader); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroSerializer.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroSerializer.java new file mode 100644 index 000000000000..03791b6ba264 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroSerializer.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.data.schemaregistry.AbstractDataSerializer; +import com.azure.data.schemaregistry.SerializationException; +import com.azure.data.schemaregistry.client.CachedSchemaRegistryClient; + +/** + * A serializer implementation capable of serializing objects and automatedly storing serialization schemas + * in the Azure Schema Registry store. + * + * SchemaRegistryAvroSerializer instances should be built using the static Builder class. + * + * Pluggable with the core Azure SDK Serializer interface. + * + * @see AbstractDataSerializer See AbstractDataSerializer for internal serialization implementation + */ +public class SchemaRegistryAvroSerializer extends AbstractDataSerializer { + SchemaRegistryAvroSerializer(CachedSchemaRegistryClient registryClient, + String schemaGroup, + boolean autoRegisterSchemas) { + super(registryClient); + + setByteEncoder(new AvroByteEncoder()); + + this.autoRegisterSchemas = autoRegisterSchemas; + this.schemaGroup = schemaGroup; + } + + /** + * Serializes object into byte array payload using the configured byte encoder. + * @param object target of serialization + * @return byte array containing GUID reference to schema, then the object serialized into bytes + * @throws SerializationException Throws on serialization failure. + */ + public byte[] serialize(Object object) throws SerializationException { + if (object == null) { + return null; + } + return serializeImpl(object); + } +} + diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroSerializerBuilder.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroSerializerBuilder.java new file mode 100644 index 000000000000..50145d43b37c --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/SchemaRegistryAvroSerializerBuilder.java @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import com.azure.core.credential.TokenCredential; +import com.azure.data.schemaregistry.AbstractDataSerializer; +import com.azure.data.schemaregistry.client.CachedSchemaRegistryClient; +import com.azure.data.schemaregistry.client.CachedSchemaRegistryClientBuilder; + +import java.util.Objects; + +/** + * Builder implemenation for building {@link SchemaRegistryAvroSerializer} and {@link SchemaRegistryAvroAsyncSerializer} + */ +public final class SchemaRegistryAvroSerializerBuilder { + private String registryUrl; + private TokenCredential credential; + private boolean autoRegisterSchemas; + private String schemaGroup; + private Integer maxSchemaMapSize; + + /** + * Instantiates instance of Builder class. + * Supplies client defaults. + */ + private SchemaRegistryAvroSerializerBuilder() { + this.registryUrl = null; + this.credential = null; + this.autoRegisterSchemas = AbstractDataSerializer.AUTO_REGISTER_SCHEMAS_DEFAULT; + this.schemaGroup = AbstractDataSerializer.SCHEMA_GROUP_DEFAULT; + this.maxSchemaMapSize = null; + } + + /** + * Sets the service endpoint for the Azure Schema Registry instance. + * + * @return The updated {@link SchemaRegistryAvroSerializerBuilder} object. + * @param schemaRegistryUrl The URL of the Azure Schema Registry instance + * @throws NullPointerException if {@code schemaRegistryUrl} is null + */ + public SchemaRegistryAvroSerializerBuilder schemaRegistryUrl(String schemaRegistryUrl) { + Objects.requireNonNull(schemaRegistryUrl, "'schemaRegistryUrl' cannot be null."); + this.registryUrl = schemaRegistryUrl; + return this; + } + + /** + * Specifies schema group for interacting with Azure Schema Registry service. + * + * If auto-registering schemas, schema will be stored under this group. + * If not auto-registering, serializer will request schema ID for matching data schema under specified group. + * + * @param schemaGroup Azure Schema Registry schema group + * @return updated {@link SchemaRegistryAvroSerializerBuilder} instance + */ + public SchemaRegistryAvroSerializerBuilder schemaGroup(String schemaGroup) { + this.schemaGroup = schemaGroup; + return this; + } + + /** + * Specifies authentication behavior with Azure Schema Registry + * @param credential TokenCredential to be used to authenticate with Azure Schema Registry service + * @return updated {@link SchemaRegistryAvroSerializerBuilder} instance + */ + public SchemaRegistryAvroSerializerBuilder credential(TokenCredential credential) { + this.credential = credential; + return this; + } + + /** + * If specified true, serializer will register schemas against Azure Schema Registry service under the specified + * group. See Azure Schema Registry documentation for a description of schema registration behavior. + * + * If specified false, serializer will simply query the service for an existing ID given schema content. + * Serialization will fail if the schema has not been pre-created. + * + * Auto-registration is **NOT RECOMMENDED** for production scenarios. + * + * @param autoRegisterSchemas flag for schema auto-registration + * @return updated {@link SchemaRegistryAvroSerializerBuilder} instance + */ + public SchemaRegistryAvroSerializerBuilder autoRegisterSchema(boolean autoRegisterSchemas) { + this.autoRegisterSchemas = autoRegisterSchemas; + return this; + } + + /** + * Specifies maximum schema object cache size for underlying CachedSchemaRegistryClient. If specified cache + * size is exceeded, all caches are recycled. + * + * @param maxSchemaMapSize maximum number of schemas per cache + * @return updated {@link SchemaRegistryAvroSerializerBuilder} instance + */ + public SchemaRegistryAvroSerializerBuilder maxSchemaMapSize(int maxSchemaMapSize) { + this.maxSchemaMapSize = maxSchemaMapSize; + return this; + } + + /** + * Instantiates SchemaRegistry + * @return {@link SchemaRegistryAvroAsyncSerializer} instance + * + * @throws NullPointerException if parameters are incorrectly set. + * @throws IllegalArgumentException if credential is not set. + */ + public SchemaRegistryAvroAsyncSerializer buildAsyncClient() { + return new SchemaRegistryAvroAsyncSerializer(this.buildSyncClient()); + } + + /** + * Instantiates {@link SchemaRegistryAvroSerializer} + * @return {@link SchemaRegistryAvroSerializer} instance + * + * @throws NullPointerException if parameters are incorrectly set. + * @throws IllegalArgumentException if credential is not set. + */ + public SchemaRegistryAvroSerializer buildSyncClient() { + CachedSchemaRegistryClient client = new CachedSchemaRegistryClientBuilder() + .endpoint(registryUrl) + .credential(credential) + .maxSchemaMapSize(maxSchemaMapSize) + .buildClient(); + + return new SchemaRegistryAvroSerializer(client, this.schemaGroup, this.autoRegisterSchemas); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/package-info.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/package-info.java new file mode 100644 index 000000000000..815a7707a645 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/java/com/azure/data/schemaregistry/avro/package-info.java @@ -0,0 +1,5 @@ +/** + * Package containing Avro-specific serializer and deserializer implementations. + * Also contains the Avro codec utility classes required for all serde operations. + */ +package com.azure.data.schemaregistry.avro; diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/module-info.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/module-info.java new file mode 100644 index 000000000000..69127c51a063 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/main/module-info.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +module com.azure.data.schemaregistry.avro { + requires transitive com.azure.core; + + exports com.azure.data.schemaregistry.avro; +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/test/java/com/azure/data/schemaregistry/avro/AvroByteDecoderTest.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/test/java/com/azure/data/schemaregistry/avro/AvroByteDecoderTest.java new file mode 100644 index 000000000000..6732085e8911 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/test/java/com/azure/data/schemaregistry/avro/AvroByteDecoderTest.java @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AvroByteDecoderTest { + @Test + public void testShouldAnswerWithTrue() { + assertTrue(true); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry-avro/src/test/java/com/azure/data/schemaregistry/avro/AvroByteEncoderTest.java b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/test/java/com/azure/data/schemaregistry/avro/AvroByteEncoderTest.java new file mode 100644 index 000000000000..2f3188989917 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry-avro/src/test/java/com/azure/data/schemaregistry/avro/AvroByteEncoderTest.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.avro; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AvroByteEncoderTest { + private static final String MOCK_AVRO_SCHEMA_STRING = "{\"namespace\":\"example2.avro\",\"type\":\"record\",\"name\":\"User\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"favorite_number\",\"type\": [\"int\", \"null\"]}]}"; + + @Test + public void testPlaceholder() { + getEncoder(); + assertTrue(true); + } + + private AvroByteEncoder getEncoder() { + return new AvroByteEncoder(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/README.md b/sdk/schemaregistry/azure-data-schemaregistry/README.md new file mode 100644 index 000000000000..19eaf0f2e8e4 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/README.md @@ -0,0 +1,19 @@ +# Azure Schema Registry shared library for Java + +This library contains common implementations for Azure Schema Registry-backed serializers and deserializers. + +## Getting started + +## Key concepts + +Using registry-backed serializers and deserializers allows schema information such as names and types of fields to be held externally in schema documents, allowing serialization and deserialization frameworks to produce very compact on-wire representations of structured data (e.g. payload of events and messages). To democratize schema handling for all clients, all parties who need to serialize or deserialize event or message payloads require consistent access to the same schema store. + +The serialization and deserialization implementations in this library utilize the `CachedSchemaRegistryClient` class to register and fetch schemas in Azure Schema Registry. + +## Examples + +## Troubleshooting + +## Next steps + +## Contributing diff --git a/sdk/schemaregistry/azure-data-schemaregistry/pom.xml b/sdk/schemaregistry/azure-data-schemaregistry/pom.xml new file mode 100644 index 000000000000..a1da5396df35 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/pom.xml @@ -0,0 +1,90 @@ + + + + 4.0.0 + + + com.azure + azure-client-sdk-parent + 1.7.0 + ../../parents/azure-client-sdk-parent + + + com.azure + azure-data-schemaregistry + jar + 1.0.0-beta.1 + + Microsoft Azure Schema Registry - Common Client/SerDe Package for client library + + Common SerDe Package containing client and base serialization/deserialization implementation for Azure Schema Registry client library + + https://github.com/Azure/azure-sdk-for-java + + + + azure-java-build-docs + ${site.url}/site/${project.artifactId} + + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + + true + + + + + com.azure + azure-core + 1.5.0 + + + com.azure + azure-core-http-netty + 1.5.1 + + + + + org.junit.jupiter + junit-jupiter-api + 5.6.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.6.2 + test + + + org.junit.jupiter + junit-jupiter-params + 5.6.2 + test + + + org.mockito + mockito-core + 3.0.0 + test + + + org.apache.avro + avro + 1.9.2 + test + + + diff --git a/sdk/schemaregistry/azure-data-schemaregistry/resources/azure-data-schemaregistry-client.properties b/sdk/schemaregistry/azure-data-schemaregistry/resources/azure-data-schemaregistry-client.properties new file mode 100644 index 000000000000..ca812989b4f2 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/resources/azure-data-schemaregistry-client.properties @@ -0,0 +1,2 @@ +name=${project.artifactId} +version=${project.version} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataDeserializer.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataDeserializer.java new file mode 100644 index 000000000000..436a73a2b937 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataDeserializer.java @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.client.SchemaRegistryObject; +import com.azure.data.schemaregistry.client.SchemaRegistryClient; +import com.azure.data.schemaregistry.client.SchemaRegistryClientException; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Common implementation for all registry-based deserializers. + */ +public abstract class AbstractDataDeserializer extends AbstractDataSerDe { + private final ClientLogger logger = new ClientLogger(AbstractDataDeserializer.class); + + private final Map byteDecoderMap = new ConcurrentHashMap<>(); + + /** + * Constructor called by all concrete implementation constructors. + * Should only call parent constructor. + * @param schemaRegistryClient client to be used for fetching schemas by ID + */ + protected AbstractDataDeserializer(SchemaRegistryClient schemaRegistryClient) { + super(schemaRegistryClient); + } + + /** + * Special case constructor for Kafka deserializer's empty constructors. + */ + protected AbstractDataDeserializer() { } + + /** + * Fetches schema referenced by prefixed ID and deserializes the subsequent payload into Java object. + * + * @param payload byte payload, produced by an Azure Schema Registry client producer + * @return object, deserialized with the prefixed schema + * @throws SerializationException if deserialization of registry schema or message payload fails. + */ + protected Object deserialize(byte[] payload) throws SerializationException { + if (payload == null) { + return null; + } + + ByteBuffer buffer = ByteBuffer.wrap(payload); + String schemaGuid = getSchemaGuidFromPayload(buffer); + SchemaRegistryObject registryObject; + Object payloadSchema; + + try { + registryObject = this.schemaRegistryClient.getSchemaByGuid(schemaGuid); + payloadSchema = registryObject.deserialize(); + } catch (SchemaRegistryClientException e) { + throw logger.logExceptionAsError( + new SerializationException(String.format("Failed to retrieve schema for id %s", schemaGuid), e)); + } + + if (payloadSchema == null) { + throw logger.logExceptionAsError( + new SerializationException( + String.format("Payload schema returned as null. Schema type: %s, Schema ID: %s", + registryObject.getSchemaType(), registryObject.getSchemaId()))); + } + + int start = buffer.position() + buffer.arrayOffset(); + int length = buffer.limit() - AbstractDataSerDe.SCHEMA_ID_SIZE; + byte[] b = Arrays.copyOfRange(buffer.array(), start, start + length); + + ByteDecoder byteDecoder = getByteDecoder(registryObject); + return byteDecoder.decodeBytes(b, payloadSchema); + } + + + /** + * Fetches the correct ByteDecoder based on schema type of the message. + * + * @param registryObject object returned from SchemaRegistryClient, contains schema type + * @return ByteDecoder to be used to deserialize encoded payload bytes + * @throws SerializationException if decoder for the required schema type has not been loaded + */ + private ByteDecoder getByteDecoder(SchemaRegistryObject registryObject) throws SerializationException { + ByteDecoder decoder = byteDecoderMap.get(registryObject.getSchemaType()); + if (decoder == null) { + throw logger.logExceptionAsError( + new SerializationException( + String.format("No decoder class found for schema type '%s'", registryObject.getSchemaType()) + )); + } + return decoder; + } + + /** + * @param buffer full payload bytes + * @return String representation of schema ID + * @throws SerializationException if schema ID could not be extracted from payload + */ + private String getSchemaGuidFromPayload(ByteBuffer buffer) throws SerializationException { + byte[] schemaGuidByteArray = new byte[AbstractDataSerDe.SCHEMA_ID_SIZE]; + try { + buffer.get(schemaGuidByteArray); + } catch (BufferUnderflowException e) { + throw logger.logExceptionAsError(new SerializationException("Payload too short, no readable guid.", e)); + } + + return new String(schemaGuidByteArray, schemaRegistryClient.getEncoding()); + } + + /** + * Loads a ByteDecoder to be used for decoding message payloads of specified schema type. + * @param decoder ByteDecoder class instance to be loaded + */ + protected void loadByteDecoder(ByteDecoder decoder) { + if (decoder == null) { + throw logger.logExceptionAsError(new SerializationException("ByteDecoder cannot be null")); + } + + this.byteDecoderMap.put(decoder.schemaType(), decoder); + this.schemaRegistryClient.addSchemaParser(decoder); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataSerDe.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataSerDe.java new file mode 100644 index 000000000000..b2bc450371b6 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataSerDe.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.client.SchemaRegistryClient; + +/** + * Common fields and helper methods for both the serializer and the deserializer. + */ +public abstract class AbstractDataSerDe { + private final ClientLogger logger = new ClientLogger(AbstractDataSerDe.class); + + public static final int SCHEMA_ID_SIZE = 32; + + protected SchemaRegistryClient schemaRegistryClient; + + /** + * Base constructor for all SerDe implementations. + * @param schemaRegistryClient client to be used for sending or fetching schemas. + * @throws IllegalArgumentException schemaRegistryClient parameter cannot be null + */ + protected AbstractDataSerDe(SchemaRegistryClient schemaRegistryClient) { + if (schemaRegistryClient == null) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Schema registry client must be initialized and passed into builder.")); + } + this.schemaRegistryClient = schemaRegistryClient; + } + + /** + * Special case for Kafka serializer/deserializer implementations. + */ + // special case for Kafka serializer/deserializer + public AbstractDataSerDe() { + + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataSerializer.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataSerializer.java new file mode 100644 index 000000000000..74784e54e37d --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/AbstractDataSerializer.java @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.client.SchemaRegistryClient; +import com.azure.data.schemaregistry.client.SchemaRegistryClientException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * Common implementation for all registry-based serializers. + */ +public abstract class AbstractDataSerializer extends AbstractDataSerDe { + private final ClientLogger logger = new ClientLogger(AbstractDataSerializer.class); + + public static final Boolean AUTO_REGISTER_SCHEMAS_DEFAULT = false; + public static final String SCHEMA_GROUP_DEFAULT = "$default"; + + protected ByteEncoder byteEncoder = null; + protected String schemaType; + protected Boolean autoRegisterSchemas = AbstractDataSerializer.AUTO_REGISTER_SCHEMAS_DEFAULT; + protected String schemaGroup = AbstractDataSerializer.SCHEMA_GROUP_DEFAULT; + + /** + * @param schemaRegistryClient registry client to be used for storing schemas. Not null. + */ + public AbstractDataSerializer(SchemaRegistryClient schemaRegistryClient) { + super(schemaRegistryClient); + } + + /** + * Special case constructor for Kafka serializer. + */ + public AbstractDataSerializer() { + } + + /** + * Set ByteEncoder class to be used for serialized objects into bytes + * @param byteEncoder ByteEncoder instance + */ + protected void setByteEncoder(ByteEncoder byteEncoder) { + if (this.byteEncoder != null) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Setting multiple encoders on serializer not permitted")); + } + this.byteEncoder = byteEncoder; + this.schemaType = byteEncoder.schemaType(); + this.schemaRegistryClient.addSchemaParser(byteEncoder); + } + + /** + * Core implementation of registry-based serialization. + * ID for data schema is fetched from the registry and prefixed to the encoded byte array + * representation of the object param. + * + * @param object object to be serialized + * @return byte array containing encoded bytes with prefixed schema ID + * @throws SerializationException if serialization operation fails during runtime. + */ + protected byte[] serializeImpl(Object object) { + if (object == null) { + throw logger.logExceptionAsError(new SerializationException( + "Null object, behavior should be defined in concrete serializer implementation.")); + } + + if (byteEncoder == null) { + throw logger.logExceptionAsError( + new SerializationException("Byte encoder null, serializer must be initialized with a byte encoder.")); + } + + if (schemaType == null) { + schemaType = byteEncoder.schemaType(); + } + + String schemaString = byteEncoder.getSchemaString(object); + String schemaName = byteEncoder.getSchemaName(object); + + try { + String schemaGuid = maybeRegisterSchema( + this.schemaGroup, schemaName, schemaString, this.schemaType); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteBuffer guidBuffer = ByteBuffer.allocate(AbstractDataSerDe.SCHEMA_ID_SIZE) + .put(schemaGuid.getBytes(StandardCharsets.UTF_8)); + out.write(guidBuffer.array()); + byteEncoder.encode(object).writeTo(out); + return out.toByteArray(); + } catch (SchemaRegistryClientException | IOException e) { + if (this.autoRegisterSchemas) { + throw logger.logExceptionAsError( + new SerializationException( + String.format("Error registering Avro schema. Group: %s, name: %s", schemaGroup, schemaName), + e)); + } else { + throw logger.logExceptionAsError( + new SerializationException( + String.format("Error retrieving Avro schema. Group: %s, name: %s", schemaGroup, schemaName), + e)); + } + } + } + + /** + * If auto-registering is enabled, register schema against SchemaRegistryClient. + * If auto-registering is disabled, fetch schema ID for provided schema. Requires pre-registering of schema + * against registry. + * + * @param schemaGroup Schema group where schema should be registered. + * @param schemaName name of schema + * @param schemaString string representation of schema being stored - must match group schema type + * @param schemaType type of schema being stored, e.g. avro + * @return string representation of schema ID + * @throws SchemaRegistryClientException upon registry client operation failure + */ + private String maybeRegisterSchema( + String schemaGroup, String schemaName, String schemaString, String schemaType) + throws SchemaRegistryClientException { + if (this.autoRegisterSchemas) { + return this.schemaRegistryClient.register(schemaGroup, schemaName, schemaString, schemaType) + .getSchemaId(); + } else { + return this.schemaRegistryClient.getSchemaId( + schemaGroup, schemaName, schemaString, schemaType); + } + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/ByteDecoder.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/ByteDecoder.java new file mode 100644 index 000000000000..70a06f339afb --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/ByteDecoder.java @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +/** + * An interface defining operations required for registry deserializer to convert encoded bytes to Java object. + */ +public interface ByteDecoder extends Codec { + /** + * Decodes byte array into Object given provided schema object. + * @param encodedBytes payload to be decoded + * @param schemaObject object used to decode the payload + * @return deserialized object + * @throws SerializationException if decode operation fails + */ + Object decodeBytes(byte[] encodedBytes, Object schemaObject) throws SerializationException; +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/ByteEncoder.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/ByteEncoder.java new file mode 100644 index 000000000000..65116e772250 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/ByteEncoder.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import java.io.ByteArrayOutputStream; + +/** + * An interface defining operations required for registry serializer to convert object to bytes. + */ +public interface ByteEncoder extends Codec { + /** + * Return schema name for storing in registry store + * @param object Schema object + * Refer to Schema Registry documentation for information on schema grouping and naming. + * + * @return schema name + * @throws SerializationException runtime exception in error cases + */ + String getSchemaName(Object object) throws SerializationException; + + /** + * Returns string representation of schema object to be stored in the service. + * + * @param object Schema object used to generate schema string + * @return String representation of schema object parameter + * @throws SerializationException if generating string representation of schema fails + */ + String getSchemaString(Object object); + + // TODO: Method does not currently require schema object to be passed since schemas can be derived from + // Avro objects. JSON implementation would be the same. + /** + * Converts object into stream containing the encoded representation of the object. + * @param object Object to be encoded into byte stream + * @return output stream containing byte representation of object + * @throws SerializationException if generating byte representation of object fails + */ + ByteArrayOutputStream encode(Object object); +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/Codec.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/Codec.java new file mode 100644 index 000000000000..cf99962f9ff6 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/Codec.java @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +/** + * Base interface for all ByteEncoder and ByteDecoder interfaces + */ +public interface Codec { + /** + * @return String representation of schema type, e.g. "avro" or "json". + * + * Utilized by schema registry store and client as non-case-sensitive tags for + * schemas of a specific type. + */ + String schemaType(); + + /** + * Parses string representation of schema into schema Object + * @param schemaString string representation of schema + * @return schema object to be used for decoding payloads + */ + Object parseSchemaString(String schemaString); +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/SerializationException.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/SerializationException.java new file mode 100644 index 000000000000..a4f6b5f6065e --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/SerializationException.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.core.exception.AzureException; + +/** + * Exception thrown by Schema Registry serializer/deserializer implementations for runtime error cases. + */ +public class SerializationException extends AzureException { + /** + * @param s error message explaining serde operation failure + */ + public SerializationException(String s) { + super(s); + } + + /** + * @param s error message explaining serde operation failure + * @param cause Throwable cause of serialization failure + */ + public SerializationException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClient.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClient.java new file mode 100644 index 000000000000..7202cd2752dc --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClient.java @@ -0,0 +1,261 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client; + +import com.azure.core.annotation.ServiceClient; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.Codec; +import com.azure.data.schemaregistry.client.implementation.AzureSchemaRegistryRestService; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemaByIdResponse; +import com.azure.data.schemaregistry.client.implementation.models.SchemaId; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.function.Function; + +/** + * HTTP-based client that interacts with Azure Schema Registry service to store and retrieve schemas on demand. + *

+ * Utilizes in-memory {@link Map} caching to minimize network I/O. Max size can be configured when instantiating by + * using {@link CachedSchemaRegistryClientBuilder#maxSchemaMapSize}, otherwise {@code 1000} will be used as the default. + *

+ * Two maps are maintained. + *

    + *
  • SchemaRegistryObject cache by GUID - stores GUIDs previously seen in payloads.
  • + *
  • SchemaRegistryObject cache by schema string - minimizes HTTP calls when sending payloads of same schema.
  • + *
+ *

+ * + * @see SchemaRegistryClient Implements SchemaRegistryClient interface to allow for testing with mock + * @see CachedSchemaRegistryClientBuilder Follows builder pattern for object instantiation + */ +@ServiceClient( + builder = CachedSchemaRegistryClientBuilder.class, + serviceInterfaces = AzureSchemaRegistryRestService.class) +public final class CachedSchemaRegistryClient implements SchemaRegistryClient { + private final ClientLogger logger = new ClientLogger(CachedSchemaRegistryClient.class); + + public static final Charset SCHEMA_REGISTRY_SERVICE_ENCODING = StandardCharsets.UTF_8; + static final int MAX_SCHEMA_MAP_SIZE_DEFAULT = 1000; + static final int MAX_SCHEMA_MAP_SIZE_MINIMUM = 10; + + private final AzureSchemaRegistryRestService restService; + private final Integer maxSchemaMapSize; + private final ConcurrentSkipListMap> typeParserMap; + private final Map idCache; + private final Map schemaStringCache; + + CachedSchemaRegistryClient( + AzureSchemaRegistryRestService restService, + int maxSchemaMapSize, + ConcurrentSkipListMap> typeParserMap) { + this.restService = restService; + this.maxSchemaMapSize = maxSchemaMapSize; + this.typeParserMap = typeParserMap; + this.idCache = new ConcurrentHashMap<>(); + this.schemaStringCache = new ConcurrentHashMap<>(); + } + + // testing - todo remove constructor and replace with mock + CachedSchemaRegistryClient( + AzureSchemaRegistryRestService restService, + Map idCache, + Map schemaStringCache, + ConcurrentSkipListMap> typeParserMap) { + this.restService = restService; // mockable + this.idCache = idCache; + this.schemaStringCache = schemaStringCache; + this.typeParserMap = typeParserMap; + this.maxSchemaMapSize = MAX_SCHEMA_MAP_SIZE_DEFAULT; + } + + /** + * @return Azure Schema Registry service string encoding + */ + @Override + public Charset getEncoding() { + return CachedSchemaRegistryClient.SCHEMA_REGISTRY_SERVICE_ENCODING; + } + + /** + * @param codec Codec class implementation + * @throws IllegalArgumentException on bad schema type or if parser for schema type has already been registered + */ + public void addSchemaParser(Codec codec) { + if (CoreUtils.isNullOrEmpty(codec.schemaType())) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Serialization type cannot be null or empty.")); + } + if (this.typeParserMap.containsKey(codec.schemaType())) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Multiple parse methods for single serialization type may not be added.")); + } + this.typeParserMap.putIfAbsent(codec.schemaType(), codec::parseSchemaString); + logger.verbose( + "Loaded parser for '{}' serialization format.", codec.schemaType().toLowerCase(Locale.ROOT)); + } + + @Override + public SchemaRegistryObject register( + String schemaGroup, String schemaName, String schemaString, String schemaType) { + if (schemaStringCache.containsKey(schemaString)) { + logger.verbose( + "Cache hit schema string. Group: '{}', name: '{}', schema type: '{}', payload: '{}'", + schemaGroup, schemaName, schemaType, schemaString); + return schemaStringCache.get(schemaString); + } + + logger.verbose( + "Registering schema. Group: '{}', name: '{}', serialization type: '{}', payload: '{}'", + schemaGroup, schemaName, schemaType, schemaString); + + SchemaId schemaId; + try { + schemaId = this.restService.createSchema(schemaGroup, schemaName, schemaString, schemaType); + } catch (HttpResponseException e) { + throw logger.logExceptionAsError(new SchemaRegistryClientException("Register operation failed.", e)); + } + + SchemaRegistryObject registered = new SchemaRegistryObject(schemaId.getId(), + schemaType, + schemaString.getBytes(SCHEMA_REGISTRY_SERVICE_ENCODING), + getParseFunc(schemaType)); + + resetIfNeeded(); + schemaStringCache.putIfAbsent(schemaString, registered); + logger.verbose("Cached schema string. Group: '{}', name: '{}'", schemaGroup, schemaName); + return registered; + } + + @Override + public SchemaRegistryObject getSchemaByGuid(String schemaId) { + Objects.requireNonNull(schemaId, "'schemaId' should not be null"); + + if (idCache.containsKey(schemaId)) { + logger.verbose("Cache hit for schema id '{}'", schemaId); + return idCache.get(schemaId); + } + + GetSchemaByIdResponse response; + try { + response = this.restService.getSchemaByIdWithResponseAsync(UUID.fromString(schemaId)).block(); + } catch (HttpResponseException e) { + throw logger.logExceptionAsError(new SchemaRegistryClientException("Fetching schema failed.", e)); + } + + if (response == null) { + throw logger.logExceptionAsError( + new SchemaRegistryClientException("HTTP client returned null schema response")); + } + + String schemaType = response.getDeserializedHeaders().getXSchemaType(); + + SchemaRegistryObject schemaObject = new SchemaRegistryObject(schemaId, + schemaType, + response.getValue().getBytes(SCHEMA_REGISTRY_SERVICE_ENCODING), + getParseFunc(schemaType)); + + resetIfNeeded(); + idCache.putIfAbsent(schemaId, schemaObject); + logger.verbose("Cached schema object. Path: '{}'", schemaId); + return schemaObject; + } + + @Override + public String getSchemaId( + String schemaGroup, String schemaName, String schemaString, String schemaType) { + if (schemaStringCache.containsKey(schemaString)) { + logger.verbose("Cache hit schema string. Group: '{}', name: '{}'", schemaGroup, schemaName); + return schemaStringCache.get(schemaString).getSchemaId(); + } + + SchemaId schemaId; + try { + schemaId = this.restService.getIdBySchemaContent(schemaGroup, schemaName, schemaType, schemaString); + } catch (HttpResponseException e) { + throw logger.logExceptionAsError(new SchemaRegistryClientException( + String.format("Failed to fetch schema guid for schema. Group: '%s', name: '%s'", + schemaGroup, schemaName), + e)); + } + + resetIfNeeded(); + schemaStringCache.putIfAbsent( + schemaString, + new SchemaRegistryObject( + schemaId.getId(), + schemaType, + schemaString.getBytes(SCHEMA_REGISTRY_SERVICE_ENCODING), + getParseFunc(schemaType))); + logger.verbose("Cached schema string. Group: '{}', name: '{}'", schemaGroup, schemaName); + return schemaId.getId(); + } + + @Override + public String deleteSchemaVersion(String schemaGroup, String schemaName, int version) { + throw logger.logExceptionAsError(new UnsupportedOperationException()); + } + + @Override + public String deleteLatestSchemaVersion(String schemaGroup, String schemaName) { + throw logger.logExceptionAsError(new UnsupportedOperationException()); + } + + @Override + public List deleteSchema(String schemaGroup, String schemaName) { + throw logger.logExceptionAsError(new UnsupportedOperationException()); + } + + /** + * Explicit call to clear all caches. + */ + public void reset() { + idCache.clear(); + schemaStringCache.clear(); + typeParserMap.clear(); + } + + // TODO: max age for schema maps? or will schemas always be immutable? + /** + * Checks if caches should be reinitialized to satisfy initial configuration + */ + private void resetIfNeeded() { + // todo add verbose log + if (idCache.size() > this.maxSchemaMapSize) { + idCache.clear(); + logger.verbose("Cleared schema ID cache."); + } + if (schemaStringCache.size() > this.maxSchemaMapSize) { + schemaStringCache.clear(); + logger.verbose("Cleared schema string cache."); + } + } + + /** + * Return stored parse function for parsing schema payloads of specified schema type + * + * @param schemaType schema type of payload to be deserialized + * @return parse method for deserializing schema string + */ + private Function getParseFunc(String schemaType) { + Function parseFunc = typeParserMap.get(schemaType); + + if (parseFunc == null) { + throw logger.logExceptionAsError(new SchemaRegistryClientException( + String.format("Unexpected serialization type '%s' received. Currently loaded parsers: %s", + schemaType, + typeParserMap.keySet().toString()))); + } + return parseFunc; + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClientBuilder.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClientBuilder.java new file mode 100644 index 000000000000..6f1da7c4a6cd --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClientBuilder.java @@ -0,0 +1,293 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client; + +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.HttpPolicyProviders; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.Configuration; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.logging.ClientLogger; +import com.azure.data.schemaregistry.Codec; +import com.azure.data.schemaregistry.client.implementation.AzureSchemaRegistryRestService; +import com.azure.data.schemaregistry.client.implementation.AzureSchemaRegistryRestServiceClientBuilder; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.function.Function; + +/** + * Builder implementation for {@link CachedSchemaRegistryClient}. + */ +@ServiceClientBuilder(serviceClients = CachedSchemaRegistryClient.class) +public class CachedSchemaRegistryClientBuilder { + private final ClientLogger logger = new ClientLogger(CachedSchemaRegistryClientBuilder.class); + + private static final String DEFAULT_SCOPE = "https://eventhubs.azure.com/.default"; + private static final String CLIENT_PROPERTIES = "azure-data-schemaregistry-client.properties"; + private static final String NAME = "name"; + private static final String VERSION = "version"; + private static final RetryPolicy DEFAULT_RETRY_POLICY = + new RetryPolicy("retry-after-ms", ChronoUnit.MILLIS); + + private final ConcurrentSkipListMap> typeParserMap; + private final List policies; + private final String clientName; + private final String clientVersion; + + private String schemaRegistryUrl; + private HttpClient httpClient; + private Integer maxSchemaMapSize; + private TokenCredential credential; + private HttpLogOptions httpLogOptions; + private HttpPipeline httpPipeline; + private RetryPolicy retryPolicy; + + /** + * Constructor for CachedSchemaRegistryClientBuilder. Supplies client defaults. + */ + public CachedSchemaRegistryClientBuilder() { + this.policies = new ArrayList<>(); + this.httpLogOptions = new HttpLogOptions(); + this.maxSchemaMapSize = null; + this.typeParserMap = new ConcurrentSkipListMap<>(String.CASE_INSENSITIVE_ORDER); + this.httpClient = null; + this.credential = null; + this.retryPolicy = new RetryPolicy("retry-after-ms", ChronoUnit.MILLIS); + + Map properties = CoreUtils.getProperties(CLIENT_PROPERTIES); + clientName = properties.getOrDefault(NAME, "UnknownName"); + clientVersion = properties.getOrDefault(VERSION, "UnknownVersion"); + } + + /** + * Sets the service endpoint for the Azure Schema Registry instance. + * + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + * @param schemaRegistryUrl The URL of the Azure Schema Registry instance + * @throws NullPointerException if {@code schemaRegistryUrl} is null + * @throws IllegalArgumentException if {@code schemaRegistryUrl} cannot be parsed into a valid URL + */ + public CachedSchemaRegistryClientBuilder endpoint(String schemaRegistryUrl) { + Objects.requireNonNull(schemaRegistryUrl, "'schemaRegistryUrl' cannot be null."); + + try { + new URL(schemaRegistryUrl); + } catch (MalformedURLException ex) { + throw logger.logExceptionAsWarning( + new IllegalArgumentException("'schemaRegistryUrl' must be a valid URL.", ex)); + } + + if (schemaRegistryUrl.endsWith("/")) { + this.schemaRegistryUrl = schemaRegistryUrl.substring(0, schemaRegistryUrl.length() - 1); + } else { + this.schemaRegistryUrl = schemaRegistryUrl; + } + + return this; + } + + /** + * Sets schema cache size limit. If limit is exceeded on any cache, all caches are recycled. + * + * @param maxSchemaMapSize max size for internal schema caches in {@link CachedSchemaRegistryClient} + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + * @throws IllegalArgumentException on invalid maxSchemaMapSize value + */ + public CachedSchemaRegistryClientBuilder maxSchemaMapSize(int maxSchemaMapSize) { + if (maxSchemaMapSize < CachedSchemaRegistryClient.MAX_SCHEMA_MAP_SIZE_MINIMUM) { + throw logger.logExceptionAsError(new IllegalArgumentException( + String.format("Schema map size must be greater than %s entries", + CachedSchemaRegistryClient.MAX_SCHEMA_MAP_SIZE_MINIMUM))); + } + + this.maxSchemaMapSize = maxSchemaMapSize; + return this; + } + + /** + * Sets the HTTP client to use for sending and receiving requests to and from the service. + * + * @param httpClient The HTTP client to use for requests. + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + */ + public CachedSchemaRegistryClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Sets the HTTP pipeline to use for the service client. + *

+ * If {@code pipeline} is set, all other HTTP settings are ignored to build {@link CachedSchemaRegistryClient}. + * + * @param httpPipeline The HTTP pipeline to use for sending service requests and receiving responses. + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + */ + public CachedSchemaRegistryClientBuilder pipeline(HttpPipeline httpPipeline) { + if (this.httpPipeline != null && httpPipeline == null) { + logger.info("HttpPipeline is being set to 'null' when it was previously configured."); + } + + this.httpPipeline = httpPipeline; + return this; + } + + + /** + * Sets the {@link TokenCredential} to use when authenticating HTTP requests for this + * {@link CachedSchemaRegistryClient}. + * + * @param credential {@link TokenCredential} + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + * @throws NullPointerException If {@code credential} is {@code null} + */ + public CachedSchemaRegistryClientBuilder credential(TokenCredential credential) { + this.credential = Objects.requireNonNull(credential, "'credential' cannot be null."); + return this; + } + + /** + * Sets the logging configuration for HTTP requests and responses. + * + *

If logLevel is not provided, default value of {@link HttpLogDetailLevel#NONE} is set.

+ * + * @param logOptions The logging configuration to use when sending and receiving HTTP requests/responses. + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + */ + public CachedSchemaRegistryClientBuilder httpLogOptions(HttpLogOptions logOptions) { + this.httpLogOptions = logOptions; + return this; + } + + /** + * Sets the {@link RetryPolicy} that is used when each request is sent. + *

+ * The default retry policy will be used if not provided to build {@link CachedSchemaRegistryClient} . + * + * @param retryPolicy user's retry policy applied to each request. + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + */ + public CachedSchemaRegistryClientBuilder retryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + return this; + } + + /** + * Adds a policy to the set of existing policies that are executed after required policies. + * + * @param policy The retry policy for service requests. + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + * @throws NullPointerException If {@code policy} is {@code null}. + */ + public CachedSchemaRegistryClientBuilder addPolicy(HttpPipelinePolicy policy) { + policies.add(Objects.requireNonNull(policy, "'policy' cannot be null.")); + return this; + } + + /** + * Loads a parser method Function object used to convert schema strings returned from the Schema Registry + * service into useable schema objects. + * + * Any com.azure.data.schemaregistry.ByteEncoder or com.azure.data.schemaregistry.ByteDecoder class will implement + * - schemaType(), which specifies schema type, and + * - parseSchemaString(), which parses schemas of the specified schema type from String to Object. + * + * The parseMethod argument should be a stateless, idempotent function. + * + * @param codec Codec class implementation + * @return The updated {@link CachedSchemaRegistryClientBuilder} object. + */ + public CachedSchemaRegistryClientBuilder addSchemaParser(Codec codec) { + Objects.requireNonNull(codec, "'codec' cannot be null."); + if (CoreUtils.isNullOrEmpty(codec.schemaType())) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Serialization type cannot be null or empty.")); + } + if (this.typeParserMap.containsKey(codec.schemaType())) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Multiple parse methods for single serialization type may not be added.")); + } + this.typeParserMap.put(codec.schemaType(), codec::parseSchemaString); + return this; + } + + /** + * Creates a {@link CachedSchemaRegistryClient} based on options set in the builder. + * Every time {@code buildClient()} is called a new instance of {@link CachedSchemaRegistryClient} is created. + * + * If {@link #pipeline(HttpPipeline) pipeline} is set, then all HTTP pipeline related settings are ignored + * endpoint} are when creating the {@link CachedSchemaRegistryClient client}. + * + * @return A {@link CachedSchemaRegistryClient} with the options set from the builder. + * @throws NullPointerException if parameters are incorrectly set. + * @throws IllegalArgumentException if credential is not set. + */ + public CachedSchemaRegistryClient buildClient() { + // Authentications + if (credential == null) { + // Throw exception that credential and tokenCredential cannot be null + throw logger.logExceptionAsError( + new IllegalArgumentException("Missing credential information while building a client.")); + } + + HttpPipeline pipeline = this.httpPipeline; + // Create a default Pipeline if it is not given + if (pipeline == null) { + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + policies.add(new UserAgentPolicy(httpLogOptions.getApplicationId(), clientName, clientVersion, + Configuration.getGlobalConfiguration().clone())); + policies.add(new RequestIdPolicy()); + + HttpPolicyProviders.addBeforeRetryPolicies(policies); + + policies.add(retryPolicy == null ? DEFAULT_RETRY_POLICY : retryPolicy); + + policies.add(new AddDatePolicy()); + + policies.add(new BearerTokenAuthenticationPolicy(credential, DEFAULT_SCOPE)); + + policies.addAll(this.policies); + HttpPolicyProviders.addAfterRetryPolicies(policies); + + policies.add(new HttpLoggingPolicy(httpLogOptions)); + + pipeline = new HttpPipelineBuilder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + } + + AzureSchemaRegistryRestService restService = new AzureSchemaRegistryRestServiceClientBuilder() + .host(this.schemaRegistryUrl) + .pipeline(pipeline) + .buildClient(); + + this.maxSchemaMapSize = this.maxSchemaMapSize != null + ? this.maxSchemaMapSize + : CachedSchemaRegistryClient.MAX_SCHEMA_MAP_SIZE_DEFAULT; + + return new CachedSchemaRegistryClient(restService, maxSchemaMapSize, typeParserMap); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryClient.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryClient.java new file mode 100644 index 000000000000..5443ded21196 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryClient.java @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client; + +import com.azure.data.schemaregistry.Codec; + +import java.nio.charset.Charset; +import java.util.List; + +/** + * Interface that defines operation for registering and fetching schemas and schema information to and from a + * schema registry store. + */ +public interface SchemaRegistryClient { + + /** + * Encoding used by registry client implementation. + * @return encoding for registry client implementation + */ + Charset getEncoding(); + + /** + * Loads function for a given schema type that can parse the registry-stored schema string into + * usable schema object. + * + * Any com.azure.data.schemaregistry.ByteEncoder or com.azure.data.schemaregistry.ByteDecoder class will implement + * - schemaType(), which specifies schema type, and + * - parseSchemaString(), which parses schemas of the specified schema type from String to Object. + * + * @param codec Codec class implementation + */ + void addSchemaParser(Codec codec); + + /** + * Registers a schema against backing schema registry store. + * + * @param schemaGroup schema group name + * @param schemaName schema name + * @param schemaString string representation of schema + * @param schemaType string representation of schema type + * @return SchemaRegistryObject containing information regarding registered schema. + * @throws SchemaRegistryClientException if registration operation fails + */ + SchemaRegistryObject register(String schemaGroup, String schemaName, String schemaString, String schemaType); + + /** + * Fetches schema specified by the GUID. + *

+ * GUID can be assumed to be unique within a schema registry store. + * + * @param schemaGuid GUID reference to specific schema within configured schema registry store. + * @return SchemaRegistryObject containing information regarding matching schema. + * @throws SchemaRegistryClientException if fetch operation fails + */ + SchemaRegistryObject getSchemaByGuid(String schemaGuid); + + /** + * Fetches schema GUID given schema group, name, string representation, and serialization type + * + * @param schemaGroup schema group name + * @param schemaName schema name + * @param schemaString String representation of schema + * @param schemaType String representation of schema type + * @return SchemaRegistryObject containing information regarding requested schema. + * @throws SchemaRegistryClientException if fetch operation fails + */ + String getSchemaId(String schemaGroup, String schemaName, String schemaString, String schemaType); + + /** + * Not currently implemented. + * + * @param schemaGroup schema group name + * @param schemaName schema name + * @param version schema version + * @return GUID of delete schema + * @throws SchemaRegistryClientException deletion operation failed + */ + String deleteSchemaVersion(String schemaGroup, String schemaName, int version); + + /** + * Not currently implemented. + * + * @param schemaGroup schema group name + * @param schemaName schema name + * @return GUID of deleted schema + * @throws SchemaRegistryClientException deletion operation failed + */ + String deleteLatestSchemaVersion(String schemaGroup, String schemaName); + + /** + * Not currently implemented. + * + * @param schemaGroup schema group name + * @param schemaName schema name + * @return list of GUID references to deleted schemas + * @throws SchemaRegistryClientException deletion operation failed + */ + List deleteSchema(String schemaGroup, String schemaName); +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryClientException.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryClientException.java new file mode 100644 index 000000000000..5d40f72d5701 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryClientException.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client; + +import com.azure.core.exception.AzureException; + +/** + * Runtime exception to be returned from SchemaRegistryClient implementations. + */ +public class SchemaRegistryClientException extends AzureException { + /** + * @param s error message returned from schema registry client + */ + SchemaRegistryClientException(String s) { + super(s); + } + + /** + * @param s error message returned from schema registry client + * @param cause Throwable cause of the exception + */ + SchemaRegistryClientException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryObject.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryObject.java new file mode 100644 index 000000000000..2af1d810d07b --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/SchemaRegistryObject.java @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client; + +import com.azure.core.util.logging.ClientLogger; +import java.util.function.Function; + +/** + * Stores all relevant information returned from SchemaRegistryClient layer. + */ +public class SchemaRegistryObject { + private final ClientLogger logger = new ClientLogger(SchemaRegistryObject.class); + + private final String schemaId; + private final String schemaType; + private final Function parseMethod; + private final byte[] schemaBytes; + + private Object deserialized; + + /** + * Initializes SchemaRegistryObject instance. + * + * @param schemaId schema ID + * @param schemaType type of schema, e.g. avro, json + * @param schemaByteArray byte payload representing schema, returned from Azure Schema Registry + * @param parseMethod method to deserialize schema payload into Object + */ + public SchemaRegistryObject( + String schemaId, + String schemaType, + byte[] schemaByteArray, + Function parseMethod) { + this.schemaId = schemaId; + this.schemaType = schemaType; + this.schemaBytes = schemaByteArray.clone(); + this.deserialized = null; + this.parseMethod = parseMethod; + } + + /** + * @return schema ID + */ + public String getSchemaId() { + return schemaId; + } + + /** + * @return schema type associated with the schema payload + */ + public String getSchemaType() { + return schemaType; + } + + /** + * Deserialize schema bytes returned from Schema Registry. If deserialization has happened once, the deserialized + * object is stored and returned. + * + * @return schema object, deserialized using stored schema parser method. + */ + public Object deserialize() { + if (this.deserialized == null) { + String schemaString = new String( + this.schemaBytes, CachedSchemaRegistryClient.SCHEMA_REGISTRY_SERVICE_ENCODING); + + logger.verbose("Deserializing schema, id: '{}', schema string '{}'", this.schemaId, schemaString); + + try { + this.deserialized = parseMethod.apply(schemaString); + } catch (Exception e) { + logger.logExceptionAsError(new SchemaRegistryClientException("Failed to deserialize schema", e)); + } + + } + return deserialized; + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/AzureSchemaRegistryRestService.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/AzureSchemaRegistryRestService.java new file mode 100644 index 000000000000..f69a532755e3 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/AzureSchemaRegistryRestService.java @@ -0,0 +1,1411 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation; + +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.Delete; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.Get; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.PathParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.Put; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.CookiePolicy; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import com.azure.data.schemaregistry.client.implementation.models.CreateGroupResponse; +import com.azure.data.schemaregistry.client.implementation.models.CreateSchemaResponse; +import com.azure.data.schemaregistry.client.implementation.models.GetIdBySchemaContentResponse; +import com.azure.data.schemaregistry.client.implementation.models.GetLatestSchemaResponse; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemaByIdResponse; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemaVersionResponse; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemaVersionsResponse; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemasByGroupResponse; +import com.azure.data.schemaregistry.client.implementation.models.SchemaGroup; +import com.azure.data.schemaregistry.client.implementation.models.SchemaId; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.UUID; + +/** + * Initializes a new instance of the AzureSchemaRegistryRestService type. + */ +public final class AzureSchemaRegistryRestService { + /** + * The proxy service used to perform REST calls. + */ + private final AzureSchemaRegistryRestServiceService service; + + /** + * server parameter. + */ + private String host; + + /** + * Gets server parameter. + * + * @return the host value. + */ + public String getHost() { + return this.host; + } + + /** + * Sets server parameter. + * + * @param host the host value. + * @return the service client itself. + */ + public AzureSchemaRegistryRestService setHost(String host) { + this.host = host; + return this; + } + + /** + * The HTTP pipeline to send requests through. + */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** + * Initializes an instance of AzureSchemaRegistryRestService client. + */ + public AzureSchemaRegistryRestService() { + this(new HttpPipelineBuilder().policies(new UserAgentPolicy(), new RetryPolicy(), new CookiePolicy()).build()); + } + + /** + * Initializes an instance of AzureSchemaRegistryRestService client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + */ + public AzureSchemaRegistryRestService(HttpPipeline httpPipeline) { + this.httpPipeline = httpPipeline; + this.service = RestProxy.create(AzureSchemaRegistryRestServiceService.class, this.httpPipeline); + } + + /** + * The interface defining all the services for AzureSchemaRegistryRestService to be used by the proxy service to + * perform REST calls. + */ + @Host("{$host}") + @ServiceInterface(name = "AzureSchemaRegistryR") + private interface AzureSchemaRegistryRestServiceService { + @Get("/$schemagroups") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono>> getGroups(@HostParam("$host") String host, Context context); + + @Get("/$schemagroups/getSchemaById/{schema-id}") + @ExpectedResponses({200, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono getSchemaById( + @HostParam("$host") String host, @PathParam("schema-id") UUID schemaId, Context context); + + @Get("/$schemagroups/{group-name}") + @ExpectedResponses({200, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getGroup( + @HostParam("$host") String host, @PathParam("group-name") String groupName, Context context); + + @Put("/$schemagroups/{group-name}") + @ExpectedResponses({201, 409}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono createGroup( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @BodyParam("application/json") SchemaGroup body, + Context context); + + @Delete("/$schemagroups/{group-name}") + @ExpectedResponses({204, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteGroup( + @HostParam("$host") String host, @PathParam("group-name") String groupName, Context context); + + @Get("/$schemagroups/{group-name}/schemas") + @ExpectedResponses({200, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono getSchemasByGroup( + @HostParam("$host") String host, @PathParam("group-name") String groupName, Context context); + + @Delete("/$schemagroups/{group-name}/schemas") + @ExpectedResponses({204, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteSchemasByGroup( + @HostParam("$host") String host, @PathParam("group-name") String groupName, Context context); + + @Post("/$schemagroups/{group-name}/schemas/{schema-name}") + @ExpectedResponses({200, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono getIdBySchemaContent( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + @HeaderParam("X-Schema-Type") String xSchemaType, + @BodyParam("application/json") String body, + Context context); + + @Put("/$schemagroups/{group-name}/schemas/{schema-name}") + @ExpectedResponses({200, 400}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono createSchema( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + @HeaderParam("X-Schema-Type") String xSchemaType, + @BodyParam("application/json") String body, + Context context); + + @Get("/$schemagroups/{group-name}/schemas/{schema-name}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono getLatestSchema( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + Context context); + + @Delete("/$schemagroups/{group-name}/schemas/{schema-name}") + @ExpectedResponses({204, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteSchema( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + Context context); + + @Get("/$schemagroups/{group-name}/schemas/{schema-name}/versions") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono getSchemaVersions( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + Context context); + + @Get("/$schemagroups/{group-name}/schemas/{schema-name}/versions/{version-number}") + @ExpectedResponses({200, 404}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono getSchemaVersion( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + @PathParam("version-number") int versionNumber, + Context context); + + @Delete("/$schemagroups/{group-name}/schemas/{schema-name}/versions/{version-number}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteSchemaVersion( + @HostParam("$host") String host, + @PathParam("group-name") String groupName, + @PathParam("schema-name") String schemaName, + @PathParam("version-number") int versionNumber, + Context context); + } + + /** + * Get all schema groups in namespace. + * + * @return all schema groups in namespace. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono>> getGroupsWithResponseAsync() { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.getGroups(this.getHost(), context)); + } + + /** + * Get all schema groups in namespace. + * + * @param context The context to associate with this operation. + * @return all schema groups in namespace. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono>> getGroupsWithResponseAsync(Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + return service.getGroups(this.getHost(), context); + } + + /** + * Get all schema groups in namespace. + * + * @return all schema groups in namespace. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getGroupsAsync() { + return getGroupsWithResponseAsync() + .flatMap( + (SimpleResponse> res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get all schema groups in namespace. + * + * @return all schema groups in namespace. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public List getGroups() { + return getGroupsAsync().block(); + } + + /** + * Get schema by schema ID. + * + * @param schemaId schema ID referencing specific schema in registry namespace. + * @return schema by schema ID. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaByIdWithResponseAsync(UUID schemaId) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (schemaId == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaId is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.getSchemaById(this.getHost(), schemaId, context)); + } + + /** + * Get schema by schema ID. + * + * @param schemaId schema ID referencing specific schema in registry namespace. + * @param context The context to associate with this operation. + * @return schema by schema ID. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaByIdWithResponseAsync(UUID schemaId, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (schemaId == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaId is required and cannot be null.")); + } + return service.getSchemaById(this.getHost(), schemaId, context); + } + + /** + * Get schema by schema ID. + * + * @param schemaId schema ID referencing specific schema in registry namespace. + * @return schema by schema ID. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaByIdAsync(UUID schemaId) { + return getSchemaByIdWithResponseAsync(schemaId) + .flatMap( + (GetSchemaByIdResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get schema by schema ID. + * + * @param schemaId schema ID referencing specific schema in registry namespace. + * @return schema by schema ID. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public String getSchemaById(UUID schemaId) { + return getSchemaByIdAsync(schemaId).block(); + + } + + /** + * Get schema group description in registry namespace. + * + * @param groupName schema group. + * @return schema group description in registry namespace. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getGroupWithResponseAsync(String groupName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.getGroup(this.getHost(), groupName, context)); + } + + /** + * Get schema group description in registry namespace. + * + * @param groupName schema group. + * @param context The context to associate with this operation. + * @return schema group description in registry namespace. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getGroupWithResponseAsync(String groupName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return service.getGroup(this.getHost(), groupName, context); + } + + /** + * Get schema group description in registry namespace. + * + * @param groupName schema group. + * @return schema group description in registry namespace. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getGroupAsync(String groupName) { + return getGroupWithResponseAsync(groupName) + .flatMap( + (SimpleResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get schema group description in registry namespace. + * + * @param groupName schema group. + * @return schema group description in registry namespace. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public SchemaGroup getGroup(String groupName) { + return getGroupAsync(groupName).block(); + } + + /** + * Create schema group with specified schema type in registry namespace. + * + * @param groupName schema group. + * @param body schema group description. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createGroupWithResponseAsync(String groupName, SchemaGroup body) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (body == null) { + return Mono.error(new IllegalArgumentException("Parameter body is required and cannot be null.")); + } else { + body.validate(); + } + return FluxUtil.withContext(context -> service.createGroup(this.getHost(), groupName, body, context)); + } + + /** + * Create schema group with specified schema type in registry namespace. + * + * @param groupName schema group. + * @param body schema group description. + * @param context The context to associate with this operation. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createGroupWithResponseAsync(String groupName, SchemaGroup body, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (body == null) { + return Mono.error(new IllegalArgumentException("Parameter body is required and cannot be null.")); + } else { + body.validate(); + } + return service.createGroup(this.getHost(), groupName, body, context); + } + + /** + * Create schema group with specified schema type in registry namespace. + * + * @param groupName schema group. + * @param body schema group description. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createGroupAsync(String groupName, SchemaGroup body) { + return createGroupWithResponseAsync(groupName, body).flatMap((CreateGroupResponse res) -> Mono.empty()); + } + + /** + * Create schema group with specified schema type in registry namespace. + * + * @param groupName schema group. + * @param body schema group description. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void createGroup(String groupName, SchemaGroup body) { + createGroupAsync(groupName, body).block(); + } + + /** + * Delete schema group in schema registry namespace. + * + * @param groupName schema group. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteGroupWithResponseAsync(String groupName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.deleteGroup(this.getHost(), groupName, context)); + } + + /** + * Delete schema group in schema registry namespace. + * + * @param groupName schema group. + * @param context The context to associate with this operation. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteGroupWithResponseAsync(String groupName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return service.deleteGroup(this.getHost(), groupName, context); + } + + /** + * Delete schema group in schema registry namespace. + * + * @param groupName schema group. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteGroupAsync(String groupName) { + return deleteGroupWithResponseAsync(groupName).flatMap((Response res) -> Mono.empty()); + } + + /** + * Delete schema group in schema registry namespace. + * + * @param groupName schema group. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteGroup(String groupName) { + deleteGroupAsync(groupName).block(); + } + + /** + * Returns schema by group name. + * + * @param groupName schema group. + * @return array of String. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemasByGroupWithResponseAsync(String groupName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.getSchemasByGroup(this.getHost(), groupName, context)); + } + + /** + * Returns schema by group name. + * + * @param groupName schema group. + * @param context The context to associate with this operation. + * @return array of String. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemasByGroupWithResponseAsync(String groupName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return service.getSchemasByGroup(this.getHost(), groupName, context); + } + + /** + * Returns schema by group name. + * + * @param groupName schema group. + * @return array of String. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getSchemasByGroupAsync(String groupName) { + return getSchemasByGroupWithResponseAsync(groupName) + .flatMap( + (GetSchemasByGroupResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Returns schema by group name. + * + * @param groupName schema group. + * @return array of String. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public List getSchemasByGroup(String groupName) { + return getSchemasByGroupAsync(groupName).block(); + } + + /** + * Deletes all schemas under specified group name. + * + * @param groupName schema group. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteSchemasByGroupWithResponseAsync(String groupName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.deleteSchemasByGroup(this.getHost(), groupName, context)); + } + + /** + * Deletes all schemas under specified group name. + * + * @param groupName schema group. + * @param context The context to associate with this operation. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteSchemasByGroupWithResponseAsync(String groupName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + return service.deleteSchemasByGroup(this.getHost(), groupName, context); + } + + /** + * Deletes all schemas under specified group name. + * + * @param groupName schema group. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteSchemasByGroupAsync(String groupName) { + return deleteSchemasByGroupWithResponseAsync(groupName).flatMap((Response res) -> Mono.empty()); + } + + /** + * Deletes all schemas under specified group name. + * + * @param groupName schema group. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteSchemasByGroup(String groupName) { + deleteSchemasByGroupAsync(groupName).block(); + } + + /** + * Get ID for schema with matching byte content and schema type. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @return iD for schema with matching byte content and schema type. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getIdBySchemaContentWithResponseAsync( + String groupName, String schemaName, String xSchemaType, String body) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + if (xSchemaType == null) { + return Mono.error(new IllegalArgumentException("Parameter xSchemaType is required and cannot be null.")); + } + if (body == null) { + return Mono.error(new IllegalArgumentException("Parameter body is required and cannot be null.")); + } + return FluxUtil.withContext( + context -> + service.getIdBySchemaContent( + this.getHost(), groupName, schemaName, xSchemaType, body, context)); + } + + /** + * Get ID for schema with matching byte content and schema type. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @param context The context to associate with this operation. + * @return iD for schema with matching byte content and schema type. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getIdBySchemaContentWithResponseAsync( + String groupName, String schemaName, String xSchemaType, String body, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + if (xSchemaType == null) { + return Mono.error(new IllegalArgumentException("Parameter xSchemaType is required and cannot be null.")); + } + if (body == null) { + return Mono.error(new IllegalArgumentException("Parameter body is required and cannot be null.")); + } + return service.getIdBySchemaContent(this.getHost(), groupName, schemaName, xSchemaType, body, context); + } + + /** + * Get ID for schema with matching byte content and schema type. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @return iD for schema with matching byte content and schema type. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getIdBySchemaContentAsync( + String groupName, String schemaName, String xSchemaType, String body) { + return getIdBySchemaContentWithResponseAsync(groupName, schemaName, xSchemaType, body) + .flatMap( + (GetIdBySchemaContentResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get ID for schema with matching byte content and schema type. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @return iD for schema with matching byte content and schema type. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public SchemaId getIdBySchemaContent(String groupName, String schemaName, String xSchemaType, String body) { + return getIdBySchemaContentAsync(groupName, schemaName, xSchemaType, body).block(); + } + + /** + * Register schema. If schema of specified name does not exist in specified group, schema is created at version 1. + * If schema of specified name exists already in specified group, schema is created at latest version + 1. If schema + * with identical content already exists, existing schema's ID is returned. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @return the response. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createSchemaWithResponseAsync( + String groupName, String schemaName, String xSchemaType, String body) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + if (xSchemaType == null) { + return Mono.error(new IllegalArgumentException("Parameter xSchemaType is required and cannot be null.")); + } + if (body == null) { + return Mono.error(new IllegalArgumentException("Parameter body is required and cannot be null.")); + } + return FluxUtil.withContext( + context -> service.createSchema(this.getHost(), groupName, schemaName, xSchemaType, body, context)); + } + + /** + * Register schema. If schema of specified name does not exist in specified group, schema is created at version 1. + * If schema of specified name exists already in specified group, schema is created at latest version + 1. If schema + * with identical content already exists, existing schema's ID is returned. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @param context The context to associate with this operation. + * @return the response. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createSchemaWithResponseAsync( + String groupName, String schemaName, String xSchemaType, String body, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + if (xSchemaType == null) { + return Mono.error(new IllegalArgumentException("Parameter xSchemaType is required and cannot be null.")); + } + if (body == null) { + return Mono.error(new IllegalArgumentException("Parameter body is required and cannot be null.")); + } + return service.createSchema(this.getHost(), groupName, schemaName, xSchemaType, body, context); + } + + /** + * Register schema. If schema of specified name does not exist in specified group, schema is created at version 1. + * If schema of specified name exists already in specified group, schema is created at latest version + 1. If schema + * with identical content already exists, existing schema's ID is returned. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @return the response. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createSchemaAsync(String groupName, String schemaName, String xSchemaType, String body) { + return createSchemaWithResponseAsync(groupName, schemaName, xSchemaType, body) + .flatMap( + (CreateSchemaResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Register schema. If schema of specified name does not exist in specified group, schema is created at version 1. + * If schema of specified name exists already in specified group, schema is created at latest version + 1. If schema + * with identical content already exists, existing schema's ID is returned. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param xSchemaType The xSchemaType parameter. + * @param body schema content. + * @return the response. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public SchemaId createSchema(String groupName, String schemaName, String xSchemaType, String body) { + return createSchemaAsync(groupName, schemaName, xSchemaType, body).block(); + } + + /** + * Get latest version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return latest version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getLatestSchemaWithResponseAsync(String groupName, String schemaName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.getLatestSchema(this.getHost(), groupName, schemaName, context)); + } + + /** + * Get latest version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param context The context to associate with this operation. + * @return latest version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getLatestSchemaWithResponseAsync( + String groupName, String schemaName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return service.getLatestSchema(this.getHost(), groupName, schemaName, context); + } + + /** + * Get latest version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return latest version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getLatestSchemaAsync(String groupName, String schemaName) { + return getLatestSchemaWithResponseAsync(groupName, schemaName) + .flatMap( + (GetLatestSchemaResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get latest version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return latest version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public String getLatestSchema(String groupName, String schemaName) { + return getLatestSchemaAsync(groupName, schemaName).block(); + } + + /** + * Delete schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteSchemaWithResponseAsync(String groupName, String schemaName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return FluxUtil.withContext(context -> service.deleteSchema(this.getHost(), groupName, schemaName, context)); + } + + /** + * Delete schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param context The context to associate with this operation. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteSchemaWithResponseAsync(String groupName, String schemaName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return service.deleteSchema(this.getHost(), groupName, schemaName, context); + } + + /** + * Delete schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteSchemaAsync(String groupName, String schemaName) { + return deleteSchemaWithResponseAsync(groupName, schemaName).flatMap((Response res) -> Mono.empty()); + } + + /** + * Delete schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteSchema(String groupName, String schemaName) { + deleteSchemaAsync(groupName, schemaName).block(); + } + + /** + * Get list of versions for specified schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return list of versions for specified schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaVersionsWithResponseAsync(String groupName, String schemaName) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return FluxUtil.withContext( + context -> service.getSchemaVersions(this.getHost(), groupName, schemaName, context)); + } + + /** + * Get list of versions for specified schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param context The context to associate with this operation. + * @return list of versions for specified schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaVersionsWithResponseAsync( + String groupName, String schemaName, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return service.getSchemaVersions(this.getHost(), groupName, schemaName, context); + } + + /** + * Get list of versions for specified schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return list of versions for specified schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getSchemaVersionsAsync(String groupName, String schemaName) { + return getSchemaVersionsWithResponseAsync(groupName, schemaName) + .flatMap( + (GetSchemaVersionsResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get list of versions for specified schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @return list of versions for specified schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public List getSchemaVersions(String groupName, String schemaName) { + return getSchemaVersionsAsync(groupName, schemaName).block(); + } + + /** + * Get specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @return specified version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaVersionWithResponseAsync( + String groupName, String schemaName, int versionNumber) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return FluxUtil.withContext( + context -> service.getSchemaVersion(this.getHost(), groupName, schemaName, versionNumber, context)); + } + + /** + * Get specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @param context The context to associate with this operation. + * @return specified version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaVersionWithResponseAsync( + String groupName, String schemaName, int versionNumber, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return service.getSchemaVersion(this.getHost(), groupName, schemaName, versionNumber, context); + } + + /** + * Get specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @return specified version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getSchemaVersionAsync(String groupName, String schemaName, int versionNumber) { + return getSchemaVersionWithResponseAsync(groupName, schemaName, versionNumber) + .flatMap( + (GetSchemaVersionResponse res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @return specified version of schema. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public String getSchemaVersion(String groupName, String schemaName, int versionNumber) { + return getSchemaVersionAsync(groupName, schemaName, versionNumber).block(); + } + + /** + * Delete specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteSchemaVersionWithResponseAsync( + String groupName, String schemaName, int versionNumber) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return FluxUtil.withContext( + context -> service.deleteSchemaVersion(this.getHost(), groupName, schemaName, versionNumber, context)); + } + + /** + * Delete specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @param context The context to associate with this operation. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteSchemaVersionWithResponseAsync( + String groupName, String schemaName, int versionNumber, Context context) { + if (this.getHost() == null) { + return Mono.error(new IllegalArgumentException("Parameter this.getHost() is required and cannot be null.")); + } + if (groupName == null) { + return Mono.error(new IllegalArgumentException("Parameter groupName is required and cannot be null.")); + } + if (schemaName == null) { + return Mono.error(new IllegalArgumentException("Parameter schemaName is required and cannot be null.")); + } + return service.deleteSchemaVersion(this.getHost(), groupName, schemaName, versionNumber, context); + } + + /** + * Delete specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @return the completion. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteSchemaVersionAsync(String groupName, String schemaName, int versionNumber) { + return deleteSchemaVersionWithResponseAsync(groupName, schemaName, versionNumber) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Delete specified version of schema. + * + * @param groupName schema group. + * @param schemaName schema name. + * @param versionNumber version number. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteSchemaVersion(String groupName, String schemaName, int versionNumber) { + deleteSchemaVersionAsync(groupName, schemaName, versionNumber).block(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/AzureSchemaRegistryRestServiceClientBuilder.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/AzureSchemaRegistryRestServiceClientBuilder.java new file mode 100644 index 000000000000..4dbf94d09ca5 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/AzureSchemaRegistryRestServiceClientBuilder.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation; + +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.CookiePolicy; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; + +/** A builder for creating a new instance of the AzureSchemaRegistryRestService type. */ +@ServiceClientBuilder(serviceClients = {AzureSchemaRegistryRestService.class}) +public final class AzureSchemaRegistryRestServiceClientBuilder { + /* + * server parameter + */ + private String host; + + /** + * Sets server parameter. + * + * @param host the host value. + * @return the AzureSchemaRegistryRestServiceClientBuilder. + */ + public AzureSchemaRegistryRestServiceClientBuilder host(String host) { + this.host = host; + return this; + } + + /* + * The HTTP pipeline to send requests through + */ + private HttpPipeline pipeline; + + /** + * Sets The HTTP pipeline to send requests through. + * + * @param pipeline the pipeline value. + * @return the AzureSchemaRegistryRestServiceClientBuilder. + */ + public AzureSchemaRegistryRestServiceClientBuilder pipeline(HttpPipeline pipeline) { + this.pipeline = pipeline; + return this; + } + + /** + * Builds an instance of AzureSchemaRegistryRestService with the provided parameters. + * + * @return an instance of AzureSchemaRegistryRestService. + */ + public AzureSchemaRegistryRestService buildClient() { + if (host == null) { + this.host = ""; + } + if (pipeline == null) { + this.pipeline = + new HttpPipelineBuilder() + .policies(new UserAgentPolicy(), new RetryPolicy(), new CookiePolicy()) + .build(); + } + AzureSchemaRegistryRestService client = new AzureSchemaRegistryRestService(pipeline); + client.setHost(this.host); + return client; + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateGroupHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateGroupHeaders.java new file mode 100644 index 000000000000..ba373f71b19d --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateGroupHeaders.java @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The CreateGroupHeaders model. */ +@Fluent +public final class CreateGroupHeaders { + /* + * The Location property. + */ + @JsonProperty(value = "Location") + private String location; + + /** + * Get the location property: The Location property. + * + * @return the location value. + */ + public String getLocation() { + return this.location; + } + + /** + * Set the location property: The Location property. + * + * @param location the location value to set. + * @return the CreateGroupHeaders object itself. + */ + public CreateGroupHeaders setLocation(String location) { + this.location = location; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateGroupResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateGroupResponse.java new file mode 100644 index 000000000000..7f6b958bbd68 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateGroupResponse.java @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** Contains all response data for the createGroup operation. */ +public final class CreateGroupResponse extends ResponseBase { + /** + * Creates an instance of CreateGroupResponse. + * + * @param request the request which resulted in this CreateGroupResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public CreateGroupResponse( + HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, CreateGroupHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateSchemaHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateSchemaHeaders.java new file mode 100644 index 000000000000..be000bba9f56 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateSchemaHeaders.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.net.URL; +import java.util.UUID; + +/** The CreateSchemaHeaders model. */ +@Fluent +public final class CreateSchemaHeaders { + /* + * The X-Schema-Version property. + */ + @JsonProperty(value = "X-Schema-Version") + private Integer xSchemaVersion; + + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /* + * The X-Schema-Id property. + */ + @JsonProperty(value = "X-Schema-Id") + private UUID xSchemaId; + + /* + * The X-Schema-Id-Location property. + */ + @JsonProperty(value = "X-Schema-Id-Location") + private URL xSchemaIdLocation; + + /* + * The Location property. + */ + @JsonProperty(value = "Location") + private String location; + + /** + * Get the xSchemaVersion property: The X-Schema-Version property. + * + * @return the xSchemaVersion value. + */ + public Integer getXSchemaVersion() { + return this.xSchemaVersion; + } + + /** + * Set the xSchemaVersion property: The X-Schema-Version property. + * + * @param xSchemaVersion the xSchemaVersion value to set. + * @return the CreateSchemaHeaders object itself. + */ + public CreateSchemaHeaders setXSchemaVersion(Integer xSchemaVersion) { + this.xSchemaVersion = xSchemaVersion; + return this; + } + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the CreateSchemaHeaders object itself. + */ + public CreateSchemaHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Get the xSchemaId property: The X-Schema-Id property. + * + * @return the xSchemaId value. + */ + public UUID getXSchemaId() { + return this.xSchemaId; + } + + /** + * Set the xSchemaId property: The X-Schema-Id property. + * + * @param xSchemaId the xSchemaId value to set. + * @return the CreateSchemaHeaders object itself. + */ + public CreateSchemaHeaders setXSchemaId(UUID xSchemaId) { + this.xSchemaId = xSchemaId; + return this; + } + + /** + * Get the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @return the xSchemaIdLocation value. + */ + public URL getXSchemaIdLocation() { + return this.xSchemaIdLocation; + } + + /** + * Set the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @param xSchemaIdLocation the xSchemaIdLocation value to set. + * @return the CreateSchemaHeaders object itself. + */ + public CreateSchemaHeaders setXSchemaIdLocation(URL xSchemaIdLocation) { + this.xSchemaIdLocation = xSchemaIdLocation; + return this; + } + + /** + * Get the location property: The Location property. + * + * @return the location value. + */ + public String getLocation() { + return this.location; + } + + /** + * Set the location property: The Location property. + * + * @param location the location value to set. + * @return the CreateSchemaHeaders object itself. + */ + public CreateSchemaHeaders setLocation(String location) { + this.location = location; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateSchemaResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateSchemaResponse.java new file mode 100644 index 000000000000..5612686cb87f --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/CreateSchemaResponse.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** Contains all response data for the createSchema operation. */ +public final class CreateSchemaResponse extends ResponseBase { + /** + * Creates an instance of CreateSchemaResponse. + * + * @param request the request which resulted in this CreateSchemaResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public CreateSchemaResponse( + HttpRequest request, int statusCode, HttpHeaders rawHeaders, SchemaId value, CreateSchemaHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public SchemaId getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetIdBySchemaContentHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetIdBySchemaContentHeaders.java new file mode 100644 index 000000000000..e8b967ee584b --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetIdBySchemaContentHeaders.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.net.URL; +import java.util.UUID; + +/** The GetIdBySchemaContentHeaders model. */ +@Fluent +public final class GetIdBySchemaContentHeaders { + /* + * The X-Schema-Version property. + */ + @JsonProperty(value = "X-Schema-Version") + private Integer xSchemaVersion; + + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /* + * The X-Schema-Id property. + */ + @JsonProperty(value = "X-Schema-Id") + private UUID xSchemaId; + + /* + * The X-Schema-Id-Location property. + */ + @JsonProperty(value = "X-Schema-Id-Location") + private URL xSchemaIdLocation; + + /* + * The Location property. + */ + @JsonProperty(value = "Location") + private String location; + + /** + * Get the xSchemaVersion property: The X-Schema-Version property. + * + * @return the xSchemaVersion value. + */ + public Integer getXSchemaVersion() { + return this.xSchemaVersion; + } + + /** + * Set the xSchemaVersion property: The X-Schema-Version property. + * + * @param xSchemaVersion the xSchemaVersion value to set. + * @return the GetIdBySchemaContentHeaders object itself. + */ + public GetIdBySchemaContentHeaders setXSchemaVersion(Integer xSchemaVersion) { + this.xSchemaVersion = xSchemaVersion; + return this; + } + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the GetIdBySchemaContentHeaders object itself. + */ + public GetIdBySchemaContentHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Get the xSchemaId property: The X-Schema-Id property. + * + * @return the xSchemaId value. + */ + public UUID getXSchemaId() { + return this.xSchemaId; + } + + /** + * Set the xSchemaId property: The X-Schema-Id property. + * + * @param xSchemaId the xSchemaId value to set. + * @return the GetIdBySchemaContentHeaders object itself. + */ + public GetIdBySchemaContentHeaders setXSchemaId(UUID xSchemaId) { + this.xSchemaId = xSchemaId; + return this; + } + + /** + * Get the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @return the xSchemaIdLocation value. + */ + public URL getXSchemaIdLocation() { + return this.xSchemaIdLocation; + } + + /** + * Set the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @param xSchemaIdLocation the xSchemaIdLocation value to set. + * @return the GetIdBySchemaContentHeaders object itself. + */ + public GetIdBySchemaContentHeaders setXSchemaIdLocation(URL xSchemaIdLocation) { + this.xSchemaIdLocation = xSchemaIdLocation; + return this; + } + + /** + * Get the location property: The Location property. + * + * @return the location value. + */ + public String getLocation() { + return this.location; + } + + /** + * Set the location property: The Location property. + * + * @param location the location value to set. + * @return the GetIdBySchemaContentHeaders object itself. + */ + public GetIdBySchemaContentHeaders setLocation(String location) { + this.location = location; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetIdBySchemaContentResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetIdBySchemaContentResponse.java new file mode 100644 index 000000000000..4061fd93f937 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetIdBySchemaContentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** Contains all response data for the getIdBySchemaContent operation. */ +public final class GetIdBySchemaContentResponse extends ResponseBase { + /** + * Creates an instance of GetIdBySchemaContentResponse. + * + * @param request the request which resulted in this GetIdBySchemaContentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public GetIdBySchemaContentResponse( + HttpRequest request, + int statusCode, + HttpHeaders rawHeaders, + SchemaId value, + GetIdBySchemaContentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public SchemaId getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetLatestSchemaHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetLatestSchemaHeaders.java new file mode 100644 index 000000000000..bc155966690e --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetLatestSchemaHeaders.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.net.URL; +import java.util.UUID; + +/** The GetLatestSchemaHeaders model. */ +@Fluent +public final class GetLatestSchemaHeaders { + /* + * The X-Schema-Version property. + */ + @JsonProperty(value = "X-Schema-Version") + private Integer xSchemaVersion; + + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /* + * The X-Schema-Id property. + */ + @JsonProperty(value = "X-Schema-Id") + private UUID xSchemaId; + + /* + * The X-Schema-Id-Location property. + */ + @JsonProperty(value = "X-Schema-Id-Location") + private URL xSchemaIdLocation; + + /* + * The Location property. + */ + @JsonProperty(value = "Location") + private String location; + + /** + * Get the xSchemaVersion property: The X-Schema-Version property. + * + * @return the xSchemaVersion value. + */ + public Integer getXSchemaVersion() { + return this.xSchemaVersion; + } + + /** + * Set the xSchemaVersion property: The X-Schema-Version property. + * + * @param xSchemaVersion the xSchemaVersion value to set. + * @return the GetLatestSchemaHeaders object itself. + */ + public GetLatestSchemaHeaders setXSchemaVersion(Integer xSchemaVersion) { + this.xSchemaVersion = xSchemaVersion; + return this; + } + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the GetLatestSchemaHeaders object itself. + */ + public GetLatestSchemaHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Get the xSchemaId property: The X-Schema-Id property. + * + * @return the xSchemaId value. + */ + public UUID getXSchemaId() { + return this.xSchemaId; + } + + /** + * Set the xSchemaId property: The X-Schema-Id property. + * + * @param xSchemaId the xSchemaId value to set. + * @return the GetLatestSchemaHeaders object itself. + */ + public GetLatestSchemaHeaders setXSchemaId(UUID xSchemaId) { + this.xSchemaId = xSchemaId; + return this; + } + + /** + * Get the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @return the xSchemaIdLocation value. + */ + public URL getXSchemaIdLocation() { + return this.xSchemaIdLocation; + } + + /** + * Set the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @param xSchemaIdLocation the xSchemaIdLocation value to set. + * @return the GetLatestSchemaHeaders object itself. + */ + public GetLatestSchemaHeaders setXSchemaIdLocation(URL xSchemaIdLocation) { + this.xSchemaIdLocation = xSchemaIdLocation; + return this; + } + + /** + * Get the location property: The Location property. + * + * @return the location value. + */ + public String getLocation() { + return this.location; + } + + /** + * Set the location property: The Location property. + * + * @param location the location value to set. + * @return the GetLatestSchemaHeaders object itself. + */ + public GetLatestSchemaHeaders setLocation(String location) { + this.location = location; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetLatestSchemaResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetLatestSchemaResponse.java new file mode 100644 index 000000000000..b1aec099e868 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetLatestSchemaResponse.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** Contains all response data for the getLatestSchema operation. */ +public final class GetLatestSchemaResponse extends ResponseBase { + /** + * Creates an instance of GetLatestSchemaResponse. + * + * @param request the request which resulted in this GetLatestSchemaResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public GetLatestSchemaResponse( + HttpRequest request, int statusCode, HttpHeaders rawHeaders, String value, GetLatestSchemaHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public String getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaByIdHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaByIdHeaders.java new file mode 100644 index 000000000000..4facf3327dbe --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaByIdHeaders.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.net.URL; +import java.util.UUID; + +/** The GetSchemaByIdHeaders model. */ +@Fluent +public final class GetSchemaByIdHeaders { + /* + * The X-Schema-Version property. + */ + @JsonProperty(value = "X-Schema-Version") + private Integer xSchemaVersion; + + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /* + * The X-Schema-Id property. + */ + @JsonProperty(value = "X-Schema-Id") + private UUID xSchemaId; + + /* + * The X-Schema-Id-Location property. + */ + @JsonProperty(value = "X-Schema-Id-Location") + private URL xSchemaIdLocation; + + /* + * The Location property. + */ + @JsonProperty(value = "Location") + private String location; + + /** + * Get the xSchemaVersion property: The X-Schema-Version property. + * + * @return the xSchemaVersion value. + */ + public Integer getXSchemaVersion() { + return this.xSchemaVersion; + } + + /** + * Set the xSchemaVersion property: The X-Schema-Version property. + * + * @param xSchemaVersion the xSchemaVersion value to set. + * @return the GetSchemaByIdHeaders object itself. + */ + public GetSchemaByIdHeaders setXSchemaVersion(Integer xSchemaVersion) { + this.xSchemaVersion = xSchemaVersion; + return this; + } + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the GetSchemaByIdHeaders object itself. + */ + public GetSchemaByIdHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Get the xSchemaId property: The X-Schema-Id property. + * + * @return the xSchemaId value. + */ + public UUID getXSchemaId() { + return this.xSchemaId; + } + + /** + * Set the xSchemaId property: The X-Schema-Id property. + * + * @param xSchemaId the xSchemaId value to set. + * @return the GetSchemaByIdHeaders object itself. + */ + public GetSchemaByIdHeaders setXSchemaId(UUID xSchemaId) { + this.xSchemaId = xSchemaId; + return this; + } + + /** + * Get the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @return the xSchemaIdLocation value. + */ + public URL getXSchemaIdLocation() { + return this.xSchemaIdLocation; + } + + /** + * Set the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @param xSchemaIdLocation the xSchemaIdLocation value to set. + * @return the GetSchemaByIdHeaders object itself. + */ + public GetSchemaByIdHeaders setXSchemaIdLocation(URL xSchemaIdLocation) { + this.xSchemaIdLocation = xSchemaIdLocation; + return this; + } + + /** + * Get the location property: The Location property. + * + * @return the location value. + */ + public String getLocation() { + return this.location; + } + + /** + * Set the location property: The Location property. + * + * @param location the location value to set. + * @return the GetSchemaByIdHeaders object itself. + */ + public GetSchemaByIdHeaders setLocation(String location) { + this.location = location; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaByIdResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaByIdResponse.java new file mode 100644 index 000000000000..9f5f8392a987 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaByIdResponse.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** Contains all response data for the getSchemaById operation. */ +public final class GetSchemaByIdResponse extends ResponseBase { + /** + * Creates an instance of GetSchemaByIdResponse. + * + * @param request the request which resulted in this GetSchemaByIdResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public GetSchemaByIdResponse( + HttpRequest request, int statusCode, HttpHeaders rawHeaders, String value, GetSchemaByIdHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public String getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionHeaders.java new file mode 100644 index 000000000000..ebdce5e0585e --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionHeaders.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.net.URL; +import java.util.UUID; + +/** The GetSchemaVersionHeaders model. */ +@Fluent +public final class GetSchemaVersionHeaders { + /* + * The X-Schema-Version property. + */ + @JsonProperty(value = "X-Schema-Version") + private Integer xSchemaVersion; + + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /* + * The X-Schema-Id property. + */ + @JsonProperty(value = "X-Schema-Id") + private UUID xSchemaId; + + /* + * The X-Schema-Id-Location property. + */ + @JsonProperty(value = "X-Schema-Id-Location") + private URL xSchemaIdLocation; + + /* + * The Location property. + */ + @JsonProperty(value = "Location") + private String location; + + /** + * Get the xSchemaVersion property: The X-Schema-Version property. + * + * @return the xSchemaVersion value. + */ + public Integer getXSchemaVersion() { + return this.xSchemaVersion; + } + + /** + * Set the xSchemaVersion property: The X-Schema-Version property. + * + * @param xSchemaVersion the xSchemaVersion value to set. + * @return the GetSchemaVersionHeaders object itself. + */ + public GetSchemaVersionHeaders setXSchemaVersion(Integer xSchemaVersion) { + this.xSchemaVersion = xSchemaVersion; + return this; + } + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the GetSchemaVersionHeaders object itself. + */ + public GetSchemaVersionHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Get the xSchemaId property: The X-Schema-Id property. + * + * @return the xSchemaId value. + */ + public UUID getXSchemaId() { + return this.xSchemaId; + } + + /** + * Set the xSchemaId property: The X-Schema-Id property. + * + * @param xSchemaId the xSchemaId value to set. + * @return the GetSchemaVersionHeaders object itself. + */ + public GetSchemaVersionHeaders setXSchemaId(UUID xSchemaId) { + this.xSchemaId = xSchemaId; + return this; + } + + /** + * Get the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @return the xSchemaIdLocation value. + */ + public URL getXSchemaIdLocation() { + return this.xSchemaIdLocation; + } + + /** + * Set the xSchemaIdLocation property: The X-Schema-Id-Location property. + * + * @param xSchemaIdLocation the xSchemaIdLocation value to set. + * @return the GetSchemaVersionHeaders object itself. + */ + public GetSchemaVersionHeaders setXSchemaIdLocation(URL xSchemaIdLocation) { + this.xSchemaIdLocation = xSchemaIdLocation; + return this; + } + + /** + * Get the location property: The Location property. + * + * @return the location value. + */ + public String getLocation() { + return this.location; + } + + /** + * Set the location property: The Location property. + * + * @param location the location value to set. + * @return the GetSchemaVersionHeaders object itself. + */ + public GetSchemaVersionHeaders setLocation(String location) { + this.location = location; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionResponse.java new file mode 100644 index 000000000000..4b4f3bfbc24c --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** Contains all response data for the getSchemaVersion operation. */ +public final class GetSchemaVersionResponse extends ResponseBase { + /** + * Creates an instance of GetSchemaVersionResponse. + * + * @param request the request which resulted in this GetSchemaVersionResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public GetSchemaVersionResponse( + HttpRequest request, + int statusCode, + HttpHeaders rawHeaders, + String value, + GetSchemaVersionHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public String getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionsHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionsHeaders.java new file mode 100644 index 000000000000..db011b690a66 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionsHeaders.java @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The GetSchemaVersionsHeaders model. */ +@Fluent +public final class GetSchemaVersionsHeaders { + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the GetSchemaVersionsHeaders object itself. + */ + public GetSchemaVersionsHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionsResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionsResponse.java new file mode 100644 index 000000000000..67afbfed471b --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemaVersionsResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** Contains all response data for the getSchemaVersions operation. */ +public final class GetSchemaVersionsResponse extends ResponseBase> { + /** + * Creates an instance of GetSchemaVersionsResponse. + * + * @param request the request which resulted in this GetSchemaVersionsResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public GetSchemaVersionsResponse( + HttpRequest request, + int statusCode, + HttpHeaders rawHeaders, + List value, + GetSchemaVersionsHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public List getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemasByGroupHeaders.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemasByGroupHeaders.java new file mode 100644 index 000000000000..a8162e0af75a --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemasByGroupHeaders.java @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The GetSchemasByGroupHeaders model. */ +@Fluent +public final class GetSchemasByGroupHeaders { + /* + * The X-Schema-Type property. + */ + @JsonProperty(value = "X-Schema-Type") + private String xSchemaType; + + /** + * Get the xSchemaType property: The X-Schema-Type property. + * + * @return the xSchemaType value. + */ + public String getXSchemaType() { + return this.xSchemaType; + } + + /** + * Set the xSchemaType property: The X-Schema-Type property. + * + * @param xSchemaType the xSchemaType value to set. + * @return the GetSchemasByGroupHeaders object itself. + */ + public GetSchemasByGroupHeaders setXSchemaType(String xSchemaType) { + this.xSchemaType = xSchemaType; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemasByGroupResponse.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemasByGroupResponse.java new file mode 100644 index 000000000000..796219fe422d --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/GetSchemasByGroupResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** Contains all response data for the getSchemasByGroup operation. */ +public final class GetSchemasByGroupResponse extends ResponseBase> { + /** + * Creates an instance of GetSchemasByGroupResponse. + * + * @param request the request which resulted in this GetSchemasByGroupResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public GetSchemasByGroupResponse( + HttpRequest request, + int statusCode, + HttpHeaders rawHeaders, + List value, + GetSchemasByGroupHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** @return the deserialized response body. */ + @Override + public List getValue() { + return super.getValue(); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/SchemaGroup.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/SchemaGroup.java new file mode 100644 index 000000000000..98d2e8e3ca71 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/SchemaGroup.java @@ -0,0 +1,176 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import java.util.Map; + +/** The SchemaGroup model. */ +@Fluent +public final class SchemaGroup { + /* + * The name property. + */ + @JsonProperty(value = "name") + private String name; + + /* + * The createdTimeUtc property. + */ + @JsonProperty(value = "createdTimeUtc") + private OffsetDateTime createdTimeUtc; + + /* + * The updatedTimeUtc property. + */ + @JsonProperty(value = "updatedTimeUtc") + private OffsetDateTime updatedTimeUtc; + + /* + * The schemaType property. + */ + @JsonProperty(value = "schemaType") + private String schemaType; + + /* + * schema compatibility mode enum, defined by supported schema type + */ + @JsonProperty(value = "schemaCompatibility") + private Integer schemaCompatibility; + + /* + * Dictionary of + */ + @JsonProperty(value = "groupProperties") + private Map groupProperties; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String getName() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the SchemaGroup object itself. + */ + public SchemaGroup setName(String name) { + this.name = name; + return this; + } + + /** + * Get the createdTimeUtc property: The createdTimeUtc property. + * + * @return the createdTimeUtc value. + */ + public OffsetDateTime getCreatedTimeUtc() { + return this.createdTimeUtc; + } + + /** + * Set the createdTimeUtc property: The createdTimeUtc property. + * + * @param createdTimeUtc the createdTimeUtc value to set. + * @return the SchemaGroup object itself. + */ + public SchemaGroup setCreatedTimeUtc(OffsetDateTime createdTimeUtc) { + this.createdTimeUtc = createdTimeUtc; + return this; + } + + /** + * Get the updatedTimeUtc property: The updatedTimeUtc property. + * + * @return the updatedTimeUtc value. + */ + public OffsetDateTime getUpdatedTimeUtc() { + return this.updatedTimeUtc; + } + + /** + * Set the updatedTimeUtc property: The updatedTimeUtc property. + * + * @param updatedTimeUtc the updatedTimeUtc value to set. + * @return the SchemaGroup object itself. + */ + public SchemaGroup setUpdatedTimeUtc(OffsetDateTime updatedTimeUtc) { + this.updatedTimeUtc = updatedTimeUtc; + return this; + } + + /** + * Get the schemaType property: The schemaType property. + * + * @return the schemaType value. + */ + public String getSchemaType() { + return this.schemaType; + } + + /** + * Set the schemaType property: The schemaType property. + * + * @param schemaType the schemaType value to set. + * @return the SchemaGroup object itself. + */ + public SchemaGroup setSchemaType(String schemaType) { + this.schemaType = schemaType; + return this; + } + + /** + * Get the schemaCompatibility property: schema compatibility mode enum, defined by supported schema type. + * + * @return the schemaCompatibility value. + */ + public Integer getSchemaCompatibility() { + return this.schemaCompatibility; + } + + /** + * Set the schemaCompatibility property: schema compatibility mode enum, defined by supported schema type. + * + * @param schemaCompatibility the schemaCompatibility value to set. + * @return the SchemaGroup object itself. + */ + public SchemaGroup setSchemaCompatibility(Integer schemaCompatibility) { + this.schemaCompatibility = schemaCompatibility; + return this; + } + + /** + * Get the groupProperties property: Dictionary of <string>. + * + * @return the groupProperties value. + */ + public Map getGroupProperties() { + return this.groupProperties; + } + + /** + * Set the groupProperties property: Dictionary of <string>. + * + * @param groupProperties the groupProperties value to set. + * @return the SchemaGroup object itself. + */ + public SchemaGroup setGroupProperties(Map groupProperties) { + this.groupProperties = groupProperties; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/SchemaId.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/SchemaId.java new file mode 100644 index 000000000000..6fa7927c4cc4 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/SchemaId.java @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The SchemaId model. */ +@Fluent +public final class SchemaId { + /* + * The id property. + */ + @JsonProperty(value = "id") + private String id; + + /** + * Get the id property: The id property. + * + * @return the id value. + */ + public String getId() { + return this.id; + } + + /** + * Set the id property: The id property. + * + * @param id the id value to set. + * @return the SchemaId object itself. + */ + public SchemaId setId(String id) { + this.id = id; + return this; + } + + /** + * Validates the instance. + * + * @throws IllegalArgumentException thrown if the instance is not valid. + */ + public void validate() { } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/package-info.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/package-info.java new file mode 100644 index 000000000000..a8f6474a639a --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/models/package-info.java @@ -0,0 +1,3 @@ +/** Package containing the data models for AzureSchemaRegistryRestService. null. */ + +package com.azure.data.schemaregistry.client.implementation.models; diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/package-info.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/package-info.java new file mode 100644 index 000000000000..b9afd3e65bc9 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/implementation/package-info.java @@ -0,0 +1,2 @@ +/** Package containing the classes for AzureSchemaRegistryRestService. null. */ +package com.azure.data.schemaregistry.client.implementation; diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/package-info.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/package-info.java new file mode 100644 index 000000000000..f6da76235f3a --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/client/package-info.java @@ -0,0 +1,7 @@ +/** + * Package containing the classes for + * - SchemaRegistryClient interface + * - CachedSchemaRegistryClient + * - AzureSchemaRegistryRestService. + */ +package com.azure.data.schemaregistry.client; diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/package-info.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/package-info.java new file mode 100644 index 000000000000..f04c2e22d1ed --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/java/com/azure/data/schemaregistry/package-info.java @@ -0,0 +1,4 @@ +/** + * Package containing core serialization and deserialization implementations for Azure Schema Registry SDK. + */ +package com.azure.data.schemaregistry; diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/main/module-info.java b/sdk/schemaregistry/azure-data-schemaregistry/src/main/module-info.java new file mode 100644 index 000000000000..1858b02d6f17 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/main/module-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +module com.azure.data.schemaregistry { + requires transitive com.azure.core; + + exports com.azure.data.schemaregistry; + exports com.azure.data.schemaregistry.client; + + opens com.azure.data.schemaregistry to com.fasterxml.jackson.databind, com.azure.core; +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/AbstractDataDeserializerTest.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/AbstractDataDeserializerTest.java new file mode 100644 index 000000000000..310d3abe0039 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/AbstractDataDeserializerTest.java @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.data.schemaregistry.client.SchemaRegistryObject; +import com.azure.data.schemaregistry.client.SchemaRegistryClientException; +import org.apache.avro.Schema; +import org.apache.avro.generic.GenericData; +import org.apache.avro.generic.GenericDatumWriter; +import org.apache.avro.generic.GenericRecord; +import org.apache.avro.io.BinaryEncoder; +import org.apache.avro.io.EncoderFactory; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbstractDataDeserializerTest { + private static final String MOCK_GUID = new String(new char[AbstractDataSerDe.SCHEMA_ID_SIZE]).replace("\0", "a"); + private static final String MOCK_AVRO_SCHEMA_STRING = "{\"namespace\":\"example2.avro\",\"type\":\"record\",\"name\":\"User\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"favorite_number\",\"type\": [\"int\", \"null\"]}]}"; + + private final EncoderFactory encoderFactory = EncoderFactory.get(); + private static final Schema MOCK_AVRO_SCHEMA = (new Schema.Parser()).parse(MOCK_AVRO_SCHEMA_STRING); + + @Test + public void testLoadDecoder() throws IOException, SchemaRegistryClientException, SerializationException { + // add standard avro decoder class and test that it is used for decoding payload + SampleByteDecoder decoder = new SampleByteDecoder(); + + // manually add SchemaRegistryObject to cache + SchemaRegistryObject registered = new SchemaRegistryObject(MOCK_GUID, + decoder.schemaType(), + MOCK_AVRO_SCHEMA_STRING.getBytes(), + decoder::parseSchemaString); + + assertTrue(registered.deserialize() != null); + + MockSchemaRegistryClient mockRegistryClient = new MockSchemaRegistryClient(); + mockRegistryClient.getGuidCache().put(MOCK_GUID, registered); + TestDummyDeserializer deserializer = new TestDummyDeserializer(mockRegistryClient); // contains byte decoder + + assertEquals(MOCK_GUID, deserializer.schemaRegistryClient.getSchemaByGuid(MOCK_GUID).getSchemaId()); + assertEquals(SampleByteDecoder.CONSTANT_PAYLOAD, deserializer.deserialize(getPayload())); + } + + @Test + public void testNullPayload() throws IOException, SchemaRegistryClientException, SerializationException { + TestDummyDeserializer deserializer = new TestDummyDeserializer(new MockSchemaRegistryClient()); + assertEquals(null, deserializer.deserialize(null)); + } + + @Test + public void testIfTooShortPayloadThrow() { + TestDummyDeserializer deserializer = new TestDummyDeserializer(new MockSchemaRegistryClient()); + + try { + deserializer.deserialize("bad payload".getBytes()); + fail("Too short payload did not throw SerializationException"); + } catch (SerializationException e) { + assertTrue(true); + } + } + + // TODO: add for non-existing guid + + @Test + public void testIfRegistryClientNullOnBuildThrow() { + try { + TestDummyDeserializer deserializer = new TestDummyDeserializer(null); + fail("should not get here."); + } catch (IllegalArgumentException e) { + // good + } + } + + private byte[] getPayload() throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(ByteBuffer.allocate(AbstractDataSerDe.SCHEMA_ID_SIZE) + .put(MOCK_GUID.getBytes(Charset.forName("UTF-8"))) + .array()); + GenericRecord record = getAvroRecord(); + BinaryEncoder encoder = encoderFactory.directBinaryEncoder(out, null); + GenericDatumWriter writer = new GenericDatumWriter<>(MOCK_AVRO_SCHEMA); + writer.write(record, encoder); + encoder.flush(); + byte[] bytes = out.toByteArray(); + return bytes; + } + + + private GenericRecord getAvroRecord() { + GenericRecord avroRecord = new GenericData.Record(MOCK_AVRO_SCHEMA); + avroRecord.put("name", "arthur"); + avroRecord.put("favorite_number", 23); + return avroRecord; + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/AbstractDataSerializerTest.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/AbstractDataSerializerTest.java new file mode 100644 index 000000000000..ec8494935b94 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/AbstractDataSerializerTest.java @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.data.schemaregistry.client.SchemaRegistryObject; +import org.junit.jupiter.api.Test; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +public class AbstractDataSerializerTest { + private static final String MOCK_GUID = new String(new char[AbstractDataSerDe.SCHEMA_ID_SIZE]).replace("\0", "a"); + + @Test + public void testRegistryGuidPrefixedToPayload() { + // manually add SchemaRegistryObject into mock registry client cache + SampleByteEncoder encoder = new SampleByteEncoder(); + SchemaRegistryObject registered = new SchemaRegistryObject(MOCK_GUID, + encoder.schemaType(), + encoder.getSchemaString(null).getBytes(), // always returns same schema string + encoder::parseSchemaString); + + assertEquals(encoder.getSchemaString(null), registered.deserialize()); + + MockSchemaRegistryClient mockRegistryClient = new MockSchemaRegistryClient(); + mockRegistryClient.getSchemaStringCache().put(encoder.getSchemaString(null), registered); + + TestDummySerializer serializer = new TestDummySerializer( + mockRegistryClient, true, false); + + try { + byte[] payload = serializer.serializeImpl(1); + ByteBuffer buffer = ByteBuffer.wrap(payload); + byte[] schemaGuidByteArray = new byte[AbstractDataSerDe.SCHEMA_ID_SIZE]; + try { + buffer.get(schemaGuidByteArray); + } catch (BufferUnderflowException e) { + throw new SerializationException("Payload too short, no readable guid.", e); + } + + // guid should match preloaded SchemaRegistryObject guid + assertEquals(MOCK_GUID, new String(schemaGuidByteArray)); + + int start = buffer.position() + buffer.arrayOffset(); + int length = buffer.limit() - AbstractDataSerDe.SCHEMA_ID_SIZE; + byte[] encodedBytes = Arrays.copyOfRange(buffer.array(), start, start + length); + assertTrue(Arrays.equals(encoder.encode(null).toByteArray(), encodedBytes)); + } catch (SerializationException e) { + e.printStackTrace(); + fail(); + } + } + + @Test + public void testNullPayloadThrowsSerializationException() { + TestDummySerializer serializer = new TestDummySerializer( + new MockSchemaRegistryClient(), + true, + false); + + try { + serializer.serializeImpl(null); + fail("Serializing null payload failed to throw SerializationException"); + } catch (SerializationException e) { + assertTrue(true); + } + } + + @Test + public void testSerializeWithNullByteEncoderThrows() { + // don't set byte encoder on constructor + TestDummySerializer serializer = new TestDummySerializer( + new MockSchemaRegistryClient(), false, false); + + try { + serializer.serializeImpl(1); + } catch (SerializationException e) { + assert (true); + } + } + + @Test + public void testIfRegistryNullThenThrow() { + try { + TestDummySerializer serializer = new TestDummySerializer( + null, true, false); + fail("Building serializer instance with null registry client failed to throw"); + } catch (IllegalArgumentException e) { + assertTrue(true); + } catch (Exception e) { + fail("Building serializer instance with null registry client should throw illegal argument exception"); + } + } + + @Test + public void testDefaultAutoRegister() { + TestDummySerializer serializer = new TestDummySerializer(new MockSchemaRegistryClient(), true); + assertEquals(false, (boolean) serializer.autoRegisterSchemas); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/MockSchemaRegistryClient.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/MockSchemaRegistryClient.java new file mode 100644 index 000000000000..54fb22667bba --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/MockSchemaRegistryClient.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.data.schemaregistry.client.SchemaRegistryClient; +import com.azure.data.schemaregistry.client.SchemaRegistryClientException; +import com.azure.data.schemaregistry.client.SchemaRegistryObject; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.function.Function; + +public class MockSchemaRegistryClient implements SchemaRegistryClient { + private final HashMap> typeParserDictionary; + private final HashMap guidCache; + private final HashMap schemaStringCache; + + public MockSchemaRegistryClient() { + this.guidCache = new HashMap(); + this.schemaStringCache = new HashMap(); + this.typeParserDictionary = new HashMap>(); + } + + @Override + public Charset getEncoding() { + return StandardCharsets.UTF_8; + } + + public void addSchemaParser(Codec codec) { } + + @Override + public SchemaRegistryObject register(String schemaGroup, String schemaName, String schemaString, String schemaType) + throws SchemaRegistryClientException { + if (schemaStringCache.containsKey(schemaString)) { + return schemaStringCache.get(schemaString); + } + + return null; + } + + @Override + public SchemaRegistryObject getSchemaByGuid(String schemaGuid) + throws SchemaRegistryClientException { + if (guidCache.containsKey(schemaGuid)) { + return guidCache.get(schemaGuid); + } + return null; + } + + @Override + public String getSchemaId(String schemaGroup, String schemaName, String schemaString, String schemaType) + throws SchemaRegistryClientException { + if (schemaStringCache.containsKey(schemaString)) { + return schemaStringCache.get(schemaString).getSchemaId(); + } + + return null; + } + + @Override + public String deleteSchemaVersion(String schemaGroup, String schemaName, int version) + throws SchemaRegistryClientException { + return null; + } + + @Override + public String deleteLatestSchemaVersion(String schemaGroup, String schemaName) + throws SchemaRegistryClientException { + return null; + } + + @Override + public List deleteSchema(String schemaGroup, String schemaName) + throws SchemaRegistryClientException { + return new ArrayList(); + } + + public HashMap> getTypeParserDictionary() { + return typeParserDictionary; + } + + public HashMap getGuidCache() { + return guidCache; + } + + public HashMap getSchemaStringCache() { + return schemaStringCache; + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/SampleByteDecoder.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/SampleByteDecoder.java new file mode 100644 index 000000000000..8b4cba7c8215 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/SampleByteDecoder.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import org.apache.avro.Schema; + +public class SampleByteDecoder implements ByteDecoder { + public SampleByteDecoder() { } + + @Override + public String schemaType() { + return "sample"; + } + + public static final String CONSTANT_PAYLOAD = "sample payload!"; + + @Override + public Object decodeBytes(byte[] bytes, Object o) throws SerializationException { + return CONSTANT_PAYLOAD; + } + + @Override + public Schema parseSchemaString(String s) { + return new Schema.Parser().parse(s); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/SampleByteEncoder.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/SampleByteEncoder.java new file mode 100644 index 000000000000..768f7fbac496 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/SampleByteEncoder.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class SampleByteEncoder implements ByteEncoder { + + public SampleByteEncoder() { } + + @Override + public String getSchemaName(Object object) throws SerializationException { + return null; + } + + @Override + public String getSchemaString(Object object) { + return "string representation of schema"; + } + + @Override + public ByteArrayOutputStream encode(Object object) throws SerializationException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + outputStream.write("sample payload".getBytes()); + outputStream.flush(); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + throw new SerializationException("this should never happen", e); + } + return outputStream; + } + + @Override + public String schemaType() { + return "test"; + } + + @Override + public String parseSchemaString(String s) { + return s; + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/TestDummyDeserializer.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/TestDummyDeserializer.java new file mode 100644 index 000000000000..591ffd95f172 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/TestDummyDeserializer.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.data.schemaregistry.client.SchemaRegistryClient; + +public class TestDummyDeserializer extends AbstractDataDeserializer { + TestDummyDeserializer(SchemaRegistryClient mockClient) { + super(mockClient); + ByteDecoder sampleDecoder = new SampleByteDecoder(); + this.loadByteDecoder(sampleDecoder); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/TestDummySerializer.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/TestDummySerializer.java new file mode 100644 index 000000000000..9844b9caaaad --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/TestDummySerializer.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry; + +import com.azure.data.schemaregistry.client.SchemaRegistryClient; + +public class TestDummySerializer extends AbstractDataSerializer { + TestDummySerializer( + SchemaRegistryClient mockClient, + boolean byteEncoder, + boolean autoRegisterSchemas) { + super(mockClient); + + // allows simulating improperly written serializer constructor that does not initialize byte encoder + if (byteEncoder) { + setByteEncoder(new SampleByteEncoder()); + } + + this.autoRegisterSchemas = autoRegisterSchemas; + } + + TestDummySerializer( + SchemaRegistryClient mockClient, + boolean byteEncoder) { + super(mockClient); + + // allows simulating improperly written serializer constructor that does not initialize byte encoder + if (byteEncoder) { + setByteEncoder(new SampleByteEncoder()); + } + + // default auto register + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClientTest.java b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClientTest.java new file mode 100644 index 000000000000..a0c34758c930 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/java/com/azure/data/schemaregistry/client/CachedSchemaRegistryClientTest.java @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.schemaregistry.client; + +import com.azure.data.schemaregistry.client.implementation.AzureSchemaRegistryRestService; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemaByIdHeaders; +import com.azure.data.schemaregistry.client.implementation.models.GetSchemaByIdResponse; +import com.azure.data.schemaregistry.client.implementation.models.SchemaId; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.UUID; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.function.Function; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CachedSchemaRegistryClientTest { + private static final String MOCK_SERIALIZATION = "mock_serialization_type"; + private static final String MOCK_ID = "mock_guid"; + private static final SchemaId MOCK_SCHEMA_ID = new SchemaId(); + private static final String MOCK_GROUP = "mockgroup"; + private static final String MOCK_SCHEMA_NAME = "mockname"; + private static final String MOCK_AVRO_SCHEMA = "{\"namespace\":\"example2.avro\",\"type\":\"record\",\"name\":\"User\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"favorite_number\",\"type\": [\"int\", \"null\"]}]}"; + + private CachedSchemaRegistryClient client; + private AzureSchemaRegistryRestService restService; + private HashMap guidCache; + private HashMap schemaStringCache; + private ConcurrentSkipListMap> typeParserDictionary; + + @BeforeEach + protected void setUp() { + this.guidCache = new HashMap(); + this.schemaStringCache = new HashMap(); + + this.typeParserDictionary = new ConcurrentSkipListMap<>(String.CASE_INSENSITIVE_ORDER); + this.typeParserDictionary.put(MOCK_SERIALIZATION, (s) -> s); + + this.restService = mock(AzureSchemaRegistryRestService.class); + this.client = new CachedSchemaRegistryClient( + this.restService, + this.guidCache, + this.schemaStringCache, + this.typeParserDictionary); + } + + @AfterEach + protected void tearDown() { + validateMockitoUsage(); + } + + @Test + public void testRegisterThenSchemaCacheHit() throws Exception { + MOCK_SCHEMA_ID.setId(MOCK_ID); + when(restService.createSchema(anyString(), anyString(), anyString(), anyString())) + .thenReturn(MOCK_SCHEMA_ID); + + assertEquals( + MOCK_ID, + client.register(MOCK_GROUP, MOCK_SCHEMA_NAME, MOCK_AVRO_SCHEMA, MOCK_SERIALIZATION).getSchemaId()); + assertEquals( + MOCK_ID, + client.register(MOCK_GROUP, MOCK_SCHEMA_NAME, MOCK_AVRO_SCHEMA, MOCK_SERIALIZATION).getSchemaId()); + + verify(restService, times(1)) + .createSchema(anyString(), anyString(), anyString(), anyString()); + } + + @Test + public void testGetGuidThenSchemaCacheHit() throws Exception { + MOCK_SCHEMA_ID.setId(MOCK_ID); + when(restService.getIdBySchemaContent(anyString(), anyString(), anyString(), anyString())) + .thenReturn(MOCK_SCHEMA_ID); + + assertEquals(MOCK_ID, client.getSchemaId(MOCK_GROUP, MOCK_SCHEMA_NAME, MOCK_AVRO_SCHEMA, MOCK_SERIALIZATION)); + assertEquals(MOCK_ID, client.getSchemaId(MOCK_GROUP, MOCK_SCHEMA_NAME, MOCK_AVRO_SCHEMA, MOCK_SERIALIZATION)); + + verify(restService, times(1)) + .getIdBySchemaContent(anyString(), anyString(), anyString(), anyString()); + } + + @Test + public void testGetSchemaThenGuidCacheHit() throws Exception { + UUID mockId = UUID.randomUUID(); + GetSchemaByIdHeaders mockHeaders = new GetSchemaByIdHeaders(); + mockHeaders.setXSchemaType(MOCK_SERIALIZATION); + when(restService.getSchemaByIdWithResponseAsync(mockId)) + .thenReturn( + Mono.just(new GetSchemaByIdResponse( + null, + 200, + null, + MOCK_AVRO_SCHEMA, + mockHeaders))); + + SchemaRegistryObject first = client.getSchemaByGuid(mockId.toString()); + SchemaRegistryObject second = client.getSchemaByGuid(mockId.toString()); + + assertTrue(first.equals(second)); + assertEquals(mockId.toString(), first.getSchemaId()); + + verify(restService, times(1)).getSchemaByIdWithResponseAsync(mockId); + } + + @Test + public void testClientReset() throws Exception { + MOCK_SCHEMA_ID.setId(MOCK_ID); + when(restService.createSchema(anyString(), anyString(), anyString(), anyString())) + .thenReturn(MOCK_SCHEMA_ID); + + assertEquals( + MOCK_ID, + client.register(MOCK_GROUP, MOCK_SCHEMA_NAME, MOCK_AVRO_SCHEMA, MOCK_SERIALIZATION).getSchemaId()); + + client.reset(); + + assertEquals(0, guidCache.size()); + assertEquals(0, schemaStringCache.size()); + assertEquals(0, this.typeParserDictionary.size()); + + this.typeParserDictionary.put(MOCK_SERIALIZATION, (s) -> s); + + assertEquals( + MOCK_ID, + client.register(MOCK_GROUP, MOCK_SCHEMA_NAME, MOCK_AVRO_SCHEMA, MOCK_SERIALIZATION).getSchemaId()); + + verify(restService, times(2)) + .createSchema(anyString(), anyString(), anyString(), anyString()); + } +} diff --git a/sdk/schemaregistry/azure-data-schemaregistry/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sdk/schemaregistry/azure-data-schemaregistry/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000000..1f0955d450f0 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline diff --git a/sdk/schemaregistry/azure-data-schemaregistry/swagger/swagger.json b/sdk/schemaregistry/azure-data-schemaregistry/swagger/swagger.json new file mode 100644 index 000000000000..3a6f605d3aa7 --- /dev/null +++ b/sdk/schemaregistry/azure-data-schemaregistry/swagger/swagger.json @@ -0,0 +1,576 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Azure Schema Registry Rest Service", + "version": "1.0.0-beta" + }, + "paths": { + "/$schemagroups": { + "get": { + "summary": "Get list of schema groups", + "description": "Get all schema groups in namespace.", + "operationId": "getGroups", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "tags": [ + "groups" + ] + } + }, + "/$schemagroups/getSchemaById/{schema-id}": { + "get": { + "summary": "Get schema by schema ID", + "description": "Get schema by schema ID.", + "operationId": "getSchemaById", + "parameters": [ + { + "name": "schema-id", + "in": "path", + "description": "schema ID referencing specific schema in registry namespace", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/SchemaBytePayloadResponse" + }, + "404": { + "description": "Schema with matching ID not found" + } + }, + "tags": [ + "runtime" + ] + } + }, + "/$schemagroups/{group-name}": { + "parameters": [ + { + "name": "group-name", + "in": "path", + "description": "schema group", + "required": true, + "schema": { + "type": "string" + } + } + ], + "get": { + "summary": "Get schema group", + "description": "Get schema group description in registry namespace.", + "operationId": "getGroup", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaGroup" + } + } + } + }, + "404": { + "description": "Specified group not found" + } + }, + "tags": [ + "groups" + ] + }, + "put": { + "summary": "Create schema group", + "description": "Create schema group with specified schema type in registry namespace.", + "operationId": "createGroup", + "requestBody": { + "description": "schema group description", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaGroup" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "409": { + "description": "Schema group already exists" + } + }, + "tags": [ + "groups" + ] + }, + "delete": { + "summary": "Delete schema group", + "description": "Delete schema group in schema registry namespace.", + "operationId": "deleteGroup", + "responses": { + "204": { + "description": "OK no content" + }, + "404": { + "description": "Specified group not found" + } + }, + "tags": [ + "groups" + ] + } + }, + "/$schemagroups/{group-name}/schemas": { + "parameters": [ + { + "name": "group-name", + "in": "path", + "description": "schema group", + "required": true, + "schema": { + "type": "string" + } + } + ], + "get": { + "tags": [ + "groups" + ], + "summary": "Get schemas for group name", + "description": "Returns schema by group name.", + "operationId": "getSchemasByGroup", + "responses": { + "200": { + "description": "OK", + "headers": { + "X-Schema-Type": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "404": { + "description": "Group not found" + } + } + }, + "delete": { + "tags": [ + "groups" + ], + "summary": "Deletes all schemas in group", + "description": "Deletes all schemas under specified group name.", + "operationId": "deleteSchemasByGroup", + "responses": { + "204": { + "description": "OK no content" + }, + "404": { + "description": "Group not found" + } + } + } + }, + "/$schemagroups/{group-name}/schemas/{schema-name}": { + "parameters": [ + { + "name": "group-name", + "in": "path", + "description": "schema group", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "schema-name", + "in": "path", + "description": "schema name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "post": { + "summary": "Get schema ID by schema content", + "description": "Get ID for schema with matching byte content and schema type.", + "operationId": "getIdBySchemaContent", + "parameters": [ + { + "in": "header", + "name": "X-Schema-Type", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "description": "schema content", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaBytePayload" + } + } + } + }, + "responses": { + "200": { + "$ref": "#/components/responses/SchemaIdResponse" + }, + "404": { + "description": "Matching schema not found" + } + }, + "tags": [ + "runtime" + ] + }, + "put": { + "summary": "Register schema", + "description": "Register schema. If schema of specified name does not exist in specified group, schema is created at version 1. If schema of specified name exists already in specified group, schema is created at latest version + 1. If schema with identical content already exists, existing schema's ID is returned. \n", + "operationId": "createSchema", + "parameters": [ + { + "in": "header", + "name": "X-Schema-Type", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "description": "schema content", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaBytePayload" + } + } + } + }, + "responses": { + "200": { + "$ref": "#/components/responses/SchemaIdResponse" + }, + "400": { + "description": "Invalid request" + } + }, + "tags": [ + "runtime" + ] + }, + "get": { + "summary": "Get latest version of schema", + "description": "Get latest version of schema.", + "operationId": "getLatestSchema", + "responses": { + "200": { + "$ref": "#/components/responses/SchemaBytePayloadResponse" + } + }, + "tags": [ + "schemas" + ] + }, + "delete": { + "summary": "Delete schema", + "operationId": "deleteSchema", + "responses": { + "204": { + "description": "OK no content" + }, + "404": { + "description": "Matching schema not found" + } + }, + "tags": [ + "schemas" + ] + } + }, + "/$schemagroups/{group-name}/schemas/{schema-name}/versions": { + "parameters": [ + { + "name": "group-name", + "in": "path", + "description": "schema group", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "schema-name", + "in": "path", + "description": "schema name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "get": { + "summary": "Get list of versions", + "description": "Get list of versions for specified schema", + "operationId": "getSchemaVersions", + "responses": { + "200": { + "description": "OK", + "headers": { + "X-Schema-Type": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + }, + "tags": [ + "schemas" + ] + } + }, + "/$schemagroups/{group-name}/schemas/{schema-name}/versions/{version-number}": { + "parameters": [ + { + "name": "group-name", + "in": "path", + "description": "schema group", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "schema-name", + "in": "path", + "description": "schema name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "version-number", + "in": "path", + "description": "version number", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "get": { + "summary": "Get specified version of schema", + "operationId": "getSchemaVersion", + "responses": { + "200": { + "$ref": "#/components/responses/SchemaBytePayloadResponse" + }, + "404": { + "description": "Specified schema not found" + } + }, + "tags": [ + "schemas" + ] + }, + "delete": { + "summary": "Delete specified version of schema", + "operationId": "deleteSchemaVersion", + "responses": { + "204": { + "description": "OK no content" + } + }, + "tags": [ + "schemas" + ] + } + } + }, + "components": { + "schemas": { + "SchemaId": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "SchemaBytePayload": { + "type": "string" + }, + "SchemaGroup": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "createdTimeUtc": { + "type": "string", + "format": "date-time" + }, + "updatedTimeUtc": { + "type": "string", + "format": "date-time" + }, + "schemaType": { + "type": "string" + }, + "schemaCompatibility": { + "type": "integer", + "description": "schema compatibility mode enum, defined by supported schema type" + }, + "groupProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "responses": { + "SchemaIdResponse": { + "description": "OK", + "headers": { + "Location": { + "schema": { + "type": "string" + } + }, + "X-Schema-Type": { + "schema": { + "type": "string" + } + }, + "X-Schema-Id": { + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "unique schema identifier" + }, + "X-Schema-Id-Location": { + "schema": { + "type": "string", + "format": "url" + }, + "description": "location of schema resource" + }, + "X-Schema-Version": { + "schema": { + "type": "integer" + }, + "description": "version of returned schema" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaId" + } + } + } + }, + "SchemaBytePayloadResponse": { + "description": "OK", + "headers": { + "Location": { + "schema": { + "type": "string" + } + }, + "X-Schema-Type": { + "schema": { + "type": "string" + } + }, + "X-Schema-Id": { + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "unique schema identifier" + }, + "X-Schema-Id-Location": { + "schema": { + "type": "string", + "format": "url" + }, + "description": "location of schema resource" + }, + "X-Schema-Version": { + "schema": { + "type": "integer" + }, + "description": "version of returned schema" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaBytePayload" + } + } + } + } + } + } + } \ No newline at end of file diff --git a/sdk/schemaregistry/ci.yml b/sdk/schemaregistry/ci.yml index 0fcdb17e44ff..81019698dc2b 100644 --- a/sdk/schemaregistry/ci.yml +++ b/sdk/schemaregistry/ci.yml @@ -37,12 +37,9 @@ stages: parameters: ServiceDirectory: schemaregistry Artifacts: - - name: azure-schemaregistry-client + - name: azure-data-schemaregistry groupId: com.azure - safeName: azureschemaregistryclient - - name: azure-schemaregistry-serde-common + safeName: azuredataschemaregistry + - name: azure-data-schemaregistry-avro groupId: com.azure - safeName: azureschemaregistryserdecommon - - name: azure-schemaregistry-serde-avro - groupId: com.azure - safeName: azureschemaregistryserde-avro + safeName: azuredataschemaregistryavro diff --git a/sdk/schemaregistry/pom.xml b/sdk/schemaregistry/pom.xml new file mode 100644 index 000000000000..b4913ee4eddd --- /dev/null +++ b/sdk/schemaregistry/pom.xml @@ -0,0 +1,18 @@ + + + + + 4.0.0 + com.azure + azure-data-schemaregistry-service + pom + 1.0.0 + + azure-data-schemaregistry + azure-data-schemaregistry-avro + +